Looks like I broke it in many ways after all... though surprisingly haven't seen that many reports. This is the first half of https://gitlab.winehq.org/wine/wine/-/merge_requests/8958.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/tests/opengl.c | 188 ++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 3 deletions(-)
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index ea88a50c49f..6f73e36732c 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -36,6 +36,28 @@
#define MAX_FORMATS 256
+static const char *debugstr_ok( const char *cond ) +{ + int c, n = 0; + /* skip possible casts */ + while ((c = *cond++)) + { + if (c == '(') n++; + if (!n) break; + if (c == ')') n--; + } + if (!strchr( cond - 1, '(' )) return wine_dbg_sprintf( "got %s", cond - 1 ); + return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond - 1, "( " ), cond - 1 ); +} + +#define ok_ex( r, op, e, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v op (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) +#define ok_ret( e, r ) ok_ex( r, ==, e, UINT, "%#x" ) + static NTSTATUS (WINAPI *pD3DKMTCreateDCFromMemory)( D3DKMT_CREATEDCFROMMEMORY *desc ); static NTSTATUS (WINAPI *pD3DKMTDestroyDCFromMemory)( const D3DKMT_DESTROYDCFROMMEMORY *desc );
@@ -2504,6 +2526,59 @@ static void test_framebuffer(void) DestroyWindow(window); }
+static DWORD CALLBACK test_window_dc_thread( void *arg ) +{ + PIXELFORMATDESCRIPTOR pfd = + { + .nSize = sizeof(pfd), + .nVersion = 1, + .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + .iPixelType = PFD_TYPE_RGBA, + .cColorBits = 24, + .cDepthBits = 32, + }; + HWND hwnd = arg; + UINT ret, pixel; + HGLRC ctx; + int format; + HDC hdc; + + hdc = GetWindowDC( hwnd ); + ok( hdc != NULL, "got %p\n", hdc ); + format = ChoosePixelFormat( hdc, &pfd ); + ok( format != 0, "got %d\n", format ); + ret = SetPixelFormat( hdc, format, &pfd ); + ok( ret != 0, "got %u\n", ret ); + + ctx = wglCreateContext( hdc ); + ok( ctx != NULL, "got %p\n", ctx ); + todo_wine ok_ret( TRUE, wglMakeCurrent( hdc, ctx ) ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + glReadBuffer( GL_BACK ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + glClearColor( 0.0, 1.0, 0.0, 1.0 ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + glClear( GL_COLOR_BUFFER_BIT ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglDeleteContext( ctx ) ); + + ReleaseDC( hwnd, hdc ); + return 0; +} + static void test_window_dc(void) { PIXELFORMATDESCRIPTOR pf_desc = @@ -2528,9 +2603,11 @@ static void test_window_dc(void) int pixel_format; HWND window; RECT vp, r; - HGLRC ctx; + HGLRC ctx, ctx1; BOOL ret; - HDC dc; + HDC dc, dc1; + UINT pixel; + HANDLE thread;
window = CreateWindowA("static", "opengl32_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0); @@ -2569,7 +2646,112 @@ static void test_window_dc(void) ret = wglDeleteContext(ctx); ok(ret, "Failed to delete GL context, last error %#lx.\n", GetLastError());
- ReleaseDC(window, dc); + ReleaseDC( window, dc ); + + + dc = GetWindowDC( window ); + ctx = wglCreateContext( dc ); + ok( ctx != NULL, "got %p\n", ctx ); + todo_wine ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); + glReadBuffer( GL_BACK ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + glClearColor( 1.0, 0.0, 0.0, 1.0 ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + glClear( GL_COLOR_BUFFER_BIT ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + ReleaseDC( window, dc ); + + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + glFlush(); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + + dc = GetWindowDC( window ); + ok( dc != NULL, "got %p\n", dc ); + todo_wine ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff0000ff, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + thread = CreateThread( NULL, 0, test_window_dc_thread, window, 0, NULL ); + ok( thread != NULL, "got %p\n", thread ); + ret = WaitForSingleObject( thread, 5000 ); + ok( ret == 0, "got %#x\n", ret ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + + dc1 = GetWindowDC( window ); + ok( dc1 != NULL, "got %p\n", dc1 ); + todo_wine ok_ret( TRUE, wglMakeCurrent( dc1, ctx ) ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + + ctx1 = wglCreateContext( dc1 ); + ok( ctx1 != NULL, "got %p\n", ctx1 ); + todo_wine ok_ret( TRUE, wglMakeCurrent( dc1, ctx1 ) ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + glReadBuffer( GL_BACK ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglDeleteContext( ctx1 ) ); + ReleaseDC( window, dc1 ); + + ok_ret( TRUE, wglDeleteContext( ctx ) ); + ReleaseDC( window, dc ); + + + dc = GetWindowDC( window ); + ok( dc != NULL, "got %p\n", dc ); + ctx = wglCreateContext( dc ); + ok( ctx != NULL, "got %p\n", ctx ); + todo_wine ok_ret( TRUE, wglMakeCurrent( dc, ctx ) ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + glReadBuffer( GL_BACK ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + pixel = 0xdeadbeef; + glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); + todo_wine ok( pixel == 0xff00ff00, "got %#x\n", pixel ); + todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + + todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); + ok_ret( TRUE, wglDeleteContext( ctx ) ); + todo_wine ok_ret( TRUE, SwapBuffers( dc ) ); + ReleaseDC( window, dc ); + DestroyWindow(window); }
From: Rémi Bernon rbernon@codeweavers.com
--- include/wine/opengl_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 984861f106d..a468e5e0a40 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -176,7 +176,7 @@ struct opengl_drawable static inline const char *debugstr_opengl_drawable( struct opengl_drawable *drawable ) { if (!drawable) return "(null)"; - return wine_dbg_sprintf( "%s/%p (format %u)", debugstr_client_surface( drawable->surface ), drawable, drawable->format ); + return wine_dbg_sprintf( "%s/%p (format %u)", debugstr_client_surface( drawable->client ), drawable, drawable->format ); }
W32KAPI void *opengl_drawable_create( UINT size, const struct opengl_drawable_funcs *funcs, int format, struct client_surface *client );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 1a5067c62e1..ba89eb36d23 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1165,12 +1165,13 @@ static struct opengl_drawable *get_dc_opengl_drawable( HDC hdc ) return drawable; }
-static BOOL create_memory_pbuffer( HDC hdc, int format ) +static BOOL create_memory_pbuffer( HDC hdc ) { const struct opengl_funcs *funcs = &display_funcs; dib_info dib = {.rect = {0, 0, 1, 1}}; BOOL ret = TRUE; BITMAPOBJ *bmp; + int format = 0; DC *dc;
if (!(dc = get_dc_ptr( hdc ))) return FALSE; @@ -1178,12 +1179,13 @@ static BOOL create_memory_pbuffer( HDC hdc, int format ) else if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC) ret = FALSE; else if ((bmp = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP ))) { + if (!(format = dc->pixel_format)) ret = FALSE; init_dib_info_from_bitmapobj( &dib, bmp ); GDI_ReleaseObj( dc->hBitmap ); } release_dc_ptr( dc );
- if (ret && format) + if (ret) { int width = dib.rect.right - dib.rect.left, height = dib.rect.bottom - dib.rect.top; struct wgl_pbuffer *pbuffer; @@ -1332,10 +1334,9 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H { struct wgl_context *previous = NtCurrentTeb()->glContext; struct opengl_drawable *new_draw, *new_read; - BOOL ret = FALSE, flush; + BOOL ret = FALSE; HWND hwnd;
- flush = create_memory_pbuffer( draw_hdc, context->format ); new_draw = get_dc_opengl_drawable( draw_hdc );
/* get the last used window drawable when reading */ @@ -1374,7 +1375,6 @@ static BOOL context_sync_drawables( struct wgl_context *context, HDC draw_hdc, H opengl_drawable_flush( new_draw, new_draw->interval, 0 ); /* update the current window drawable to the last used draw surface */ if ((hwnd = NtUserWindowFromDC( draw_hdc ))) set_window_opengl_drawable( hwnd, new_draw ); - if (flush) flush_memory_dc( context, draw_hdc, TRUE, NULL ); } else if (previous) { @@ -1410,6 +1410,7 @@ static void pop_internal_context( struct wgl_context *context ) static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct wgl_context *context ) { struct wgl_context *prev_context = NtCurrentTeb()->glContext; + BOOL created; int format;
TRACE( "draw_hdc %p, read_hdc %p, context %p\n", draw_hdc, read_hdc, context ); @@ -1436,8 +1437,11 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct return FALSE; }
+ created = create_memory_pbuffer( draw_hdc ); if (!context_sync_drawables( context, draw_hdc, read_hdc )) return FALSE; NtCurrentTeb()->glContext = context; + if (created) flush_memory_dc( context, draw_hdc, TRUE, NULL ); + return TRUE; }
@@ -1896,6 +1900,20 @@ static BOOL win32u_wgl_context_reset( struct wgl_context *context, HDC hdc, stru return TRUE; }
+static BOOL flush_memory_pbuffer( void (*flush)(void) ) +{ + HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; + struct wgl_context *context = NtCurrentTeb()->glContext; + BOOL created; + + TRACE( "context %p, draw_hdc %p, read_hdc %p, flush %p\n", context, draw_hdc, read_hdc, flush ); + + created = create_memory_pbuffer( draw_hdc ); + if (context) context_sync_drawables( context, draw_hdc, read_hdc ); + if (created) flush_memory_dc( context, draw_hdc, TRUE, NULL ); + return flush_memory_dc( context, draw_hdc, FALSE, flush ); +} + static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush)(void) ) { HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; @@ -1905,13 +1923,13 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush) int interval; HWND hwnd;
- if (!(hwnd = NtUserWindowFromDC( draw_hdc ))) interval = 0; - else interval = get_window_swap_interval( hwnd ); + if (!(hwnd = NtUserWindowFromDC( draw_hdc ))) return flush_memory_pbuffer( flush ); + + interval = get_window_swap_interval( hwnd );
TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d, flush %p\n", context, hwnd, draw_hdc, interval, flush );
context_sync_drawables( context, draw_hdc, read_hdc ); - if (flush_memory_dc( context, draw_hdc, FALSE, flush )) return TRUE;
if (flush) flush(); if (flush == funcs->p_glFinish) flags |= GL_FLUSH_FINISHED; @@ -1933,11 +1951,13 @@ static BOOL win32u_wglSwapBuffers( HDC hdc ) HWND hwnd; BOOL ret;
- if (!(hwnd = NtUserWindowFromDC( hdc ))) interval = 0; - else interval = get_window_swap_interval( hwnd ); + if (!(hwnd = NtUserWindowFromDC( hdc ))) return flush_memory_pbuffer( funcs->p_glFlush ); + + interval = get_window_swap_interval( hwnd ); + + TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d\n", context, hwnd, draw_hdc, interval );
context_sync_drawables( context, draw_hdc, read_hdc ); - if (flush_memory_dc( context, hdc, FALSE, funcs->p_glFlush )) return TRUE;
if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE; opengl_drawable_flush( draw, interval, 0 );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/opengl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index ba89eb36d23..092202348a1 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1918,7 +1918,6 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush) { HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1]; const struct opengl_funcs *funcs = &display_funcs; - struct opengl_drawable *draw; UINT flags = 0; int interval; HWND hwnd; @@ -1933,10 +1932,7 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush)
if (flush) flush(); if (flush == funcs->p_glFinish) flags |= GL_FLUSH_FINISHED; - - if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE; - opengl_drawable_flush( draw, interval, flags ); - opengl_drawable_release( draw ); + opengl_drawable_flush( context->draw, interval, flags );
return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/tests/opengl.c | 2 +- dlls/win32u/opengl.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 6f73e36732c..f15f456bdfa 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -2749,7 +2749,7 @@ static void test_window_dc(void)
todo_wine ok_ret( TRUE, wglMakeCurrent( NULL, NULL ) ); ok_ret( TRUE, wglDeleteContext( ctx ) ); - todo_wine ok_ret( TRUE, SwapBuffers( dc ) ); + ok_ret( TRUE, SwapBuffers( dc ) ); ReleaseDC( window, dc );
DestroyWindow(window); diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 092202348a1..3bbf0d4cb93 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1953,12 +1953,13 @@ static BOOL win32u_wglSwapBuffers( HDC hdc )
TRACE( "context %p, hwnd %p, draw_hdc %p, interval %d\n", context, hwnd, draw_hdc, interval );
- context_sync_drawables( context, draw_hdc, read_hdc ); + if (context) context_sync_drawables( context, draw_hdc, read_hdc ); + + if (context) opengl_drawable_add_ref( (draw = context->draw) ); + else if (!(draw = get_window_opengl_drawable( hwnd ))) return FALSE;
- if (!(draw = get_dc_opengl_drawable( draw_hdc ))) return FALSE; opengl_drawable_flush( draw, interval, 0 ); - if (!draw->client) ret = FALSE; /* pbuffer, nothing to do */ - else ret = draw->funcs->swap( draw ); + ret = draw->funcs->swap( draw ); opengl_drawable_release( draw );
return ret;