aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE19
-rw-r--r--README.md7
-rw-r--r--window_texture.c129
-rw-r--r--window_texture.h39
4 files changed, 194 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bc8b574
--- /dev/null
+++ b/LICENSE
@@ -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 */