From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 122 +++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 621ee66d3ef..d905b4bd22c 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -66,6 +66,7 @@ DECL_FUNCPTR(eglGetDisplay); DECL_FUNCPTR(eglGetError); DECL_FUNCPTR(eglGetProcAddress); DECL_FUNCPTR(eglInitialize); +DECL_FUNCPTR(eglMakeCurrent); #undef DECL_FUNCPTR
static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -88,6 +89,7 @@ struct wgl_context struct list entry; EGLConfig config; EGLContext context; + struct wayland_gl_drawable *draw, *read; };
static struct wayland_gl_drawable *wayland_gl_drawable_get(HWND hwnd) @@ -190,9 +192,43 @@ err: return NULL; }
+static inline void wayland_gl_drawable_array_add(struct wl_array *drawables, + struct wayland_gl_drawable *gl) +{ + struct wayland_gl_drawable **elem; + + if ((elem = wl_array_add(drawables, sizeof(gl)))) *elem = gl; +} + +static void update_context_drawables(struct wayland_gl_drawable *new, + struct wayland_gl_drawable *old, + struct wl_array *release) +{ + struct wgl_context *ctx; + + LIST_FOR_EACH_ENTRY(ctx, &gl_contexts, struct wgl_context, entry) + { + if (ctx->draw == old) + { + wayland_gl_drawable_array_add(release, ctx->draw); + InterlockedIncrement(&new->ref); + ctx->draw = new; + } + if (ctx->read == old) + { + wayland_gl_drawable_array_add(release, ctx->read); + InterlockedIncrement(&new->ref); + ctx->read = new; + } + } +} + static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *new) { struct wayland_gl_drawable *gl, *old = NULL; + struct wl_array release; + + wl_array_init(&release);
pthread_mutex_lock(&gl_object_mutex);
@@ -204,10 +240,61 @@ static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *ne break; } if (new) list_add_head(&gl_drawables, &new->entry); + if (old && new) update_context_drawables(new, old, &release); + if (old) wayland_gl_drawable_array_add(&release, old); + + pthread_mutex_unlock(&gl_object_mutex); + + /* Release the drawables outside the gl_object_mutex lock, since the release + * process may acquire the wayland_surface lock and lead to a deadlock. */ + wl_array_for_each(gl, &release) wayland_gl_drawable_release(gl); + wl_array_release(&release); +} + +static BOOL wgl_context_make_current(struct wgl_context *ctx, HWND draw_hwnd, + HWND read_hwnd) +{ + BOOL ret; + struct wayland_gl_drawable *draw_gl = NULL, *read_gl = NULL; + struct wayland_gl_drawable *release[2]; + int i; + + draw_gl = wayland_gl_drawable_get(draw_hwnd); + read_gl = wayland_gl_drawable_get(read_hwnd); + + TRACE("%p/%p context %p surface %p/%p\n", + draw_hwnd, read_hwnd, ctx->context, + draw_gl ? draw_gl->surface : NULL, + read_gl ? read_gl->surface : NULL); + + pthread_mutex_lock(&gl_object_mutex); + + ret = p_eglMakeCurrent(egl_display, + draw_gl ? draw_gl->surface : NULL, + read_gl ? read_gl->surface : NULL, + ctx->context); + if (ret) + { + release[0] = ctx->draw; + release[1] = ctx->read; + ctx->draw = draw_gl; + ctx->read = read_gl; + NtCurrentTeb()->glContext = ctx; + } + else + { + release[0] = draw_gl; + release[1] = read_gl; + }
pthread_mutex_unlock(&gl_object_mutex);
- if (old) wayland_gl_drawable_release(old); + /* Release the drawables outside the gl_object_mutex lock, since the release + * process may acquire the wayland_surface lock and lead to a deadlock. */ + for (i = 0; i < ARRAY_SIZE(release); ++i) + if (release[i]) wayland_gl_drawable_release(release[i]); + + return ret; }
static BOOL set_pixel_format(HDC hdc, int format, BOOL internal) @@ -289,6 +376,8 @@ static BOOL wayland_wglDeleteContext(struct wgl_context *ctx) list_remove(&ctx->entry); pthread_mutex_unlock(&gl_object_mutex); p_eglDestroyContext(egl_display, ctx->context); + if (ctx->draw) wayland_gl_drawable_release(ctx->draw); + if (ctx->read) wayland_gl_drawable_release(ctx->read); free(ctx); return TRUE; } @@ -369,6 +458,31 @@ static PROC wayland_wglGetProcAddress(LPCSTR name) return ret; }
+static BOOL wayland_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, + struct wgl_context *ctx) +{ + BOOL ret; + + TRACE("draw_hdc=%p read_hdc=%p ctx=%p\n", draw_hdc, read_hdc, ctx); + + if (!ctx) + { + p_eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + NtCurrentTeb()->glContext = NULL; + return TRUE; + } + + ret = wgl_context_make_current(ctx, NtUserWindowFromDC(draw_hdc), NtUserWindowFromDC(read_hdc)); + if (!ret) RtlSetLastWin32Error(ERROR_INVALID_HANDLE); + + return ret; +} + +static BOOL wayland_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) +{ + return wayland_wglMakeContextCurrentARB(hdc, hdc, ctx); +} + static BOOL wayland_wglSetPixelFormat(HDC hdc, int format, const PIXELFORMATDESCRIPTOR *pfd) { @@ -416,6 +530,10 @@ static BOOL init_opengl_funcs(void) register_extension("WGL_WINE_pixel_format_passthrough"); opengl_funcs.ext.p_wglSetPixelFormatWINE = wayland_wglSetPixelFormatWINE;
+ register_extension("WGL_ARB_make_current_read"); + opengl_funcs.ext.p_wglGetCurrentReadDCARB = (void *)1; /* never called */ + opengl_funcs.ext.p_wglMakeContextCurrentARB = wayland_wglMakeContextCurrentARB; + return TRUE; }
@@ -508,6 +626,7 @@ static void init_opengl(void) LOAD_FUNCPTR(eglGetDisplay); LOAD_FUNCPTR(eglGetError); LOAD_FUNCPTR(eglInitialize); + LOAD_FUNCPTR(eglMakeCurrent); #undef LOAD_FUNCPTR
egl_display = p_eglGetDisplay((EGLNativeDisplayType)process_wayland.wl_display); @@ -557,6 +676,7 @@ static struct opengl_funcs opengl_funcs = .p_wglDeleteContext = wayland_wglDeleteContext, .p_wglDescribePixelFormat = wayland_wglDescribePixelFormat, .p_wglGetProcAddress = wayland_wglGetProcAddress, + .p_wglMakeCurrent = wayland_wglMakeCurrent, .p_wglSetPixelFormat = wayland_wglSetPixelFormat, } };