EGL Wayland doesn't support pbuffer EGLSurfaces (and it doesn't seem it will ever gain support for them), but we can emulate them in winewayland WGL/OpenGL by using a normal window EGLSurface targeting an unmapped wl_surface. For `wglBindTexImage` we use the same `glCopyTexImage` approach used by winex11 and, like in winex11, our implementation is incomplete (only 2D textures and only from the pbuffer back buffer), but should be a good start.
Please try a few of your (likely) older games that use pbuffers and let me know if you see any issues.
Note: While implementing this I realized that we are missing a `wglGetPixelFormat` implementation, I will provide one in a follow-up MR.
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 183 +++++++++++++++++++++++++++++++--- 1 file changed, 167 insertions(+), 16 deletions(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 994154968b3..eb0c973ac49 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -77,6 +77,7 @@ DECL_FUNCPTR(glClear); static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; static struct list gl_drawables = LIST_INIT(gl_drawables); static struct list gl_contexts = LIST_INIT(gl_contexts); +static struct list gl_pbuffer_dcs = LIST_INIT(gl_pbuffer_dcs);
struct wayland_gl_drawable { @@ -101,12 +102,34 @@ struct wgl_context BOOL sharing; };
+struct wgl_pbuffer +{ + struct wayland_gl_drawable *gl; + int width, height; +}; + +struct wayland_pbuffer_dc +{ + struct list entry; + HDC hdc; + struct wayland_gl_drawable *gl; +}; + /* lookup the existing drawable for a window, gl_object_mutex must be held */ -static struct wayland_gl_drawable *find_drawable_for_hwnd(HWND hwnd) +static struct wayland_gl_drawable *find_drawable(HWND hwnd, HDC hdc) { struct wayland_gl_drawable *gl; - LIST_FOR_EACH_ENTRY(gl, &gl_drawables, struct wayland_gl_drawable, entry) - if (gl->hwnd == hwnd) return gl; + struct wayland_pbuffer_dc *pb; + if (hwnd) + { + LIST_FOR_EACH_ENTRY(gl, &gl_drawables, struct wayland_gl_drawable, entry) + if (gl->hwnd == hwnd) return gl; + } + if (hdc) + { + LIST_FOR_EACH_ENTRY(pb, &gl_pbuffer_dcs, struct wayland_pbuffer_dc, entry) + if (pb->hdc == hdc) return pb->gl; + } return NULL; }
@@ -116,12 +139,12 @@ static struct wayland_gl_drawable *wayland_gl_drawable_acquire(struct wayland_gl return gl; }
-static struct wayland_gl_drawable *wayland_gl_drawable_get(HWND hwnd) +static struct wayland_gl_drawable *wayland_gl_drawable_get(HWND hwnd, HDC hdc) { struct wayland_gl_drawable *ret;
pthread_mutex_lock(&gl_object_mutex); - if ((ret = find_drawable_for_hwnd(hwnd))) + if ((ret = find_drawable(hwnd, hdc))) ret = wayland_gl_drawable_acquire(ret); pthread_mutex_unlock(&gl_object_mutex);
@@ -229,7 +252,7 @@ static void wayland_update_gl_drawable(HWND hwnd, struct wayland_gl_drawable *ne
pthread_mutex_lock(&gl_object_mutex);
- if ((old = find_drawable_for_hwnd(hwnd))) list_remove(&old->entry); + if ((old = find_drawable(hwnd, 0))) list_remove(&old->entry); if (new) list_add_head(&gl_drawables, &new->entry); if (old && new) { @@ -284,18 +307,17 @@ static void wayland_gl_drawable_sync_surface_state(struct wayland_gl_drawable *g pthread_mutex_unlock(&wayland_surface->mutex); }
-static BOOL wgl_context_make_current(struct wgl_context *ctx, HWND draw_hwnd, - HWND read_hwnd) +static BOOL wgl_context_make_current(struct wgl_context *ctx, HDC draw_hdc, HDC read_hdc) { BOOL ret; struct wayland_gl_drawable *draw, *read; struct wayland_gl_drawable *old_draw = NULL, *old_read = NULL;
- draw = wayland_gl_drawable_get(draw_hwnd); - read = wayland_gl_drawable_get(read_hwnd); + draw = wayland_gl_drawable_get(NtUserWindowFromDC(draw_hdc), draw_hdc); + read = wayland_gl_drawable_get(NtUserWindowFromDC(read_hdc), read_hdc);
TRACE("%p/%p context %p surface %p/%p\n", - draw_hwnd, read_hwnd, ctx->context, + draw_hdc, read_hdc, ctx->context, draw ? draw->surface : EGL_NO_SURFACE, read ? read->surface : EGL_NO_SURFACE);
@@ -466,7 +488,7 @@ static struct wgl_context *create_context(HDC hdc, struct wgl_context *share, struct wayland_gl_drawable *gl; struct wgl_context *ctx;
- if (!(gl = wayland_gl_drawable_get(NtUserWindowFromDC(hdc)))) return NULL; + if (!(gl = wayland_gl_drawable_get(NtUserWindowFromDC(hdc), hdc))) return NULL;
if (!(ctx = calloc(1, sizeof(*ctx)))) { @@ -503,6 +525,41 @@ out: return ctx; }
+static struct wayland_gl_drawable *clear_pbuffer_dc(HDC hdc) +{ + struct wayland_pbuffer_dc *pd; + struct wayland_gl_drawable *gl; + + LIST_FOR_EACH_ENTRY(pd, &gl_pbuffer_dcs, struct wayland_pbuffer_dc, entry) + { + if (pd->hdc == hdc) + { + list_remove(&pd->entry); + gl = pd->gl; + free(pd); + return gl; + } + } + + return NULL; +} + +static BOOL set_pbuffer_dc(struct wgl_pbuffer *pbuffer, HDC hdc) +{ + struct wayland_pbuffer_dc *pd; + + if (!(pd = calloc(1, sizeof(*pd)))) + { + ERR("Failed to allocate memory for pbuffer HDC mapping\n"); + return FALSE; + } + pd->hdc = hdc; + pd->gl = wayland_gl_drawable_acquire(pbuffer->gl); + list_add_head(&gl_pbuffer_dcs, &pd->entry); + + return TRUE; +} + void wayland_glClear(GLbitfield mask) { struct wgl_context *ctx = NtCurrentTeb()->glContext; @@ -592,7 +649,7 @@ static BOOL wayland_wglMakeContextCurrentARB(HDC draw_hdc, HDC read_hdc, return TRUE; }
- ret = wgl_context_make_current(ctx, NtUserWindowFromDC(draw_hdc), NtUserWindowFromDC(read_hdc)); + ret = wgl_context_make_current(ctx, draw_hdc, read_hdc); if (!ret) RtlSetLastWin32Error(ERROR_INVALID_HANDLE);
return ret; @@ -660,10 +717,9 @@ static BOOL wayland_wglShareLists(struct wgl_context *orig, struct wgl_context * static BOOL wayland_wglSwapBuffers(HDC hdc) { struct wgl_context *ctx = NtCurrentTeb()->glContext; - HWND hwnd = NtUserWindowFromDC(hdc); struct wayland_gl_drawable *gl;
- if (!(gl = wayland_gl_drawable_get(hwnd))) return FALSE; + if (!(gl = wayland_gl_drawable_get(NtUserWindowFromDC(hdc), hdc))) return FALSE;
if (ctx) wgl_context_refresh(ctx); wayland_gl_drawable_sync_surface_state(gl); @@ -706,6 +762,94 @@ static BOOL wayland_wglSwapIntervalEXT(int interval) return ret; }
+static struct wgl_pbuffer *wayland_wglCreatePbufferARB(HDC hdc, int format, + int width, int height, + const int *attribs) +{ + struct wgl_pbuffer *pbuffer; + + TRACE("(%p, %d, %d, %d, %p)\n", hdc, format, width, height, attribs); + + /* Use an unmapped wayland surface as our offscreen "pbuffer" surface. */ + if (!(pbuffer = calloc(1, sizeof(*pbuffer))) || + !(pbuffer->gl = wayland_gl_drawable_create(0, format))) + { + RtlSetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES); + free(pbuffer); + return NULL; + } + + pbuffer->width = width; + pbuffer->height = height; + wl_egl_window_resize(pbuffer->gl->wl_egl_window, width, height, 0, 0); + + return pbuffer; +} + +static BOOL wayland_wglDestroyPbufferARB(struct wgl_pbuffer *pbuffer) +{ + TRACE("(%p)\n", pbuffer); + + wayland_gl_drawable_release(pbuffer->gl); + free(pbuffer); + + return GL_TRUE; +} + +static HDC wayland_wglGetPbufferDCARB(struct wgl_pbuffer *pbuffer) +{ + HDC hdc; + BOOL set; + struct wayland_gl_drawable *old; + + if (!(hdc = NtGdiOpenDCW(NULL, NULL, NULL, 0, TRUE, NULL, NULL, NULL))) return 0; + + pthread_mutex_lock(&gl_object_mutex); + old = clear_pbuffer_dc(hdc); + set = set_pbuffer_dc(pbuffer, hdc); + pthread_mutex_unlock(&gl_object_mutex); + + if (old) wayland_gl_drawable_release(old); + if (!set) + { + NtGdiDeleteObjectApp(hdc); + return 0; + } + + return hdc; +} + +static BOOL wayland_wglQueryPbufferARB(struct wgl_pbuffer *pbuffer, int attrib, int *value) +{ + TRACE("(%p, 0x%x, %p)\n", pbuffer, attrib, value); + + switch (attrib) + { + case WGL_PBUFFER_WIDTH_ARB: *value = pbuffer->width; break; + case WGL_PBUFFER_HEIGHT_ARB: *value = pbuffer->height; break; + case WGL_PBUFFER_LOST_ARB: *value = GL_FALSE; break; + default: + FIXME("unexpected attribute %x\n", attrib); + break; + } + + return GL_TRUE; +} + +static int wayland_wglReleasePbufferDCARB(struct wgl_pbuffer *pbuffer, HDC hdc) +{ + struct wayland_gl_drawable *old; + + pthread_mutex_lock(&gl_object_mutex); + old = clear_pbuffer_dc(hdc); + pthread_mutex_unlock(&gl_object_mutex); + + if (old) wayland_gl_drawable_release(old); + else hdc = 0; + + return hdc && NtGdiDeleteObjectApp(hdc); +} + static void describe_pixel_format(EGLConfig config, struct wgl_pixel_format *fmt) { EGLint value, surface_type; @@ -919,6 +1063,13 @@ static BOOL init_opengl_funcs(void) register_extension("WGL_ATI_pixel_format_float"); }
+ register_extension("WGL_ARB_pbuffer"); + opengl_funcs.ext.p_wglCreatePbufferARB = wayland_wglCreatePbufferARB; + opengl_funcs.ext.p_wglDestroyPbufferARB = wayland_wglDestroyPbufferARB; + opengl_funcs.ext.p_wglGetPbufferDCARB = wayland_wglGetPbufferDCARB; + opengl_funcs.ext.p_wglQueryPbufferARB = wayland_wglQueryPbufferARB; + opengl_funcs.ext.p_wglReleasePbufferDCARB = wayland_wglReleasePbufferDCARB; + return TRUE; }
@@ -1118,7 +1269,7 @@ void wayland_resize_gl_drawable(HWND hwnd) { struct wayland_gl_drawable *gl;
- if (!(gl = wayland_gl_drawable_get(hwnd))) return; + if (!(gl = wayland_gl_drawable_get(hwnd, 0))) return; /* wl_egl_window_resize is not thread safe, so we just mark the * drawable as resized and perform the resize in the proper thread. */ InterlockedExchange(&gl->resized, TRUE);
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index eb0c973ac49..8694c558ada 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -63,6 +63,8 @@ DECL_FUNCPTR(eglCreateWindowSurface); DECL_FUNCPTR(eglDestroyContext); DECL_FUNCPTR(eglDestroySurface); DECL_FUNCPTR(eglGetConfigAttrib); +DECL_FUNCPTR(eglGetCurrentContext); +DECL_FUNCPTR(eglGetCurrentSurface); DECL_FUNCPTR(eglGetError); DECL_FUNCPTR(eglGetPlatformDisplay); DECL_FUNCPTR(eglGetProcAddress); @@ -78,6 +80,7 @@ static pthread_mutex_t gl_object_mutex = PTHREAD_MUTEX_INITIALIZER; static struct list gl_drawables = LIST_INIT(gl_drawables); static struct list gl_contexts = LIST_INIT(gl_contexts); static struct list gl_pbuffer_dcs = LIST_INIT(gl_pbuffer_dcs); +static struct list gl_pbuffers = LIST_INIT(gl_pbuffers);
struct wayland_gl_drawable { @@ -104,8 +107,11 @@ struct wgl_context
struct wgl_pbuffer { + struct list entry; struct wayland_gl_drawable *gl; int width, height; + int texture_format, texture_target, texture_binding; + EGLContext tmp_context, prev_context; };
struct wayland_pbuffer_dc @@ -592,8 +598,18 @@ static struct wgl_context *wayland_wglCreateContextAttribsARB(HDC hdc,
static BOOL wayland_wglDeleteContext(struct wgl_context *ctx) { + struct wgl_pbuffer *pb; + pthread_mutex_lock(&gl_object_mutex); list_remove(&ctx->entry); + LIST_FOR_EACH_ENTRY(pb, &gl_pbuffers, struct wgl_pbuffer, entry) + { + if (pb->prev_context == ctx->context) + { + p_eglDestroyContext(egl_display, pb->tmp_context); + pb->prev_context = pb->tmp_context = NULL; + } + } pthread_mutex_unlock(&gl_object_mutex); p_eglDestroyContext(egl_display, ctx->context); if (ctx->draw) wayland_gl_drawable_release(ctx->draw); @@ -783,13 +799,101 @@ static struct wgl_pbuffer *wayland_wglCreatePbufferARB(HDC hdc, int format, pbuffer->height = height; wl_egl_window_resize(pbuffer->gl->wl_egl_window, width, height, 0, 0);
+ for (; attribs && attribs[0]; attribs += 2) + { + switch (attribs[0]) + { + case WGL_TEXTURE_FORMAT_ARB: + TRACE("attribs[WGL_TEXTURE_FORMAT_ARB]=0x%x\n", attribs[1]); + switch(attribs[1]) + { + case WGL_NO_TEXTURE_ARB: + pbuffer->texture_format = 0; + break; + case WGL_TEXTURE_RGB_ARB: + pbuffer->texture_format = GL_RGB; + break; + case WGL_TEXTURE_RGBA_ARB: + pbuffer->texture_format = GL_RGBA; + break; + /* WGL_FLOAT_COMPONENTS_NV */ + case WGL_TEXTURE_FLOAT_R_NV: + pbuffer->texture_format = GL_FLOAT_R_NV; + break; + case WGL_TEXTURE_FLOAT_RG_NV: + pbuffer->texture_format = GL_FLOAT_RG_NV; + break; + case WGL_TEXTURE_FLOAT_RGB_NV: + pbuffer->texture_format = GL_FLOAT_RGB_NV; + break; + case WGL_TEXTURE_FLOAT_RGBA_NV: + pbuffer->texture_format = GL_FLOAT_RGBA_NV; + break; + default: + ERR("Unknown texture format: %x\n", attribs[1]); + } + break; + + case WGL_TEXTURE_TARGET_ARB: + TRACE("attribs[WGL_TEXTURE_TARGET_ARB]=0x%x\n", attribs[1]); + switch (attribs[1]) + { + case WGL_TEXTURE_CUBE_MAP_ARB: + if (width != height) goto err; + pbuffer->texture_target = GL_TEXTURE_CUBE_MAP; + pbuffer->texture_binding = GL_TEXTURE_BINDING_CUBE_MAP; + break; + case WGL_TEXTURE_1D_ARB: + if (height != 1) goto err; + pbuffer->texture_target = GL_TEXTURE_1D; + pbuffer->texture_binding = GL_TEXTURE_BINDING_1D; + break; + case WGL_TEXTURE_2D_ARB: + pbuffer->texture_target = GL_TEXTURE_2D; + pbuffer->texture_binding = GL_TEXTURE_BINDING_2D; + break; + case WGL_TEXTURE_RECTANGLE_NV: + pbuffer->texture_target = GL_TEXTURE_RECTANGLE_NV; + pbuffer->texture_binding = GL_TEXTURE_BINDING_RECTANGLE_NV; + break; + default: + ERR("Unknown texture target: %x\n", attribs[1]); + goto err; + } + break; + + case WGL_MIPMAP_TEXTURE_ARB: + TRACE("attribs[WGL_MIPMAP_TEXTURE_ARB]=0x%x\n", attribs[1]); + break; + + default: + WARN("Unknown attribute: %x\n", attribs[0]); + break; + } + } + + pthread_mutex_lock(&gl_object_mutex); + list_add_head(&gl_pbuffers, &pbuffer->entry); + pthread_mutex_unlock(&gl_object_mutex); + return pbuffer; + +err: + RtlSetLastWin32Error(ERROR_INVALID_DATA); + wayland_gl_drawable_release(pbuffer->gl); + free(pbuffer); + return NULL; }
static BOOL wayland_wglDestroyPbufferARB(struct wgl_pbuffer *pbuffer) { TRACE("(%p)\n", pbuffer);
+ pthread_mutex_lock(&gl_object_mutex); + list_remove(&pbuffer->entry); + pthread_mutex_unlock(&gl_object_mutex); + + if (pbuffer->tmp_context) p_eglDestroyContext(egl_display, pbuffer->tmp_context); wayland_gl_drawable_release(pbuffer->gl); free(pbuffer);
@@ -828,6 +932,36 @@ static BOOL wayland_wglQueryPbufferARB(struct wgl_pbuffer *pbuffer, int attrib, case WGL_PBUFFER_WIDTH_ARB: *value = pbuffer->width; break; case WGL_PBUFFER_HEIGHT_ARB: *value = pbuffer->height; break; case WGL_PBUFFER_LOST_ARB: *value = GL_FALSE; break; + case WGL_TEXTURE_FORMAT_ARB: + switch(pbuffer->texture_format) + { + case GL_RGB: *value = WGL_TEXTURE_RGB_ARB; break; + case GL_RGBA: *value = WGL_TEXTURE_RGBA_ARB; break; + case GL_FLOAT_R_NV: *value = WGL_TEXTURE_FLOAT_R_NV; break; + case GL_FLOAT_RG_NV: *value = WGL_TEXTURE_FLOAT_RG_NV; break; + case GL_FLOAT_RGB_NV: *value = WGL_TEXTURE_FLOAT_RGB_NV; break; + case GL_FLOAT_RGBA_NV: *value = WGL_TEXTURE_FLOAT_RGBA_NV; break; + default: + ERR("Unknown texture format: %x\n", pbuffer->texture_format); + break; + } + break; + case WGL_TEXTURE_TARGET_ARB: + switch (pbuffer->texture_target) + { + case GL_TEXTURE_1D: *value = WGL_TEXTURE_1D_ARB; break; + case GL_TEXTURE_2D: *value = WGL_TEXTURE_2D_ARB; break; + case GL_TEXTURE_CUBE_MAP: *value = WGL_TEXTURE_CUBE_MAP_ARB; break; + case GL_TEXTURE_RECTANGLE_NV: *value = WGL_TEXTURE_RECTANGLE_NV; break; + default: + ERR("Unknown texture target: %x\n", pbuffer->texture_target); + break; + } + break; + case WGL_MIPMAP_TEXTURE_ARB: + *value = GL_FALSE; + FIXME("unsupported attribute query for 0x%x\n", attrib); + break; default: FIXME("unexpected attribute %x\n", attrib); break; @@ -850,6 +984,66 @@ static int wayland_wglReleasePbufferDCARB(struct wgl_pbuffer *pbuffer, HDC hdc) return hdc && NtGdiDeleteObjectApp(hdc); }
+static BOOL wayland_wglBindTexImageARB(struct wgl_pbuffer *pbuffer, int buffer) +{ + EGLContext prev_context = p_eglGetCurrentContext(); + EGLSurface prev_draw = p_eglGetCurrentSurface(EGL_DRAW); + EGLSurface prev_read = p_eglGetCurrentSurface(EGL_READ); + int prev_bound_texture = 0; + + TRACE("(%p, %d)\n", pbuffer, buffer); + + if (!pbuffer->tmp_context || pbuffer->prev_context != prev_context) + { + if (pbuffer->tmp_context) p_eglDestroyContext(egl_display, pbuffer->tmp_context); + p_eglBindAPI(EGL_OPENGL_API); + pbuffer->tmp_context = + p_eglCreateContext(egl_display, EGL_NO_CONFIG_KHR, prev_context, NULL); + pbuffer->prev_context = prev_context; + } + + opengl_funcs.gl.p_glGetIntegerv(pbuffer->texture_binding, &prev_bound_texture); + + p_eglMakeCurrent(egl_display, pbuffer->gl->surface, pbuffer->gl->surface, + pbuffer->tmp_context); + + /* Make sure that the prev_bound_texture is set as the current texture + * state isn't shared between contexts. After that copy the pbuffer texture + * data. Note that at the moment we ignore the 'buffer' argument and always + * copy from the pbuffer back buffer. */ + opengl_funcs.gl.p_glBindTexture(pbuffer->texture_target, prev_bound_texture); + opengl_funcs.gl.p_glCopyTexImage2D(pbuffer->texture_target, 0, + pbuffer->texture_format, 0, 0, + pbuffer->width, pbuffer->height, 0); + + /* Switch back to the original surface and context. */ + p_eglMakeCurrent(egl_display, prev_draw, prev_read, prev_context); + + return GL_TRUE; +} + +static BOOL wayland_wglReleaseTexImageARB(struct wgl_pbuffer *pbuffer, int buffer) +{ + TRACE("(%p, %d)\n", pbuffer, buffer); + + if (!pbuffer->texture_format) + { + RtlSetLastWin32Error(ERROR_INVALID_HANDLE); + return GL_FALSE; + } + return GL_TRUE; +} + +static BOOL wayland_wglSetPbufferAttribARB(struct wgl_pbuffer *pbuffer, const int *attribs) +{ + if (!pbuffer->texture_format) + { + RtlSetLastWin32Error(ERROR_INVALID_HANDLE); + return GL_FALSE; + } + return GL_TRUE; +} + static void describe_pixel_format(EGLConfig config, struct wgl_pixel_format *fmt) { EGLint value, surface_type; @@ -1070,6 +1264,11 @@ static BOOL init_opengl_funcs(void) opengl_funcs.ext.p_wglQueryPbufferARB = wayland_wglQueryPbufferARB; opengl_funcs.ext.p_wglReleasePbufferDCARB = wayland_wglReleasePbufferDCARB;
+ register_extension("WGL_ARB_render_texture"); + opengl_funcs.ext.p_wglBindTexImageARB = wayland_wglBindTexImageARB; + opengl_funcs.ext.p_wglReleaseTexImageARB = wayland_wglReleaseTexImageARB; + opengl_funcs.ext.p_wglSetPbufferAttribARB = wayland_wglSetPbufferAttribARB; + return TRUE; }
@@ -1170,6 +1369,8 @@ static void init_opengl(void) LOAD_FUNCPTR_EGL(eglDestroyContext); LOAD_FUNCPTR_EGL(eglDestroySurface); LOAD_FUNCPTR_EGL(eglGetConfigAttrib); + LOAD_FUNCPTR_EGL(eglGetCurrentContext); + LOAD_FUNCPTR_EGL(eglGetCurrentSurface); LOAD_FUNCPTR_EGL(eglGetError); LOAD_FUNCPTR_EGL(eglGetPlatformDisplay); LOAD_FUNCPTR_EGL(eglInitialize);
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Since we are emulating pbuffer support using normal EGL window surfaces this commit marks all formats as pbuffer capable. Additionally since pbuffers are usually requested as single-buffered, we advertise single-buffered, pbuffer-only variations of all the formats. --- dlls/winewayland.drv/opengl.c | 63 ++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 15 deletions(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 8694c558ada..5e1f040ac0a 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -92,6 +92,7 @@ struct wayland_gl_drawable EGLSurface surface; LONG resized; int swap_interval; + BOOL double_buffered; };
struct wgl_context @@ -176,6 +177,18 @@ static void wayland_gl_drawable_release(struct wayland_gl_drawable *gl) free(gl); }
+static inline BOOL is_onscreen_format(int format) +{ + return format > 0 && format <= num_egl_configs; +} + +static inline EGLConfig egl_config_for_format(int format) +{ + assert(format > 0 && format <= 2 * num_egl_configs); + if (format <= num_egl_configs) return egl_configs[format - 1]; + return egl_configs[format - num_egl_configs - 1]; +} + static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, int format) { struct wayland_gl_drawable *gl; @@ -223,7 +236,7 @@ static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, int for goto err; }
- gl->surface = p_eglCreateWindowSurface(egl_display, egl_configs[format - 1], + gl->surface = p_eglCreateWindowSurface(egl_display, egl_config_for_format(format), gl->wl_egl_window, NULL); if (!gl->surface) { @@ -231,6 +244,8 @@ static struct wayland_gl_drawable *wayland_gl_drawable_create(HWND hwnd, int for goto err; }
+ gl->double_buffered = is_onscreen_format(format); + TRACE("hwnd=%p egl_surface=%p\n", gl->hwnd, gl->surface);
return gl; @@ -739,7 +754,9 @@ static BOOL wayland_wglSwapBuffers(HDC hdc)
if (ctx) wgl_context_refresh(ctx); wayland_gl_drawable_sync_surface_state(gl); - p_eglSwapBuffers(egl_display, gl->surface); + /* Although all the EGL surfaces we create are double-buffered, we want to + * use some as single-buffered, so avoid swapping those. */ + if (gl->double_buffered) p_eglSwapBuffers(egl_display, gl->surface); wayland_gl_drawable_sync_size(gl);
wayland_gl_drawable_release(gl); @@ -786,6 +803,13 @@ static struct wgl_pbuffer *wayland_wglCreatePbufferARB(HDC hdc, int format,
TRACE("(%p, %d, %d, %d, %p)\n", hdc, format, width, height, attribs);
+ if (format <= 0 || format > 2 * num_egl_configs) + { + RtlSetLastWin32Error(ERROR_INVALID_PIXEL_FORMAT); + ERR("Invalid format %d\n", format); + return NULL; + } + /* Use an unmapped wayland surface as our offscreen "pbuffer" surface. */ if (!(pbuffer = calloc(1, sizeof(*pbuffer))) || !(pbuffer->gl = wayland_gl_drawable_create(0, format))) @@ -1044,7 +1068,7 @@ static BOOL wayland_wglSetPbufferAttribARB(struct wgl_pbuffer *pbuffer, const in return GL_TRUE; }
-static void describe_pixel_format(EGLConfig config, struct wgl_pixel_format *fmt) +static void describe_pixel_format(EGLConfig config, struct wgl_pixel_format *fmt, BOOL pbuffer_single) { EGLint value, surface_type; PIXELFORMATDESCRIPTOR *pfd = &fmt->pfd; @@ -1055,8 +1079,12 @@ static void describe_pixel_format(EGLConfig config, struct wgl_pixel_format *fmt memset(fmt, 0, sizeof(*fmt)); pfd->nSize = sizeof(*pfd); pfd->nVersion = 1; - pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SUPPORT_COMPOSITION; - if (surface_type & EGL_WINDOW_BIT) pfd->dwFlags |= PFD_DRAW_TO_WINDOW; + pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION; + if (!pbuffer_single) + { + pfd->dwFlags |= PFD_DOUBLEBUFFER; + if (surface_type & EGL_WINDOW_BIT) pfd->dwFlags |= PFD_DRAW_TO_WINDOW; + } pfd->iPixelType = PFD_TYPE_RGBA; pfd->iLayerType = PFD_MAIN_PLANE;
@@ -1123,10 +1151,11 @@ static void describe_pixel_format(EGLConfig config, struct wgl_pixel_format *fmt } else fmt->pixel_type = -1;
- fmt->draw_to_pbuffer = !!(surface_type & EGL_PBUFFER_BIT); - SET_ATTRIB_ARB(max_pbuffer_pixels, EGL_MAX_PBUFFER_PIXELS); - SET_ATTRIB_ARB(max_pbuffer_width, EGL_MAX_PBUFFER_WIDTH); - SET_ATTRIB_ARB(max_pbuffer_height, EGL_MAX_PBUFFER_HEIGHT); + fmt->draw_to_pbuffer = TRUE; + /* Use some arbitrary but reasonable limits (4096 is also Mesa's default) */ + fmt->max_pbuffer_width = 4096; + fmt->max_pbuffer_height = 4096; + fmt->max_pbuffer_pixels = fmt->max_pbuffer_width * fmt->max_pbuffer_height;
if (p_eglGetConfigAttrib(egl_display, config, EGL_TRANSPARENT_RED_VALUE, &value)) { @@ -1151,10 +1180,10 @@ static void describe_pixel_format(EGLConfig config, struct wgl_pixel_format *fmt SET_ATTRIB_ARB(sample_buffers, EGL_SAMPLE_BUFFERS); SET_ATTRIB_ARB(samples, EGL_SAMPLES);
- SET_ATTRIB_ARB(bind_to_texture_rgb, EGL_BIND_TO_TEXTURE_RGB); - SET_ATTRIB_ARB(bind_to_texture_rgba, EGL_BIND_TO_TEXTURE_RGBA); - fmt->bind_to_texture_rectangle_rgb = fmt->bind_to_texture_rgb; - fmt->bind_to_texture_rectangle_rgba = fmt->bind_to_texture_rgba; + fmt->bind_to_texture_rgb = GL_TRUE; + fmt->bind_to_texture_rgba = GL_TRUE; + fmt->bind_to_texture_rectangle_rgb = GL_TRUE; + fmt->bind_to_texture_rectangle_rgba = GL_TRUE;
/* TODO: Support SRGB surfaces and enable the attribute */ fmt->framebuffer_srgb_capable = GL_FALSE; @@ -1181,9 +1210,13 @@ static void wayland_get_pixel_formats(struct wgl_pixel_format *formats, if (formats) { for (i = 0; i < min(max_formats, num_egl_configs); ++i) - describe_pixel_format(egl_configs[i], &formats[i]); + describe_pixel_format(egl_configs[i], &formats[i], FALSE); + /* Add single-buffered pbuffer capable configs. */ + for (i = num_egl_configs; i < min(max_formats, 2 * num_egl_configs); ++i) + describe_pixel_format(egl_configs[i - num_egl_configs], &formats[i], TRUE); } - *num_formats = *num_onscreen_formats = num_egl_configs; + *num_formats = 2 * num_egl_configs; + *num_onscreen_formats = num_egl_configs; }
static BOOL has_extension(const char *list, const char *ext)
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c index 5e1f040ac0a..fd13bdbb406 100644 --- a/dlls/winewayland.drv/opengl.c +++ b/dlls/winewayland.drv/opengl.c @@ -482,7 +482,7 @@ static BOOL set_pixel_format(HDC hdc, int format, BOOL internal) WARN("not a proper window DC %p/%p\n", hdc, hwnd); return FALSE; } - if (format < 0 || format >= num_egl_configs) + if (!is_onscreen_format(format)) { WARN("Invalid format %d\n", format); return FALSE;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147803
Your paranoid android.
=== debian11b (64 bit WoW report) ===
dinput: joystick8.c:5762: Test failed: input 1: WaitForSingleObject returned 0x102 joystick8.c:5763: Test failed: input 1: got 0 WM_INPUT messages joystick8.c:5766: Test failed: input 1: got dwType 0 joystick8.c:5767: Test failed: input 1: got header.dwSize 0 joystick8.c:5769: Test failed: input 1: got hDevice 0000000000000000 joystick8.c:5771: Test failed: input 1: got dwSizeHid 0 joystick8.c:5772: Test failed: input 1: got dwCount 0