From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/make_opengl | 3 + dlls/opengl32/tests/opengl.c | 25 ++++---- dlls/opengl32/unix_private.h | 3 + dlls/opengl32/unix_thunks.c | 9 +-- dlls/opengl32/unix_wgl.c | 21 +++++++ dlls/win32u/opengl.c | 108 ++++++++++++++++++++++++++++++----- 6 files changed, 137 insertions(+), 32 deletions(-)
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index bc8eb05aaa5..d43ee4abf3e 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -200,11 +200,14 @@ my %manual_unix_thunks = "glDebugMessageCallback" => 1, "glDebugMessageCallbackAMD" => 1, "glDebugMessageCallbackARB" => 1, + "glDrawPixels" => 1, "glFinish" => 1, "glFlush" => 1, "glGetIntegerv" => 1, "glGetString" => 1, "glGetStringi" => 1, + "glReadPixels" => 1, + "glViewport" => 1, "wglGetProcAddress" => 1, "wglSwapBuffers" => 1, ); diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 10d4e9a491f..901745098f1 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -1597,7 +1597,7 @@ static void test_bitmap_rendering( BOOL use_dib ) ok( EqualRect( (RECT *)viewport, &expect_rect ), "got viewport %s\n", wine_dbgstr_rect( (RECT *)viewport ) );
glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( (pixel & 0xffffff) == 0xcdcdcd, "got %#x\n", pixel ); + ok( (pixel & 0xffffff) == 0xcdcdcd, "got %#x\n", pixel );
glClearColor( (float)0x22 / 0xff, (float)0x33 / 0xff, (float)0x44 / 0xff, (float)0x11 / 0xff ); glClear( GL_COLOR_BUFFER_BIT ); @@ -1642,7 +1642,7 @@ static void test_bitmap_rendering( BOOL use_dib ) ok( (pixel & 0xffffff) == 0x443322, "got %#x\n", pixel ); if (pixels == buffer) read_bitmap_pixels( hdc, bmp, pixels, 4, 4, bpp ); if (pixels2 == buffer2) read_bitmap_pixels( hdc, bmp2, pixels2, 12, 12, bpp ); - todo_wine ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); + ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); ok( (pixels2[0] & 0xffffff) == 0xdcdcdc, "got %#x\n", pixels2[0] );
@@ -1657,13 +1657,13 @@ static void test_bitmap_rendering( BOOL use_dib ) /* pixels are read from the selected bitmap */
glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( (pixel & 0xffffff) == 0xdcdcdc, "got %#x\n", pixel ); + ok( (pixel & 0xffffff) == 0xdcdcdc, "got %#x\n", pixel );
if (use_dib) { memset( buffer2, 0xa5, sizeof(buffer2) ); glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( (pixel & 0xffffff) == 0xdcdcdc, "got %#x\n", pixel ); + ok( (pixel & 0xffffff) == 0xdcdcdc, "got %#x\n", pixel ); memset( buffer2, 0xdc, sizeof(buffer2) ); }
@@ -1676,7 +1676,7 @@ static void test_bitmap_rendering( BOOL use_dib )
if (pixels == buffer) read_bitmap_pixels( hdc, bmp, pixels, 4, 4, bpp ); if (pixels2 == buffer2) read_bitmap_pixels( hdc, bmp2, pixels2, 12, 12, bpp ); - todo_wine ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); + ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); ok( (pixels2[0] & 0xffffff) == 0xdcdcdc, "got %#x\n", pixels2[0] );
glFinish(); @@ -1685,8 +1685,8 @@ static void test_bitmap_rendering( BOOL use_dib ) ok( (pixel & 0xffffff) == 0x223344, "got %#x\n", pixel ); if (pixels == buffer) read_bitmap_pixels( hdc, bmp, pixels, 4, 4, bpp ); if (pixels2 == buffer2) read_bitmap_pixels( hdc, bmp2, pixels2, 12, 12, bpp ); - todo_wine ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); - todo_wine ok( (pixels2[0] & 0xffffff) == 0x443322, "got %#x\n", pixels2[0] ); + ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); + ok( (pixels2[0] & 0xffffff) == 0x443322, "got %#x\n", pixels2[0] );
ret = wglMakeCurrent( NULL, NULL ); @@ -1704,7 +1704,7 @@ static void test_bitmap_rendering( BOOL use_dib )
if (pixels == buffer) read_bitmap_pixels( hdc, bmp, pixels, 4, 4, bpp ); if (pixels2 == buffer2) read_bitmap_pixels( hdc, bmp2, pixels2, 12, 12, bpp ); - todo_wine ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); + ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); ok( (pixels2[0] & 0xffffff) == 0x445566, "got %#x\n", pixels2[0] );
@@ -1726,7 +1726,7 @@ static void test_bitmap_rendering( BOOL use_dib )
if (pixels == buffer) read_bitmap_pixels( hdc, bmp, pixels, 4, 4, bpp ); if (pixels2 == buffer2) read_bitmap_pixels( hdc, bmp2, pixels2, 12, 12, bpp ); - todo_wine ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); + ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); if (use_dib) todo_wine ok( (pixels2[0] & 0xffffff) == 0x03148, "got %#x\n", pixels2[0] ); else ok( (pixels2[0] & 0xffffff) == 0x665544, "got %#x\n", pixels2[0] );
@@ -1743,7 +1743,7 @@ static void test_bitmap_rendering( BOOL use_dib )
if (pixels == buffer) read_bitmap_pixels( hdc, bmp, pixels, 4, 4, bpp ); if (pixels2 == buffer2) read_bitmap_pixels( hdc, bmp2, pixels2, 12, 12, bpp ); - todo_wine ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); + ok( (pixels[0] & 0xffffff) == 0x223344, "got %#x\n", pixels[0] ); ok( (pixels2[0] & 0xffffff) == 0x667788, "got %#x\n", pixels2[0] );
@@ -1789,6 +1789,7 @@ static void test_d3dkmt_rendering(void) NTSTATUS status; HGLRC hglrc;
+ memset( (void *)pixels, 0xcd, sizeof(*pixels) * 4 * 4 ); create.pMemory = pixels; create.Format = D3DDDIFMT_A8R8G8B8; create.Width = 4; @@ -1858,7 +1859,7 @@ static void test_d3dkmt_rendering(void)
memset( (void *)pixels, 0xcd, sizeof(*pixels) * 4 * 4 ); glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); - todo_wine ok( (pixel & 0xffffff) == 0xcdcdcd, "got %#x\n", pixel ); + ok( (pixel & 0xffffff) == 0xcdcdcd, "got %#x\n", pixel );
glClearColor( (float)0x44 / 0xff, (float)0x33 / 0xff, (float)0x22 / 0xff, (float)0x11 / 0xff ); glClear( GL_COLOR_BUFFER_BIT ); @@ -1881,7 +1882,7 @@ static void test_d3dkmt_rendering(void) ok( (pixels[0] & 0xffffff) == 0x556677, "got %#x\n", pixels[0] ); glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); ok( (pixel & 0xffffff) == 0x223344, "got %#x\n", pixel ); - todo_wine ok( (pixels[0] & 0xffffff) == 0x443322, "got %#x\n", pixels[0] ); + ok( (pixels[0] & 0xffffff) == 0x443322, "got %#x\n", pixels[0] );
glReadPixels( 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel ); ok( (pixel & 0xffffff) == 0x223344, "got %#x\n", pixel ); diff --git a/dlls/opengl32/unix_private.h b/dlls/opengl32/unix_private.h index 30b90545105..c15bda2c99a 100644 --- a/dlls/opengl32/unix_private.h +++ b/dlls/opengl32/unix_private.h @@ -82,6 +82,9 @@ extern PROC wrap_wglGetProcAddress( TEB *teb, LPCSTR lpszProc ); extern BOOL wrap_wglMakeCurrent( TEB *teb, HDC hDc, HGLRC newContext ); extern void wrap_glFinish( TEB *teb ); extern void wrap_glFlush( TEB *teb ); +extern void wrap_glDrawPixels( TEB *teb, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels ); +extern void wrap_glReadPixels( TEB *teb, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels ); +extern void wrap_glViewport( TEB *teb, GLint x, GLint y, GLsizei width, GLsizei height ); extern BOOL wrap_wglSwapBuffers( TEB *teb, HDC hdc ); extern BOOL wrap_wglShareLists( TEB *teb, HGLRC hrcSrvShare, HGLRC hrcSrvSource ); extern void wrap_glGetIntegerv( TEB *teb, GLenum pname, GLint *data ); diff --git a/dlls/opengl32/unix_thunks.c b/dlls/opengl32/unix_thunks.c index ae97dfbec47..91aaadbe9c0 100644 --- a/dlls/opengl32/unix_thunks.c +++ b/dlls/opengl32/unix_thunks.c @@ -718,8 +718,7 @@ static NTSTATUS gl_glDrawElements( void *args ) static NTSTATUS gl_glDrawPixels( void *args ) { struct glDrawPixels_params *params = args; - const struct opengl_funcs *funcs = params->teb->glTable; - funcs->p_glDrawPixels( params->width, params->height, params->format, params->type, params->pixels ); + wrap_glDrawPixels( params->teb, params->width, params->height, params->format, params->type, params->pixels ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -2203,8 +2202,7 @@ static NTSTATUS gl_glReadBuffer( void *args ) static NTSTATUS gl_glReadPixels( void *args ) { struct glReadPixels_params *params = args; - const struct opengl_funcs *funcs = params->teb->glTable; - funcs->p_glReadPixels( params->x, params->y, params->width, params->height, params->format, params->type, params->pixels ); + wrap_glReadPixels( params->teb, params->x, params->y, params->width, params->height, params->format, params->type, params->pixels ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -3085,8 +3083,7 @@ static NTSTATUS gl_glVertexPointer( void *args ) static NTSTATUS gl_glViewport( void *args ) { struct glViewport_params *params = args; - const struct opengl_funcs *funcs = params->teb->glTable; - funcs->p_glViewport( params->x, params->y, params->width, params->height ); + wrap_glViewport( params->teb, params->x, params->y, params->width, params->height ); set_context_attribute( params->teb, GL_VIEWPORT, ¶ms->x, 2 * sizeof(GLint) + 2 * sizeof(GLsizei) ); return STATUS_SUCCESS; } diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index f009c74e209..d203f4781a7 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -1010,6 +1010,27 @@ void wrap_glFlush( TEB *teb ) flush_context( teb, funcs->p_glFlush ); }
+void wrap_glDrawPixels( TEB *teb, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels ) +{ + const struct opengl_funcs *funcs = teb->glTable; + flush_context( teb, NULL ); + funcs->p_glDrawPixels( width, height, format, type, pixels ); +} + +void wrap_glReadPixels( TEB *teb, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels ) +{ + const struct opengl_funcs *funcs = teb->glTable; + flush_context( teb, NULL ); + funcs->p_glReadPixels( x, y, width, height, format, type, pixels ); +} + +void wrap_glViewport( TEB *teb, GLint x, GLint y, GLsizei width, GLsizei height ) +{ + const struct opengl_funcs *funcs = teb->glTable; + flush_context( teb, NULL ); + funcs->p_glViewport( x, y, width, height ); +} + BOOL wrap_wglSwapBuffers( TEB *teb, HDC hdc ) { const struct opengl_funcs *funcs = get_dc_funcs( hdc ); diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 13c9d230925..310beaa8922 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -45,6 +45,9 @@ struct wgl_context const struct opengl_funcs *funcs; void *driver_private; int pixel_format; + + HBITMAP memory_bitmap; + struct wgl_pbuffer *memory_pbuffer; };
struct wgl_pbuffer @@ -935,6 +938,76 @@ static int win32u_wglGetPixelFormat( HDC hdc ) return format > 0 ? format : 0; }
+static struct wgl_pbuffer *create_memory_pbuffer( HDC hdc, int format ) +{ + const struct opengl_funcs *funcs = &display_funcs; + struct wgl_pbuffer *pbuffer = NULL; + BITMAPOBJ *bmp; + dib_info dib; + BOOL ret; + DC *dc; + + if (!(dc = get_dc_ptr( hdc ))) return NULL; + if (get_gdi_object_type( hdc ) != NTGDI_OBJ_MEMDC) ret = FALSE; + else if (!(bmp = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP ))) ret = FALSE; + else + { + ret = init_dib_info_from_bitmapobj( &dib, bmp ); + GDI_ReleaseObj( dc->hBitmap ); + } + release_dc_ptr( dc ); + + if (ret) + { + int width = dib.rect.right - dib.rect.left, height = dib.rect.bottom - dib.rect.top; + pbuffer = funcs->p_wglCreatePbufferARB( hdc, format, width, height, NULL ); + } + + if (pbuffer) TRACE( "Created pbuffer %p for memory DC %p\n", pbuffer, hdc ); + else WARN( "Failed to create pbuffer for memory DC %p\n", hdc ); + return pbuffer; +} + +static BOOL flush_memory_pbuffer( struct wgl_context *context, HDC hdc, BOOL write, void (*flush)(void) ) +{ + const struct opengl_funcs *funcs = &display_funcs; + BITMAPOBJ *bmp; + DC *dc; + + if (flush) flush(); + + if (!(dc = get_dc_ptr( hdc ))) return TRUE; + if ((bmp = GDI_GetObjPtr( dc->hBitmap, NTGDI_OBJ_BITMAP ))) + { + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *info = (BITMAPINFO *)buffer; + struct bitblt_coords src = {0}; + struct gdi_image_bits bits; + + if (dc->hBitmap != context->memory_bitmap) write = TRUE; + context->memory_bitmap = dc->hBitmap; + + if (!get_image_from_bitmap( bmp, info, &bits, &src )) + { + int width = info->bmiHeader.biWidth, height = abs( info->bmiHeader.biHeight ); + if (write) funcs->p_glDrawPixels( width, height, GL_BGRA, GL_UNSIGNED_BYTE, bits.ptr ); + else funcs->p_glReadPixels( 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, bits.ptr ); + } + GDI_ReleaseObj( dc->hBitmap ); + } + release_dc_ptr( dc ); + + return TRUE; +} + +static void destroy_memory_pbuffer( struct wgl_context *context, HDC hdc ) +{ + const struct opengl_funcs *funcs = context->funcs; + flush_memory_pbuffer( context, hdc, FALSE, funcs->p_glFinish ); + funcs->p_wglDestroyPbufferARB( context->memory_pbuffer ); + context->memory_pbuffer = NULL; +} + static BOOL set_dc_pixel_format( HDC hdc, int new_format, BOOL internal ) { const struct opengl_funcs *funcs; @@ -1038,7 +1111,7 @@ static struct wgl_context *context_create( HDC hdc, struct wgl_context *shared, context->funcs = funcs; context->pixel_format = format;
- if (!driver_funcs->p_context_create( hdc, format, shared_private, attribs, &context->driver_private )) + if (!context->driver_funcs->p_context_create( hdc, format, shared_private, attribs, &context->driver_private )) { free( context ); return NULL; @@ -1079,14 +1152,18 @@ static BOOL win32u_wglDeleteContext( struct wgl_context *context )
static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct wgl_context *context ) { + HDC hdc = draw_hdc, prev_draw = NtCurrentTeb()->glReserved1[0]; + struct wgl_context *prev_context = NtCurrentTeb()->glContext; const struct opengl_driver_funcs *funcs; int format;
TRACE( "draw_hdc %p, read_hdc %p, context %p\n", draw_hdc, read_hdc, context );
+ if (prev_context && prev_context->memory_pbuffer) destroy_memory_pbuffer( prev_context, prev_draw ); + if (!context) { - if (!(context = NtCurrentTeb()->glContext)) return TRUE; + if (!(context = prev_context)) return TRUE; funcs = context->driver_funcs; if (!funcs->p_context_make_current( NULL, NULL, NULL )) return FALSE; NtCurrentTeb()->glContext = NULL; @@ -1106,9 +1183,16 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct return FALSE; }
+ if ((context->memory_pbuffer = create_memory_pbuffer( draw_hdc, context->pixel_format ))) + { + if (read_hdc != draw_hdc) ERR( "read != draw not supported\n" ); + draw_hdc = read_hdc = context->memory_pbuffer->hdc; + } + funcs = context->driver_funcs; if (!funcs->p_context_make_current( draw_hdc, read_hdc, context->driver_private )) return FALSE; NtCurrentTeb()->glContext = context; + if (context->memory_pbuffer) flush_memory_pbuffer( context, hdc, TRUE, NULL ); return TRUE; }
@@ -1147,7 +1231,7 @@ static struct wgl_pbuffer *win32u_wglCreatePbufferARB( HDC hdc, int format, int return NULL; } NtGdiSetPixelFormat( pbuffer->hdc, format ); - pbuffer->driver_funcs = funcs == &display_funcs ? display_driver_funcs : memory_driver_funcs; + pbuffer->driver_funcs = display_driver_funcs; pbuffer->funcs = funcs; pbuffer->width = width; pbuffer->height = height; @@ -1553,13 +1637,14 @@ static BOOL win32u_wgl_context_flush( struct wgl_context *context, void (*flush) else 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 ); + + if (context->memory_pbuffer) return flush_memory_pbuffer( context, draw_hdc, FALSE, flush ); return context->driver_funcs->p_context_flush( context->driver_private, hwnd, draw_hdc, interval, flush ); }
static BOOL win32u_wglSwapBuffers( HDC hdc ) { struct wgl_context *context = NtCurrentTeb()->glContext; - const struct opengl_driver_funcs *driver_funcs; const struct opengl_funcs *funcs; int interval; HWND hwnd; @@ -1569,12 +1654,13 @@ static BOOL win32u_wglSwapBuffers( HDC hdc ) RtlSetLastWin32Error( ERROR_DC_NOT_FOUND ); return FALSE; } - driver_funcs = funcs == &display_funcs ? display_driver_funcs : memory_driver_funcs; + context->driver_funcs = funcs == &display_funcs ? display_driver_funcs : memory_driver_funcs;
if (!(hwnd = NtUserWindowFromDC( hdc ))) interval = 0; else interval = get_window_swap_interval( hwnd );
- return driver_funcs->p_swap_buffers( context ? context->driver_private : NULL, hwnd, hdc, interval ); + if (context->memory_pbuffer) return flush_memory_pbuffer( context, hdc, FALSE, funcs->p_glFlush ); + return context->driver_funcs->p_swap_buffers( context ? context->driver_private : NULL, hwnd, hdc, interval ); }
static BOOL win32u_wglSwapIntervalEXT( int interval ) @@ -1635,7 +1721,7 @@ static void init_opengl_funcs( struct opengl_funcs *funcs, const struct opengl_d #undef USE_GL_FUNC }
-static void memory_funcs_init(void) +static inline void memory_funcs_init(void) { if (!osmesa_get_wgl_driver( &memory_driver_funcs )) WARN( "Failed to initialize OSMesa functions\n" );
@@ -1749,18 +1835,12 @@ static const struct opengl_funcs *get_dc_funcs( HDC hdc, const struct opengl_fun release_dc_ptr( dc );
if (is_disabled) return NULL; - if (is_display) + if (is_display || is_memdc) { static pthread_once_t display_init_once = PTHREAD_ONCE_INIT; pthread_once( &display_init_once, display_funcs_init ); return &display_funcs; } - if (is_memdc) - { - static pthread_once_t memory_init_once = PTHREAD_ONCE_INIT; - pthread_once( &memory_init_once, memory_funcs_init ); - return &memory_funcs; - } return NULL; }