/* * KHR_vg_parent_image extension test * * This test aims to validate KHR_vg_parent_image extension which provides * a mechanism for creating EGLImage objects from OpenVG VGImage resources, * and then bind EGLImage with texture which will be used by OpenGL API. * * VGImage->EGLImage->Texture * * Cooper Yuan * 20 Aug 2011 */ #include #include #include #include #include #include #include #include #include #include #include #include #define WINDOW_WIDTH 300 #define WINDOW_HEIGHT 300 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = NULL; static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = NULL; static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = NULL; typedef struct _egl_manager_t { EGLNativeDisplayType xdpy; EGLNativeWindowType xwin; EGLDisplay dpy; EGLConfig conf; // Rendering contexts EGLContext vg_ctx; EGLContext es_ctx; // Surfaces EGLSurface win_surface; EGLSurface pbuf_surface; VGImage vg_image; EGLImageKHR egl_image; GLuint texture; EGLint major_ver, minor_ver; }EGLmanager; static EGLBoolean check_ext(EGLmanager *eglman) { const char* egl_ext_str = NULL; egl_ext_str = eglQueryString(eglman->dpy, EGL_EXTENSIONS); // check extension KHR_vg_parent_image if (eglCreateImageKHR == NULL) { if (!strstr(egl_ext_str, "EGL_KHR_image")) { return EGL_FALSE; } else { eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR"); eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR"); if ((!eglCreateImageKHR) || (!eglDestroyImageKHR)) { return EGL_FALSE; } } } // check extension GL_OES_EGL_image if (glEGLImageTargetTexture2DOES == NULL) { glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); if (!glEGLImageTargetTexture2DOES) { return EGL_FALSE; } } return EGL_TRUE; } static EGLBoolean create_x_window(EGLmanager *eglman, const char *name) { EGLint scrnum, num_conf, num_visuals; Window root; EGLint vid; XVisualInfo *visInfo, visTemplate; XSetWindowAttributes attr; unsigned long mask; EGLint config_attrib[] = { EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, EGL_DEPTH_SIZE, 1, EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT | EGL_OPENGL_BIT, EGL_NONE }; scrnum = DefaultScreen(eglman->xdpy); root = RootWindow(eglman->xdpy, scrnum); if (!eglChooseConfig(eglman->dpy, config_attrib, &eglman->conf, 1, &num_conf) || num_conf == 0 || eglGetError() != EGL_SUCCESS) { printf("Error: couldn't get an EGL visual config\n"); return EGL_FALSE; } if (!eglGetConfigAttrib(eglman->dpy, eglman->conf, EGL_NATIVE_VISUAL_ID, &vid) || eglGetError() != EGL_SUCCESS) { printf("Error: eglGetConfigAttrib() failed\n"); return EGL_FALSE; } /* The X window visual must match the EGL config */ visTemplate.visualid = vid; visInfo = XGetVisualInfo(eglman->xdpy, VisualIDMask, &visTemplate, &num_visuals); if (!visInfo) { printf("Error: couldn't get X visual\n"); return EGL_FALSE; } /* window attributes */ attr.background_pixel = 0; attr.border_pixel = 0; attr.colormap = XCreateColormap(eglman->xdpy, root, visInfo->visual, AllocNone); attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; eglman->xwin = XCreateWindow(eglman->xdpy, root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); if (!eglman->xwin) { printf("Error: couldn't create X Window\n"); return EGL_FALSE; } /* set hints and properties */ { XSizeHints sizehints; sizehints.x = 0; sizehints.y = 0; sizehints.width = WINDOW_WIDTH; sizehints.height = WINDOW_HEIGHT; sizehints.flags = USSize | USPosition; XSetNormalHints(eglman->xdpy, eglman->xwin, &sizehints); XSetStandardProperties(eglman->xdpy, eglman->xwin, name, name, None, (char **)NULL, 0, &sizehints); } XFree(visInfo); return EGL_TRUE; } static EGLBoolean egl_init(EGLmanager *eglman) { EGLint pbuffer_attrib[] = { EGL_WIDTH, 128, EGL_HEIGHT, 128, EGL_NONE }; // Check extension support if (check_ext(eglman) != EGL_TRUE) { return EGL_FALSE; } // Create GL context eglBindAPI(EGL_OPENGL_ES_API); eglman->es_ctx = eglCreateContext(eglman->dpy, eglman->conf, NULL, NULL); if (eglman->es_ctx == EGL_NO_CONTEXT || eglGetError() != EGL_SUCCESS) { return EGL_FALSE; } // Create VG context eglBindAPI(EGL_OPENVG_API); eglman->vg_ctx = eglCreateContext(eglman->dpy, eglman->conf, NULL, NULL); if (eglman->vg_ctx == EGL_NO_CONTEXT || eglGetError() != EGL_SUCCESS) { return EGL_FALSE; } // Create window surface eglman->win_surface = eglCreateWindowSurface(eglman->dpy, eglman->conf, eglman->xwin, NULL); if (eglman->win_surface == EGL_NO_SURFACE || eglGetError() != EGL_SUCCESS) { return EGL_FALSE; } // Create pbuffer surface eglman->pbuf_surface = eglCreatePbufferSurface(eglman->dpy, eglman->conf, pbuffer_attrib); if (eglman->pbuf_surface == EGL_NO_SURFACE || eglGetError() != EGL_SUCCESS) { return EGL_FALSE; } return EGL_TRUE; } static void egl_deinit(EGLmanager *eglman) { eglBindAPI(EGL_OPENGL_ES_API); eglMakeCurrent(eglman->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(eglman->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(eglman->dpy, eglman->win_surface); eglDestroySurface(eglman->dpy, eglman->pbuf_surface); eglDestroyContext(eglman->dpy, eglman->es_ctx); eglDestroyContext(eglman->dpy, eglman->vg_ctx); } static EGLBoolean vg_es_init(EGLmanager *eglman) { // Initialize OpenVG eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(eglman->dpy, eglman->pbuf_surface, eglman->pbuf_surface, eglman->vg_ctx); // Create VGImage eglman->vg_image = vgCreateImage(VG_sRGBA_8888, WINDOW_WIDTH, WINDOW_HEIGHT, VG_IMAGE_QUALITY_BETTER); // Create EGLImage from VGImage eglman->egl_image = (EGLImageKHR)eglCreateImageKHR(eglman->dpy, eglman->vg_ctx, EGL_VG_PARENT_IMAGE_KHR, (EGLClientBuffer)eglman->vg_image, NULL); // Initialize OpenGL ES eglBindAPI(EGL_OPENGL_ES_API); eglMakeCurrent(eglman->dpy, eglman->win_surface, eglman->win_surface, eglman->es_ctx); // Create Texture Target from EGLImage glGenTextures(1, &eglman->texture); glBindTexture(GL_TEXTURE_2D, eglman->texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglman->egl_image); return EGL_TRUE; } static void vg_es_deinit(EGLmanager *eglman) { // Destroy VG eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(eglman->dpy, eglman->pbuf_surface, eglman->pbuf_surface, eglman->vg_ctx); eglDestroyImageKHR(eglman->dpy, eglman->egl_image); vgDestroyImage(eglman->vg_image); // Destroy GL eglBindAPI(EGL_OPENGL_ES_API); eglMakeCurrent(eglman->dpy, eglman->win_surface, eglman->win_surface, eglman->es_ctx); glDeleteTextures(1, &eglman->texture); glBindTexture(GL_TEXTURE_2D, 0); } static void draw(EGLmanager *eglman) { static const GLfloat red[4] = {1.0, 0.2, 0.2, 1.0}; static const GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0}; GLfloat pVertex[12] = { -1.f, -1.f, 0.f, 1.f, -1.f, 0.f, -1.f, 1.f, 0.f, 1.f, 1.f, 0.f }; GLshort pTexCoord[8] = { 0, 0, 1, 0, 0, 1, 1, 1, }; // Make current to VG content eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(eglman->dpy, eglman->pbuf_surface, eglman->pbuf_surface, eglman->vg_ctx); vgSetfv(VG_CLEAR_COLOR, 4, red); vgClearImage(eglman->vg_image, 0, 0, WINDOW_WIDTH/2, WINDOW_HEIGHT/2); vgSetfv(VG_CLEAR_COLOR, 4, blue); vgClearImage(eglman->vg_image, WINDOW_WIDTH/2, WINDOW_HEIGHT/2, WINDOW_WIDTH/2, WINDOW_HEIGHT/2); // Make current to GL content eglBindAPI(EGL_OPENGL_ES_API); eglMakeCurrent(eglman->dpy, eglman->win_surface, eglman->win_surface, eglman->es_ctx); glViewport(WINDOW_WIDTH / 8, WINDOW_HEIGHT / 8, WINDOW_WIDTH * 3 / 4, WINDOW_HEIGHT * 3 / 4); glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, eglman->texture); glEnable(GL_TEXTURE_2D); glEnableClientState( GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, pVertex); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_SHORT, 0, pTexCoord); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Swap buffer eglSwapBuffers(eglman->dpy, eglman->win_surface); return; } int main(int argc, char **argv) { const char *s; EGLmanager *eglman = calloc(1, sizeof(*eglman)); // Open X Display Display *x_dpy = XOpenDisplay(NULL); if (!x_dpy) { printf("error: can't open default display\n"); goto exit0; } eglman->xdpy = (EGLNativeDisplayType)x_dpy; // Get EGL Display eglman->dpy = eglGetDisplay(eglman->xdpy); if (!eglman->dpy || eglGetError() != EGL_SUCCESS) { printf("error: can't get EGL display\n"); goto exit1; } // Initialize EGL eglInitialize(eglman->dpy, &eglman->major_ver, &eglman->minor_ver); if (eglGetError() != EGL_SUCCESS) { goto exit1; } // Query and print out information s = eglQueryString(eglman->dpy, EGL_VERSION); printf("EGL_VERSION = %s\n", s); s = eglQueryString(eglman->dpy, EGL_VENDOR); printf("EGL_VENDOR = %s\n", s); s = eglQueryString(eglman->dpy, EGL_EXTENSIONS); printf("EGL_EXTENSIONS = %s\n", s); s = eglQueryString(eglman->dpy, EGL_CLIENT_APIS); printf("EGL_CLIENT_APIS = %s\n", s); // Create an RGB, double-buffered X window if (create_x_window(eglman, "vgimage to texture") != EGL_TRUE) { goto exit2; } XMapWindow(eglman->xdpy, eglman->xwin); // Initialize EGL if (egl_init(eglman) != EGL_TRUE) { goto exit3; } // Initialize rendering API: OpenGL ES and OpenVG if (vg_es_init(eglman) != EGL_TRUE) { goto exit3; } // Rendering draw(eglman); // Deinitialize rendering API vg_es_deinit(eglman); // Deinitialize EGL egl_deinit(eglman); exit3: XDestroyWindow(eglman->xdpy, eglman->xwin); exit2: eglTerminate(eglman->dpy); exit1: XCloseDisplay(eglman->xdpy); exit0: free(eglman); return 0; }