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