/* * gcc -g tfp-test.c -o tfp-test $(pkg-config --cflags --libs epoxy xrender xfixes xcomposite x11) */ #include #include #include #include #include #include #include #include #include #include Display *dpy; int screen; int depth; Visual *visual; Window root; XSetWindowAttributes swa; Window win; GLXWindow glw; GLXContext glc; Pixmap pixmap; int pixmap_width = 256, pixmap_height = 256; GC gc; GLuint texture_id; GLenum texture_type; GLint texture_target = 0; GLint texture_format = 0; bool texture_inverted = false; bool has_texture_rectangle; GLXFBConfig fb_config; GLXPixmap glxpixmap = 0; void Repaint () { XRenderColor background = { 0x7fff, 0x7fff, 0x7fff, 0xffff }; XRenderColor foreground = { 0xffff, 0x0000, 0x0000, 0xffff }; XRenderPictFormat *render_format; Picture pict; render_format = XRenderFindVisualFormat (dpy, visual); pict = XRenderCreatePicture (dpy, pixmap, render_format, 0, NULL); XRenderFillRectangle (dpy, PictOpSrc, pict, &background, 0, 0, pixmap_width, pixmap_height); XRenderFillRectangle (dpy, PictOpSrc, pict, &foreground, 20, 20, pixmap_width - 40, pixmap_height - 40); XRenderFreePicture (dpy, pict); XFlush (dpy); } void Rebind () { glXBindTexImageEXT (dpy, glxpixmap, GLX_FRONT_EXT, NULL); glEnable (texture_type); glTexParameteri (texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri (texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } void Redraw () { XWindowAttributes gwa; glXWaitX (); Repaint (); Rebind (); XGetWindowAttributes (dpy, win, &gwa); glViewport (0, 0, gwa.width, gwa.height); glMatrixMode(GL_TEXTURE); glPushMatrix (); if (texture_type == GL_TEXTURE_RECTANGLE_ARB) glScaled (pixmap_width, pixmap_height, 1.0); else glScaled (1.0, 1.0, 1.0); glTranslated (0.0, 0.0, 0.0); glBegin (GL_QUADS); glTexCoord2f(0.0, texture_inverted ? 1.0 : 0.0); glVertex2f(-1.0, 1.0); glTexCoord2f(1.0, texture_inverted ? 1.0 : 0.0); glVertex2f( 1.0, 1.0); glTexCoord2f(1.0, texture_inverted ? 0.0 : 1.0); glVertex2f( 1.0, -1.0); glTexCoord2f(0.0, texture_inverted ? 0.0 : 1.0); glVertex2f(-1.0, -1.0); glEnd (); glPopMatrix (); glXSwapBuffers (dpy, glw); glDisable (texture_type); glXReleaseTexImageEXT (dpy, glxpixmap, GLX_FRONT_EXT); } void GetFBConfig () { static GLint visual_attribs[] = { GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT, GLX_X_RENDERABLE, True, GLX_DOUBLEBUFFER, True, GLX_CONFIG_CAVEAT, GLX_DONT_CARE, GLX_DEPTH_SIZE, 1, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_RENDER_TYPE, GLX_RGBA_BIT, None }; int n_configs, i; int value, status; GLXFBConfig *configs; XVisualInfo *visual_info; int fb_match; VisualID xvisual_id; has_texture_rectangle = epoxy_has_gl_extension ("GL_ARB_texture_rectangle"); if (has_texture_rectangle) { printf ("Using texture type GL_TEXTURE_RECTANGLE_ARB\n"); texture_type = GL_TEXTURE_RECTANGLE_ARB; } else { printf ("Using texture type GL_TEXTURE_2D\n"); texture_type = GL_TEXTURE_2D; } configs = glXChooseFBConfig (dpy, screen, visual_attribs, &n_configs); if (configs == NULL) { printf ("Cannot retrieve GLX frame buffer config.\n"); exit (0); } fb_match = False; xvisual_id = XVisualIDFromVisual (visual); for (i = 0; i < n_configs; i++) { visual_info = glXGetVisualFromFBConfig (dpy, configs[i]); if (!visual_info) { printf (" - %i/%i: no visual info, skipped\n", i + 1, n_configs); continue; } if (visual_info->visualid != xvisual_id) { printf (" - %i/%i: xvisual id 0x%lx != 0x%lx, skipped\n", i + 1, n_configs, visual_info->visualid, xvisual_id); XFree (visual_info); continue; } XFree (visual_info); status = glXGetFBConfigAttrib (dpy, configs[i], GLX_DRAWABLE_TYPE, &value); if (status != Success || !(value & GLX_PIXMAP_BIT)) { printf (" - %i/%i: No GLX_PIXMAP_BIT, skipped\n", i + 1, n_configs); continue; } status = glXGetFBConfigAttrib (dpy, configs[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &value); if (status != Success) { printf (" - %i/%i: No GLX_BIND_TO_TEXTURE_TARGETS_EXT, skipped\n", i + 1, n_configs); continue; } if (texture_type == GL_TEXTURE_RECTANGLE_ARB) { if (value & GLX_TEXTURE_RECTANGLE_BIT_EXT) { texture_target = GLX_TEXTURE_RECTANGLE_EXT; printf ("Using texture target GLX_TEXTURE_RECTANGLE_EXT\n"); } else { printf (" - %i/%i: No GLX_TEXTURE_RECTANGLE_BIT_EXT, skipped\n", i + 1, n_configs); continue; } } else if (texture_type == GL_TEXTURE_2D) { if (value & GLX_TEXTURE_2D_BIT_EXT) { texture_target = GLX_TEXTURE_2D_EXT; printf ("Using texture target GLX_TEXTURE_2D_EXT\n"); } else { printf (" - %i/%i: No GLX_TEXTURE_2D_BIT_EXT, skipped\n", i + 1, n_configs); continue; } } else { printf (" - %i/%i: No GLX_TEXTURE_*_BIT_EXT, skipped\n", i + 1, n_configs); continue; } status = glXGetFBConfigAttrib (dpy, configs[i], GLX_RED_SIZE, &value); if (status == Success && value > 8) { printf (" - %i/%i: RGB10 config, skipped\n", i + 1, n_configs); continue; } status = glXGetFBConfigAttrib (dpy, configs[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &value); if (status == Success && value == True) { texture_format = GLX_TEXTURE_FORMAT_RGBA_EXT; printf ("Using texture format GLX_TEXTURE_FORMAT_RGBA_EXT\n"); } else { status = glXGetFBConfigAttrib (dpy, configs[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &value); if (status == Success && value == True) { printf ("Using texture format GLX_TEXTURE_FORMAT_RGB_EXT\n"); texture_format = GLX_TEXTURE_FORMAT_RGB_EXT; } else { printf (" - %i/%i: No GLX_BIND_TO_TEXTURE_RGB/RGBA_EXT, skipped\n", i + 1, n_configs); continue; } } status = glXGetFBConfigAttrib (dpy, configs[i], GLX_Y_INVERTED_EXT, &value); texture_inverted = (status == Success && value == True); if (texture_inverted) { printf ("Using texture attribute GLX_Y_INVERTED_EXT\n"); texture_inverted = True; } fb_config = configs[i]; fb_match = True; break; } XFree (configs); if (fb_match == False) { printf ("Cannot find a matching visual for the frame buffer config.\n"); exit (0); } } int main (int argc, char *argv[]) { GLint pixmap_attribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, None }; XEvent xev; dpy = XOpenDisplay (NULL); if (dpy == NULL) { printf ("Cannot open display\n"); exit (0); } root = DefaultRootWindow (dpy); screen = DefaultScreen (dpy); depth = DefaultDepth (dpy, screen); visual = DefaultVisual (dpy, screen); if (epoxy_glx_version (dpy, screen) < 13) { printf ("GLX version is too old\n"); exit (0); } if (!epoxy_has_glx_extension (dpy, screen, "GLX_EXT_texture_from_pixmap")) { printf ("Missing GLX_EXT_texture_from_pixmap extension\n"); exit (0); } swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask; win = XCreateWindow (dpy, root, 0, 0, pixmap_width, pixmap_height, 0, depth, InputOutput, visual, CWEventMask, &swa); XMapWindow (dpy, win); XStoreName (dpy, win, "PIXMAP TO TEXTURE"); GetFBConfig (); glc = glXCreateNewContext (dpy, fb_config, GLX_RGBA_TYPE, 0, GL_TRUE); if (glc == NULL) { printf ("Cannot create gl context\n"); exit (0); } glw = glXCreateWindow (dpy, fb_config, win, NULL); if (!glw) { printf ("Could not create GLX window.\n"); exit (0); } if (!glXMakeCurrent (dpy, glw, glc)) { printf ("Could not make OpenGL context current.\n"); exit (0); } printf ("Using renderer: '%s'\n", glGetString (GL_RENDERER)); pixmap = XCreatePixmap (dpy, root, pixmap_width, pixmap_height, depth); pixmap_attribs[1] = texture_target; pixmap_attribs[3] = texture_format; glxpixmap = glXCreatePixmap (dpy, fb_config, pixmap, pixmap_attribs); glEnable(texture_type); glGenTextures (1, &texture_id); glBindTexture (texture_type, texture_id); while (1) { XNextEvent (dpy, &xev); Redraw (); if (xev.type == KeyPress) { glXReleaseTexImageEXT (dpy, glxpixmap, GLX_FRONT_EXT); XFreePixmap (dpy, pixmap); glXMakeCurrent (dpy, None, NULL); glXDestroyContext (dpy, glc); XDestroyWindow (dpy, win); XCloseDisplay (dpy); exit (0); } } }