diff options
-rw-r--r-- | LICENSE | 19 | ||||
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | window_texture.c | 129 | ||||
-rw-r--r-- | window_texture.h | 39 |
4 files changed, 194 insertions, 0 deletions
@@ -0,0 +1,19 @@ +Copyright (c) dec05eba + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..37de08b --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +Utility to get the opengl texture associated with a x11 window.\ +It is recommended to use this over https://git.dec05eba.com/window-texture/about/ since EGL window textures are more reliable than GLX window texture, especially on nvidia. +For example when you use a compositor such as picom you cant get window textures on nvidia (only one application gets access to window textures at a time). +However with EGL there is no such issue (limitation) on nvidia (nor amd and intel). + +# Dependencies +egl (a library such as libglvnd), x11, xcomposite diff --git a/window_texture.c b/window_texture.c new file mode 100644 index 0000000..a4dbb38 --- /dev/null +++ b/window_texture.c @@ -0,0 +1,129 @@ +#include "window_texture.h" +#include <X11/extensions/Xcomposite.h> +#include <stdio.h> + +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) { + 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; +} diff --git a/window_texture.h b/window_texture.h new file mode 100644 index 0000000..7d3f899 --- /dev/null +++ b/window_texture.h @@ -0,0 +1,39 @@ +#ifndef WINDOW_TEXTURE_H +#define WINDOW_TEXTURE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EGL_EGLEXT_PROTOTYPES +#include <GL/gl.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <X11/Xlib.h> + +typedef struct { + Display *display; + EGLDisplay egl_display; + Window window; + Pixmap pixmap; + GLuint texture_id; + int redirected; +} WindowTexture; + +/* Returns 0 on success */ +int window_texture_init(WindowTexture *window_texture, Display *display, EGLDisplay egl_display, Window window); +void window_texture_deinit(WindowTexture *self); + +/* + This should ONLY be called when the target window is resized. + Returns 0 on success. +*/ +int window_texture_on_resize(WindowTexture *self); + +GLuint window_texture_get_opengl_texture_id(WindowTexture *self); + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_TEXTURE_H */ |