#include "window_texture.h" #include #include static int x11_supports_composite_named_window_pixmap(Display *display) { int extension_major; int extension_minor; if(!XCompositeQueryExtension(display, &extension_major, &extension_minor)) return 0; int major_version; int minor_version; return XCompositeQueryVersion(display, &major_version, &minor_version) && (major_version > 0 || minor_version >= 2); } int window_texture_init(WindowTexture *window_texture, Display *display, EGLDisplay egl_display, Window window) { window_texture->display = display; window_texture->egl_display = egl_display; window_texture->window = window; window_texture->pixmap = None; window_texture->texture_id = 0; window_texture->redirected = 0; if(!x11_supports_composite_named_window_pixmap(display)) return 1; XCompositeRedirectWindow(display, window, CompositeRedirectAutomatic); window_texture->redirected = 1; return window_texture_on_resize(window_texture); } static void window_texture_cleanup(WindowTexture *self, int delete_texture) { if(delete_texture && self->texture_id) { glDeleteTextures(1, &self->texture_id); self->texture_id = 0; } if(self->pixmap) { XFreePixmap(self->display, self->pixmap); self->pixmap = None; } } void window_texture_deinit(WindowTexture *self) { if(self->redirected) { XCompositeUnredirectWindow(self->display, self->window, CompositeRedirectAutomatic); self->redirected = 0; } window_texture_cleanup(self, 1); } int window_texture_on_resize(WindowTexture *self) { window_texture_cleanup(self, 0); int result = 0; Pixmap pixmap = None; GLuint texture_id = 0; EGLImage image = NULL; const intptr_t pixmap_attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, }; pixmap = XCompositeNameWindowPixmap(self->display, self->window); if(!pixmap) { result = 2; goto cleanup; } if(self->texture_id == 0) { glGenTextures(1, &texture_id); if(texture_id == 0) { result = 4; goto cleanup; } glBindTexture(GL_TEXTURE_2D, texture_id); } else { glBindTexture(GL_TEXTURE_2D, self->texture_id); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* float fLargest = 0.0f; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest); */ while(glGetError()) {} while(eglGetError() != EGL_SUCCESS) {} image = eglCreateImage(self->egl_display, NULL, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)pixmap, pixmap_attrs); if(!image) { /* One reason this can happen is if the egl display is not the same as the X11 display passed to window_texture_init */ result = 4; goto cleanup; } glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); if(glGetError() != 0 || eglGetError() != EGL_SUCCESS) { result = 5; goto cleanup; } self->pixmap = pixmap; self->texture_id = texture_id; cleanup: glBindTexture(GL_TEXTURE_2D, 0); if(image) eglDestroyImage(self->egl_display, image); if(result != 0) { if(texture_id != 0) glDeleteTextures(1, &texture_id); if(pixmap) XFreePixmap(self->display, pixmap); } return result; } GLuint window_texture_get_opengl_texture_id(WindowTexture *self) { return self->texture_id; }