From 989460af642d92fe654348fe1b39b9ff13747adc Mon Sep 17 00:00:00 2001 From: Predidit <34627277+Predidit@users.noreply.github.com> Date: Sun, 8 Feb 2026 05:50:23 +0800 Subject: [PATCH 1/3] draft --- media_kit_video/linux/texture_gl.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/media_kit_video/linux/texture_gl.cc b/media_kit_video/linux/texture_gl.cc index af9ca136e..91231746e 100644 --- a/media_kit_video/linux/texture_gl.cc +++ b/media_kit_video/linux/texture_gl.cc @@ -298,18 +298,21 @@ void texture_gl_check_and_resize(TextureGL* self, gint64 required_width, gint64 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, buf->texture, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + // Flush to ensure texture is fully defined before creating EGLImage + glFlush(); + // Create EGLImage from texture for sharing between contexts EGLint egl_image_attribs[] = { EGL_NONE }; buf->egl_image = eglCreateImageKHR( egl_display, - egl_context, + EGL_NO_CONTEXT, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(guintptr)buf->texture, egl_image_attribs); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - // Mark Flutter texture as invalid (needs recreation) buf->flutter_texture_valid = FALSE; buf->render_sync.store(EGL_NO_SYNC_KHR, std::memory_order_release); From a86c6c86616789e0891f31d639768b18da1c4a82 Mon Sep 17 00:00:00 2001 From: Predidit <34627277+Predidit@users.noreply.github.com> Date: Sun, 8 Feb 2026 06:06:47 +0800 Subject: [PATCH 2/3] Revert "draft" This reverts commit 989460af642d92fe654348fe1b39b9ff13747adc. --- media_kit_video/linux/texture_gl.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/media_kit_video/linux/texture_gl.cc b/media_kit_video/linux/texture_gl.cc index 91231746e..af9ca136e 100644 --- a/media_kit_video/linux/texture_gl.cc +++ b/media_kit_video/linux/texture_gl.cc @@ -298,21 +298,18 @@ void texture_gl_check_and_resize(TextureGL* self, gint64 required_width, gint64 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, buf->texture, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - - // Flush to ensure texture is fully defined before creating EGLImage - glFlush(); - // Create EGLImage from texture for sharing between contexts EGLint egl_image_attribs[] = { EGL_NONE }; buf->egl_image = eglCreateImageKHR( egl_display, - EGL_NO_CONTEXT, + egl_context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(guintptr)buf->texture, egl_image_attribs); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + // Mark Flutter texture as invalid (needs recreation) buf->flutter_texture_valid = FALSE; buf->render_sync.store(EGL_NO_SYNC_KHR, std::memory_order_release); From 2c93a40a3314fe03400247375e498b077de8ddd1 Mon Sep 17 00:00:00 2001 From: Predidit <34627277+Predidit@users.noreply.github.com> Date: Sun, 8 Feb 2026 06:11:37 +0800 Subject: [PATCH 3/3] only epoxy --- media_kit_video/linux/texture_gl.cc | 67 +++++------------------------ 1 file changed, 10 insertions(+), 57 deletions(-) diff --git a/media_kit_video/linux/texture_gl.cc b/media_kit_video/linux/texture_gl.cc index af9ca136e..d46a13d02 100644 --- a/media_kit_video/linux/texture_gl.cc +++ b/media_kit_video/linux/texture_gl.cc @@ -16,52 +16,6 @@ // Number of buffers for mailbox triple buffering #define NUM_BUFFERS 3 -// EGLImage extension function pointers -typedef EGLImageKHR (*PFNEGLCREATEIMAGEKHRPROC)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); -typedef EGLBoolean (*PFNEGLDESTROYIMAGEKHRPROC)(EGLDisplay dpy, EGLImageKHR image); -typedef void (*PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target, GLeglImageOES image); - -// EGL_KHR_fence_sync extension function pointers -typedef EGLSyncKHR (*PFNEGLCREATESYNCKHRPROC)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); -typedef EGLBoolean (*PFNEGLDESTROYSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync); -typedef EGLint (*PFNEGLCLIENTWAITSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); -typedef EGLint (*PFNEGLWAITSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags); - -// Define the extension functions -#ifndef eglCreateImageKHR -static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = NULL; -#endif -#ifndef eglDestroyImageKHR -static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = NULL; -#endif -#ifndef glEGLImageTargetTexture2DOES -static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = NULL; -#endif - -// EGL_KHR_fence_sync extension functions -static PFNEGLCREATESYNCKHRPROC _eglCreateSyncKHR = NULL; -static PFNEGLDESTROYSYNCKHRPROC _eglDestroySyncKHR = NULL; -static PFNEGLCLIENTWAITSYNCKHRPROC _eglClientWaitSyncKHR = NULL; -static PFNEGLWAITSYNCKHRPROC _eglWaitSyncKHR = NULL; - -static void init_egl_extensions() { - static gboolean initialized = FALSE; - if (!initialized) { - // EGLImage extensions - eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR"); - eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR"); - glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); - - // EGL_KHR_fence_sync extensions - _eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC)eglGetProcAddress("eglCreateSyncKHR"); - _eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)eglGetProcAddress("eglDestroySyncKHR"); - _eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)eglGetProcAddress("eglClientWaitSyncKHR"); - _eglWaitSyncKHR = (PFNEGLWAITSYNCKHRPROC)eglGetProcAddress("eglWaitSyncKHR"); - - initialized = TRUE; - } -} - // Buffer structure for mailbox triple buffering // Each buffer has its own GPU resources typedef struct { @@ -181,7 +135,7 @@ static void texture_gl_dispose(GObject* object) { // Clean up EGLSyncKHR EGLSyncKHR sync = buf->render_sync.load(std::memory_order_acquire); if (sync != EGL_NO_SYNC_KHR) { - _eglDestroySyncKHR(egl_display, sync); + eglDestroySyncKHR(egl_display, sync); buf->render_sync.store(EGL_NO_SYNC_KHR, std::memory_order_release); } @@ -224,7 +178,6 @@ static void texture_gl_class_init(TextureGLClass* klass) { } TextureGL* texture_gl_new(VideoOutput* video_output) { - init_egl_extensions(); TextureGL* self = TEXTURE_GL(g_object_new(texture_gl_get_type(), NULL)); self->video_output = video_output; return self; @@ -266,9 +219,9 @@ void texture_gl_check_and_resize(TextureGL* self, gint64 required_width, gint64 // Wait for any pending GPU work before destroying resources EGLSyncKHR sync = buf->render_sync.load(std::memory_order_acquire); if (sync != EGL_NO_SYNC_KHR) { - _eglClientWaitSyncKHR(egl_display, sync, + eglClientWaitSyncKHR(egl_display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); - _eglDestroySyncKHR(egl_display, sync); + eglDestroySyncKHR(egl_display, sync); buf->render_sync.store(EGL_NO_SYNC_KHR, std::memory_order_release); } @@ -359,8 +312,8 @@ gboolean texture_gl_render(TextureGL* self) { EGLSyncKHR old_sync = back_buf->render_sync.exchange(EGL_NO_SYNC_KHR, std::memory_order_acq_rel); if (old_sync != EGL_NO_SYNC_KHR) { // Wait for previous GPU work to complete, then destroy the sync - _eglClientWaitSyncKHR(egl_display, old_sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); - _eglDestroySyncKHR(egl_display, old_sync); + eglClientWaitSyncKHR(egl_display, old_sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); + eglDestroySyncKHR(egl_display, old_sync); } gint32 required_width = self->current_width; @@ -390,7 +343,7 @@ gboolean texture_gl_render(TextureGL* self) { // Create sync fence to mark render completion // Consumer will use this for GPU-side synchronization - EGLSyncKHR new_sync = _eglCreateSyncKHR(egl_display, EGL_SYNC_FENCE_KHR, NULL); + EGLSyncKHR new_sync = eglCreateSyncKHR(egl_display, EGL_SYNC_FENCE_KHR, NULL); back_buf->render_sync.store(new_sync, std::memory_order_release); return TRUE; @@ -481,14 +434,14 @@ gboolean texture_gl_populate_texture(FlTextureGL* texture, if (sync != EGL_NO_SYNC_KHR) { // Use GPU-side wait for better performance (doesn't block CPU) // This inserts a wait into Flutter's GL command stream - if (_eglWaitSyncKHR != NULL) { - _eglWaitSyncKHR(egl_display, sync, 0); + if (epoxy_has_egl_extension(egl_display, "EGL_KHR_wait_sync")) { + eglWaitSyncKHR(egl_display, sync, 0); } else { // Fallback to CPU wait if eglWaitSyncKHR not available - _eglClientWaitSyncKHR(egl_display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); + eglClientWaitSyncKHR(egl_display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); } // Destroy the sync after use (we own it now) - _eglDestroySyncKHR(egl_display, sync); + eglDestroySyncKHR(egl_display, sync); } // Check if we need to create/recreate Flutter texture for this buffer