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