1 /*
2  * KHR_gl_texture_2D_image extension test
3  *
4  * This test aims to validate KHR_gl_texture_2D_image extension which provide
5  * a mechanism for creating EGLImage objects from OpenGL ES API resources,
6  *
7  * such as two- and three- dimensional textures, cube maps and render buffers.
8  *
9  * Texture->EGLImage->VGImage
10  *
11  * Cooper Yuan <cooperyuan@gmail.com>
12  * 20 Aug 2011
13  */
14 #include <math.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xutil.h>
20 #include <X11/keysym.h>
21 #include <GL/gl.h>
22 #include <VG/openvg.h>
23 #include <GL/glu.h>
24 #include <EGL/egl.h>
25 
26 #include <EGL/eglext.h>
27 #include <VG/vgext.h>
28 
29 #define WINDOW_WIDTH   300
30 #define WINDOW_HEIGHT  300
31 #define TEXTURE_WIDTH  128
32 #define TEXTURE_HEIGHT 128
33 
34 static PFNEGLCREATEIMAGEKHRPROC    eglCreateImageKHR                    = NULL;
35 static PFNEGLDESTROYIMAGEKHRPROC   eglDestroyImageKHR                   = NULL;
36 static PFNVGCREATEEGLIMAGETARGETKHRPROC vgCreateEGLImageTargetKHR_func  = NULL;
37 
38 typedef struct _egl_manager_t
39 {
40     EGLNativeDisplayType xdpy;
41     EGLNativeWindowType  xwin;
42 
43     EGLDisplay  dpy;
44     EGLConfig   conf;
45 
46     // Rendering contexts
47     EGLContext  vg_ctx;
48     EGLContext  es_ctx;
49 
50     // Surfaces
51     EGLSurface  win_surface;
52     EGLSurface  pbuf_surface;
53 
54     VGImage     vg_image;
55     EGLImageKHR egl_image;
56     GLuint      texture;
57 
58     EGLint      major_ver, minor_ver;
59 }EGLmanager;
60 
61 
check_ext(EGLmanager * eglman)62 static EGLBoolean check_ext(EGLmanager *eglman)
63 {
64     const char* egl_ext_str = NULL;
65     egl_ext_str = eglQueryString(eglman->dpy, EGL_EXTENSIONS);
66 
67     // check extension KHR_vg_parent_image
68     if (eglCreateImageKHR == NULL)
69     {
70         if (!strstr(egl_ext_str, "EGL_KHR_image"))
71         {
72             return EGL_FALSE;
73         }
74         else
75         {
76             eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
77             eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
78             if ((!eglCreateImageKHR) || (!eglDestroyImageKHR))
79             {
80                 return EGL_FALSE;
81             }
82         }
83     }
84 
85     // check extension VG_KHR_EGL_image
86     if (vgCreateEGLImageTargetKHR_func == NULL)
87     {
88         if (!strstr(egl_ext_str, "VG_KHR_EGL_image") )
89         {
90             return EGL_FALSE;
91         }
92         else
93         {
94             vgCreateEGLImageTargetKHR_func = (PFNVGCREATEEGLIMAGETARGETKHRPROC)eglGetProcAddress("vgCreateEGLImageTargetKHR");
95             if (!vgCreateEGLImageTargetKHR_func)
96             {
97                 return EGL_FALSE;
98             }
99         }
100     }
101 
102     return EGL_TRUE;
103 }
104 
create_x_window(EGLmanager * eglman,const char * name)105 static EGLBoolean create_x_window(EGLmanager *eglman, const char *name)
106 {
107     EGLint scrnum, num_conf, num_visuals;
108     Window root;
109     EGLint vid;
110     XVisualInfo *visInfo, visTemplate;
111     XSetWindowAttributes attr;
112     unsigned long mask;
113 
114     EGLint config_attrib[] =
115     {
116         EGL_RED_SIZE,			1,
117         EGL_GREEN_SIZE, 		1,
118         EGL_BLUE_SIZE,			1,
119         EGL_DEPTH_SIZE,         1,
120         EGL_SURFACE_TYPE,       EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
121         EGL_RENDERABLE_TYPE,	EGL_OPENVG_BIT | EGL_OPENGL_BIT,
122         EGL_NONE
123     };
124 
125     scrnum = DefaultScreen(eglman->xdpy);
126     root = RootWindow(eglman->xdpy, scrnum);
127 
128     if (!eglChooseConfig(eglman->dpy, config_attrib, &eglman->conf, 1, &num_conf) ||
129         num_conf == 0 ||
130         eglGetError() != EGL_SUCCESS)
131     {
132         printf("Error: couldn't get an EGL visual config\n");
133         return EGL_FALSE;
134     }
135 
136     if (!eglGetConfigAttrib(eglman->dpy, eglman->conf, EGL_NATIVE_VISUAL_ID, &vid) ||
137         eglGetError() != EGL_SUCCESS)
138     {
139         printf("Error: eglGetConfigAttrib() failed\n");
140         return EGL_FALSE;
141     }
142 
143     /* The X window visual must match the EGL config */
144     visTemplate.visualid = vid;
145     visInfo = XGetVisualInfo(eglman->xdpy, VisualIDMask, &visTemplate, &num_visuals);
146     if (!visInfo)
147     {
148         printf("Error: couldn't get X visual\n");
149         return EGL_FALSE;
150     }
151 
152     /* window attributes */
153     attr.background_pixel = 0;
154     attr.border_pixel = 0;
155     attr.colormap = XCreateColormap(eglman->xdpy, root, visInfo->visual, AllocNone);
156     attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
157     mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
158 
159     eglman->xwin = XCreateWindow(eglman->xdpy, root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT,
160                                  0, visInfo->depth, InputOutput,
161                                  visInfo->visual, mask, &attr);
162 
163     if (!eglman->xwin)
164     {
165         printf("Error: couldn't create X Window\n");
166         return EGL_FALSE;
167     }
168 
169     /* set hints and properties */
170     {
171        XSizeHints sizehints;
172        sizehints.x = 0;
173        sizehints.y = 0;
174        sizehints.width  = WINDOW_WIDTH;
175        sizehints.height = WINDOW_HEIGHT;
176        sizehints.flags = USSize | USPosition;
177        XSetNormalHints(eglman->xdpy, eglman->xwin, &sizehints);
178        XSetStandardProperties(eglman->xdpy, eglman->xwin, name, name,
179                               None, (char **)NULL, 0, &sizehints);
180     }
181 
182     XFree(visInfo);
183 
184     return EGL_TRUE;
185 }
186 
egl_init(EGLmanager * eglman)187 static EGLBoolean egl_init(EGLmanager *eglman)
188 {
189     EGLint pbuffer_attrib[] =
190     {
191         EGL_WIDTH,  128,
192         EGL_HEIGHT, 128,
193         EGL_NONE
194     };
195 
196     // Check extension support
197     if (check_ext(eglman) != EGL_TRUE)
198     {
199         return EGL_FALSE;
200     }
201 
202     // Create GL context
203     eglBindAPI(EGL_OPENGL_ES_API);
204     eglman->es_ctx = eglCreateContext(eglman->dpy, eglman->conf, NULL, NULL);
205     if (eglman->es_ctx == EGL_NO_CONTEXT ||
206         eglGetError() != EGL_SUCCESS)
207     {
208         return EGL_FALSE;
209     }
210 
211     // Create VG context
212     eglBindAPI(EGL_OPENVG_API);
213     eglman->vg_ctx = eglCreateContext(eglman->dpy, eglman->conf, NULL, NULL);
214     if (eglman->vg_ctx == EGL_NO_CONTEXT ||
215         eglGetError() != EGL_SUCCESS)
216     {
217         return EGL_FALSE;
218     }
219 
220     // Create window surface
221     eglman->win_surface = eglCreateWindowSurface(eglman->dpy, eglman->conf, eglman->xwin, NULL);
222     if (eglman->win_surface == EGL_NO_SURFACE ||
223         eglGetError() != EGL_SUCCESS)
224     {
225         return EGL_FALSE;
226     }
227 
228     // Create pbuffer surface
229     eglman->pbuf_surface = eglCreatePbufferSurface(eglman->dpy, eglman->conf, pbuffer_attrib);
230     if (eglman->pbuf_surface == EGL_NO_SURFACE ||
231         eglGetError() != EGL_SUCCESS)
232     {
233 
234         return EGL_FALSE;
235     }
236 
237     return EGL_TRUE;
238 }
239 
egl_deinit(EGLmanager * eglman)240 static void egl_deinit(EGLmanager *eglman)
241 {
242     eglBindAPI(EGL_OPENGL_ES_API);
243     eglMakeCurrent(eglman->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
244 
245     eglBindAPI(EGL_OPENVG_API);
246     eglMakeCurrent(eglman->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
247 
248     eglDestroySurface(eglman->dpy, eglman->win_surface);
249     eglDestroySurface(eglman->dpy, eglman->pbuf_surface);
250 
251     eglDestroyContext(eglman->dpy, eglman->es_ctx);
252     eglDestroyContext(eglman->dpy, eglman->vg_ctx);
253 }
254 
vg_es_init(EGLmanager * eglman)255 static EGLBoolean vg_es_init(EGLmanager *eglman)
256 {
257     unsigned char* textureData = NULL;
258     int tsize = 0;
259 
260     // Initialize GL
261     eglBindAPI(EGL_OPENGL_ES_API);
262     eglMakeCurrent(eglman->dpy, eglman->pbuf_surface, eglman->pbuf_surface, eglman->es_ctx);
263 
264     // Create Texture Target from EGLImage
265     glGenTextures(1, &eglman->texture);
266     glBindTexture(GL_TEXTURE_2D, eglman->texture);
267     tsize = TEXTURE_WIDTH * TEXTURE_HEIGHT * 4;
268     textureData = (GLubyte*) malloc (tsize);
269     memset(textureData, 0, tsize);
270     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
271 
272     free (textureData);
273 
274     // Create EGLImage from Texture
275     eglman->egl_image = (EGLImageKHR)eglCreateImageKHR(eglman->dpy, eglman->es_ctx, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)eglman->texture, NULL);
276 
277     // Initialize VG
278     eglBindAPI(EGL_OPENVG_API);
279     eglMakeCurrent(eglman->dpy, eglman->win_surface, eglman->win_surface, eglman->vg_ctx);
280 
281     // Create VGImage from EGLImage
282     eglman->vg_image = vgCreateEGLImageTargetKHR_func((VGeglImageKHR)eglman->egl_image);
283 
284     return EGL_TRUE;
285 }
286 
vg_es_deinit(EGLmanager * eglman)287 static void vg_es_deinit(EGLmanager *eglman)
288 {
289     // Destroy GL
290     eglDestroyImageKHR(eglman->dpy, eglman->egl_image);
291     eglBindAPI(EGL_OPENGL_ES_API);
292     eglMakeCurrent(eglman->dpy, eglman->pbuf_surface, eglman->pbuf_surface, eglman->es_ctx);
293     glDeleteTextures(1, &eglman->texture);
294     glBindTexture(GL_TEXTURE_2D, 0);
295 
296     // Destroy VG
297     eglBindAPI(EGL_OPENVG_API);
298     eglMakeCurrent(eglman->dpy, eglman->win_surface, eglman->win_surface, eglman->vg_ctx);
299     vgDestroyImage(eglman->vg_image);
300 }
301 
draw(EGLmanager * eglman)302 static void draw(EGLmanager *eglman)
303 {
304     VGfloat black[]   = {0.f, 0.f, 0.f, 1.f};
305 
306     // Render 3D scene by GL
307     eglBindAPI(EGL_OPENGL_ES_API);
308     eglMakeCurrent(eglman->dpy, eglman->pbuf_surface, eglman->pbuf_surface, eglman->es_ctx);
309 
310     // Modify GL texture source
311     glClearColor(1.0, 0.0, 0.0, 1.0);
312     glClear(GL_COLOR_BUFFER_BIT);
313     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEXTURE_WIDTH/2, TEXTURE_HEIGHT/2);
314     glClearColor(0.0, 1.0, 0.0, 1.0);
315     glClear(GL_COLOR_BUFFER_BIT);
316     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, TEXTURE_WIDTH/2, 0, 0, 0, TEXTURE_WIDTH/2, TEXTURE_HEIGHT/2);
317     glClearColor(0.0, 0.0, 1.0, 1.0);
318     glClear(GL_COLOR_BUFFER_BIT);
319     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, TEXTURE_HEIGHT/2, 0, 0, TEXTURE_WIDTH/2, TEXTURE_HEIGHT/2);
320     glClearColor(1.0, 1.0, 1.0, 1.0);
321     glClear(GL_COLOR_BUFFER_BIT);
322     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, TEXTURE_WIDTH/2, TEXTURE_HEIGHT/2, 0, 0, TEXTURE_WIDTH/2, TEXTURE_HEIGHT/2);
323 
324     // Make current to VG content
325     eglBindAPI(EGL_OPENVG_API);
326     eglMakeCurrent(eglman->dpy, eglman->win_surface, eglman->win_surface, eglman->vg_ctx);
327 
328     // Draw VGImage target
329     vgSetfv(VG_CLEAR_COLOR, 4, black);
330     vgClear(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
331     vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
332     vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
333     vgLoadIdentity();
334     vgTranslate(WINDOW_WIDTH/2.0f, WINDOW_HEIGHT/2.0f);
335     vgScale((VGfloat)WINDOW_WIDTH/(VGfloat)TEXTURE_WIDTH * 0.8f, (VGfloat)WINDOW_HEIGHT/(VGfloat)TEXTURE_HEIGHT * 0.8f);
336     vgTranslate(-TEXTURE_WIDTH/2.0f, -TEXTURE_HEIGHT/2.0f);
337     vgDrawImage(eglman->vg_image);
338 
339     // Swap buffer
340     eglSwapBuffers(eglman->dpy, eglman->win_surface);
341 
342     return;
343 }
344 
main(int argc,char ** argv)345 int main(int argc, char **argv)
346 {
347     const char *s;
348 
349     EGLmanager *eglman = calloc(1, sizeof(*eglman));
350 
351     // Open X Display
352     Display *x_dpy = XOpenDisplay(NULL);
353     if (!x_dpy)
354     {
355         printf("error: can't open default display\n");
356         goto exit0;
357     }
358     eglman->xdpy = (EGLNativeDisplayType)x_dpy;
359 
360     // Get EGL Display
361     eglman->dpy = eglGetDisplay(eglman->xdpy);
362     if (!eglman->dpy || eglGetError() != EGL_SUCCESS)
363     {
364         printf("error: can't get EGL display\n");
365         goto exit1;
366     }
367 
368     // Initialize EGL
369     eglInitialize(eglman->dpy, &eglman->major_ver, &eglman->minor_ver);
370     if (eglGetError() != EGL_SUCCESS)
371     {
372         goto exit1;
373     }
374 
375     // Query and print out information
376     s = eglQueryString(eglman->dpy, EGL_VERSION);
377     printf("EGL_VERSION = %s\n", s);
378 
379     s = eglQueryString(eglman->dpy, EGL_VENDOR);
380     printf("EGL_VENDOR = %s\n", s);
381 
382     s = eglQueryString(eglman->dpy, EGL_EXTENSIONS);
383     printf("EGL_EXTENSIONS = %s\n", s);
384 
385     s = eglQueryString(eglman->dpy, EGL_CLIENT_APIS);
386     printf("EGL_CLIENT_APIS = %s\n", s);
387 
388     // Create an RGB, double-buffered X window
389     if (create_x_window(eglman, "vgimage to texture") != EGL_TRUE)
390     {
391         goto exit2;
392     }
393 
394     XMapWindow(eglman->xdpy, eglman->xwin);
395 
396     // Initialize EGL
397     if (egl_init(eglman) != EGL_TRUE)
398     {
399         goto exit3;
400     }
401 
402     // Initialize rendering API: OpenGL ES and OpenVG
403     if (vg_es_init(eglman) != EGL_TRUE)
404     {
405         goto exit3;
406     }
407 
408     // Rendering
409     draw(eglman);
410 
411     // Deinitialize rendering API
412     vg_es_deinit(eglman);
413 
414     // Deinitialize EGL
415     egl_deinit(eglman);
416 
417 exit3:
418     XDestroyWindow(eglman->xdpy, eglman->xwin);
419 exit2:
420     eglTerminate(eglman->dpy);
421 exit1:
422     XCloseDisplay(eglman->xdpy);
423 exit0:
424     free(eglman);
425 
426     return 0;
427 }
428 
429