From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 61 +++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 5f40f28de3d..dac856e992e 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1086,6 +1086,16 @@ static GLXContext create_glxcontext(Display *display, struct wgl_context *contex return ctx; }
+static BOOL needs_offscreen_rendering( HWND hwnd, BOOL known_child ) +{ + if (NtUserGetDpiForWindow( hwnd ) != get_win_monitor_dpi( hwnd )) return TRUE; + + if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && + NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) + return FALSE; /* childless top-level window */ + + return TRUE; +}
/*********************************************************************** * create_gl_drawable @@ -1114,8 +1124,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct glx_pixel gl->hwnd = hwnd; gl->mutable_pf = mutable_pf;
- if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && - NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) /* childless top-level window */ + if (!needs_offscreen_rendering( hwnd, known_child )) { gl->type = DC_GL_WINDOW; gl->colormap = XCreateColormap( gdi_display, get_dummy_parent(), visual->visual, @@ -1842,15 +1851,49 @@ static Drawable get_dc_drawable( HDC hdc, RECT *rect ) return escape.drawable; }
+static HRGN get_dc_monitor_region( HWND hwnd, HDC hdc ) +{ + RGNDATA *data; + UINT i, size; + HRGN region; + POINT pt; + + if (!(region = NtGdiCreateRectRgn( 0, 0, 0, 0 ))) return 0; + if (NtGdiGetRandomRgn( hdc, region, SYSRGN ) <= 0) goto failed; + if (!(size = NtGdiGetRegionData( region, 0, NULL ))) goto failed; + if (!(data = malloc( size ))) goto failed; + NtGdiGetRegionData( region, size, data ); + NtGdiDeleteObjectApp( region ); + + NtGdiGetDCPoint( hdc, NtGdiGetDCOrg, &pt ); + NtUserLogicalToPerMonitorDPIPhysicalPoint( hwnd, &pt ); + for (i = 0; i < data->rdh.nCount; i++) + { + RECT *rect = (RECT *)data->Buffer + i; + NtUserLogicalToPerMonitorDPIPhysicalPoint( hwnd, (POINT *)&rect->left ); + NtUserLogicalToPerMonitorDPIPhysicalPoint( hwnd, (POINT *)&rect->right ); + OffsetRect( rect, -pt.x, -pt.y ); + } + + region = NtGdiExtCreateRegion( NULL, size, data ); + free( data ); + return region; + +failed: + NtGdiDeleteObjectApp( region ); + return 0; +} + static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOOL flush ) { static const WCHAR displayW[] = {'D','I','S','P','L','A','Y'}; - static HDC hdc_src; + static HDC hdc_src, hdc_dst;
UNICODE_STRING device_str = RTL_CONSTANT_STRING(displayW); HWND toplevel = NtUserGetAncestor( hwnd, GA_ROOT ); RECT rect_dst, rect_src, rect; - Drawable drawable; + Drawable window, drawable; + HRGN region;
if (!gl) return; switch (gl->type) @@ -1860,6 +1903,8 @@ static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOO default: drawable = 0; break; } if (!drawable) return; + window = get_dc_drawable( hdc, &rect ); + region = get_dc_monitor_region( hwnd, hdc );
if (flush) XFlush( gdi_display );
@@ -1872,15 +1917,21 @@ static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOO pthread_mutex_lock( &context_mutex );
if (!hdc_src && !(hdc_src = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ))) goto done; + if (!hdc_dst && !(hdc_dst = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ))) goto done;
if (get_dc_drawable( hdc_src, &rect ) != drawable || !EqualRect( &rect, &rect_src )) set_dc_drawable( hdc_src, drawable, &rect_src, IncludeInferiors ); + if (get_dc_drawable( hdc_dst, &rect ) != window || !EqualRect( &rect, &rect_dst )) + set_dc_drawable( hdc_dst, window, &rect_dst, ClipByChildren ); + if (region) NtGdiExtSelectClipRgn( hdc_dst, region, RGN_COPY );
- NtGdiStretchBlt( hdc, 0, 0, rect_dst.right - rect_dst.left, rect_dst.bottom - rect_dst.top, + NtGdiStretchBlt( hdc_dst, 0, 0, rect_dst.right - rect_dst.left, rect_dst.bottom - rect_dst.top, hdc_src, 0, 0, rect_src.right, rect_src.bottom, SRCCOPY, 0 );
done: pthread_mutex_unlock( &context_mutex ); + + if (region) NtGdiDeleteObjectApp( region ); }
static void wglFinish(void)