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 34static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = NULL; 35static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = NULL; 36static PFNVGCREATEEGLIMAGETARGETKHRPROC vgCreateEGLImageTargetKHR_func = NULL; 37 38typedef 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 62static 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 105static 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 187static 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 240static 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 255static 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 287static 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 302static 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 345int 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 417exit3: 418 XDestroyWindow(eglman->xdpy, eglman->xwin); 419exit2: 420 eglTerminate(eglman->dpy); 421exit1: 422 XCloseDisplay(eglman->xdpy); 423exit0: 424 free(eglman); 425 426 return 0; 427} 428 429