From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/opengl32/make_opengl | 35 +++++-- dlls/opengl32/private.h | 2 + dlls/opengl32/tests/opengl.c | 14 +++ dlls/opengl32/thunks.c | 51 +++------- dlls/opengl32/unix_private.h | 5 + dlls/opengl32/unix_thunks.c | 54 +++++------ dlls/opengl32/unix_thunks.h | 9 +- dlls/opengl32/unix_wgl.c | 177 ++++++++--------------------------- dlls/opengl32/wgl.c | 153 +++++++++++++++++++++++++++++- include/wine/opengl_driver.h | 6 ++ 10 files changed, 281 insertions(+), 225 deletions(-) diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index d71a715e008..be1c67a9bfa 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -165,8 +165,12 @@ my %manual_win_functions = ); my %manual_win_thunks = ( + "glCreateSyncFromCLeventARB" => 1, + "glDeleteSync" => 1, + "glFenceSync" => 1, "glGetString" => 1, "glGetStringi" => 1, + "glImportSyncEXT" => 1, "wglChoosePixelFormatARB" => 1, "wglCreateContext" => 1, "wglCreateContextAttribsARB" => 1, @@ -188,12 +192,14 @@ my %manual_win_thunks = my %manual_unix_thunks = ( "glClear" => 1, + "glCreateSyncFromCLeventARB" => 1, "glDebugMessageCallback" => 1, "glDebugMessageCallbackAMD" => 1, "glDebugMessageCallbackARB" => 1, "glDrawBuffer" => 1, "glDrawBuffers" => 1, "glDrawPixels" => 1, + "glFenceSync" => 1, "glFinish" => 1, "glFlush" => 1, "glFramebufferDrawBufferEXT" => 1, @@ -209,6 +215,7 @@ my %manual_unix_thunks = "glGetString" => 1, "glGetStringi" => 1, "glGetUnsignedBytevEXT" => 1, + "glImportSyncEXT" => 1, "glNamedFramebufferDrawBuffer" => 1, "glNamedFramebufferDrawBuffers" => 1, "glNamedFramebufferReadBuffer" => 1, @@ -289,10 +296,7 @@ my %map_default_fbo_thunks = my %manual_wow64_wrappers = ( "glBufferStorage" => 0, - "glClientWaitSync" => 0, "glDeleteBuffers" => 0, - "glDeleteSync" => 0, - "glFenceSync" => 0, "glFlushMappedBufferRange" => 0, "glFlushMappedNamedBufferRange" => 0, "glFlushMappedNamedBufferRangeEXT" => 0, @@ -300,8 +304,6 @@ my %manual_wow64_wrappers = "glGetBufferPointervARB" => 0, "glGetNamedBufferPointerv" => 0, "glGetNamedBufferPointervEXT" => 0, - "glGetSynciv" => 0, - "glIsSync" => 0, "glMapBuffer" => 0, "glMapBufferARB" => 0, "glMapBufferRange" => 0, @@ -315,7 +317,6 @@ my %manual_wow64_wrappers = "glUnmapBufferARB" => 0, "glUnmapNamedBuffer" => 0, "glUnmapNamedBufferEXT" => 0, - "glWaitSync" => 0, ); my %wow64_invalidate_buffer = ( @@ -516,6 +517,10 @@ sub generate_unix_thunk($$$$) { $call_args .= " (" . $arg_type . ")ULongToPtr(params->$pname),"; } + elsif ($arg_type =~ /GLsync/) + { + $call_args .= " get_unix_sync( ULongToPtr(params->$pname) ),"; + } else { $call_args .= " ULongToPtr(params->$pname),"; @@ -523,7 +528,7 @@ sub generate_unix_thunk($$$$) $need_lock = 1 if $arg_type =~ /GLsync/; } } - $call_args .= " UlongToHandle( params->ret )," if $func_ret =~ /HPBUFFERARB|HGLRC/; + $call_args .= " UlongToHandle( params->ret )," if $func_ret =~ /HPBUFFERARB|HGLRC|GLsync/; if (!is_void_func($func)) { my $ret_type = get_arg_type( $func->[0] ); @@ -538,7 +543,7 @@ sub generate_unix_thunk($$$$) elsif ($ptype eq "PTR32") { $ret_expr .= "(UINT_PTR)"; - $need_manual_thunk = 1 if $func_ret !~ /HDC|HPBUFFERARB|HGLRC/; + $need_manual_thunk = 1 if $func_ret !~ /HDC|HPBUFFERARB|HGLRC|GLsync/; } } $ret .= " } *params = args;\n"; @@ -567,9 +572,16 @@ sub generate_unix_thunk($$$$) { my $ptype = get_arg_type( $arg ); my $pname = get_arg_name( $arg ); - $call_args .= " params->$pname,"; + if ($ptype =~ /GLsync/) + { + $call_args .= " get_unix_sync( params->$pname ),"; + } + else + { + $call_args .= " params->$pname,"; + } } - $call_args .= " params->ret," if $func_ret =~ /HPBUFFERARB|HGLRC/; + $call_args .= " params->ret," if $func_ret =~ /HPBUFFERARB|HGLRC|GLsync/; $ret .= " struct $name\_params *params = args;\n"; } $ret .= $vars; @@ -663,6 +675,7 @@ sub generate_wrapper_declaration($$$) } $ret .= " HPBUFFERARB handle," if $ret_type =~ /HPBUFFERARB/; $ret .= " HGLRC handle," if $ret_type =~ /HGLRC/; + $ret .= " GLsync handle," if $ret_type =~ /GLsync/; $ret =~ s/,$/ /; $ret .= ");\n"; return $ret; @@ -673,6 +686,7 @@ sub get_handle_function($) my $ptype = shift; return "get_pbuffer_from_handle" if $ptype =~ /HPBUFFERARB/; return "get_context_from_handle" if $ptype =~ /HGLRC/; + return "get_sync_from_handle" if $ptype =~ /GLsync/; return 0; } @@ -696,6 +710,7 @@ sub generate_win_thunk($$) if (my $get_handle = get_handle_function( $ptype )) { my $retval = is_void_func($func) ? "return;" : "return 0;"; + $retval = "{ set_gl_error( GL_INVALID_VALUE ); $retval }" if $ptype =~ /GLsync/ && $name !~ /glIsSync/; $checks .= " if (!$get_handle( $pname, &args.$pname )) $retval\n"; } else diff --git a/dlls/opengl32/private.h b/dlls/opengl32/private.h index 5ee9a0fce2d..42298ac9ccc 100644 --- a/dlls/opengl32/private.h +++ b/dlls/opengl32/private.h @@ -34,5 +34,7 @@ extern const void *extension_procs[]; extern int WINAPI wglDescribePixelFormat( HDC hdc, int ipfd, UINT cjpfd, PIXELFORMATDESCRIPTOR *ppfd ); extern BOOL get_pbuffer_from_handle( HPBUFFERARB handle, HPBUFFERARB *obj ); extern BOOL get_context_from_handle( HGLRC handle, HGLRC *obj ); +extern BOOL get_sync_from_handle( GLsync handle, GLsync *obj ); +extern void set_gl_error( GLenum error ); #endif /* __WINE_OPENGL32_PRIVATE_H */ diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 656872ec800..5882d75f200 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -112,6 +112,7 @@ static PFN_glFlushMappedBufferRange pglFlushMappedBufferRange; static PFN_glFlushMappedNamedBufferRange pglFlushMappedNamedBufferRange; static PFN_glGenBuffers pglGenBuffers; static PFN_glIsSync pglIsSync; +static PFN_glFenceSync pglFenceSync; static PFN_glMapBuffer pglMapBuffer; static PFN_glMapBufferRange pglMapBufferRange; static PFN_glMapNamedBuffer pglMapNamedBuffer; @@ -198,6 +199,7 @@ static void init_functions(void) GET_PROC(glFlushMappedNamedBufferRange) GET_PROC(glGenBuffers) GET_PROC(glIsSync) + GET_PROC(glFenceSync) GET_PROC(glMapBuffer) GET_PROC(glMapBufferRange) GET_PROC(glMapNamedBuffer) @@ -3500,6 +3502,7 @@ static void test_gl_error( HDC hdc ) HGLRC rc, old_rc; int i; BOOL ret; + GLsync sync; if (!pglDeleteSync) { @@ -3536,6 +3539,17 @@ static void test_gl_error( HDC hdc ) ok( !ret, "glIsSync returned %x\n", ret ); check_gl_error( GL_NO_ERROR ); + sync = pglFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); + ok( !!sync, "got %p\n", sync ); + check_gl_error( GL_NO_ERROR ); + + ret = pglIsSync( sync ); + ok( !!ret, "glIsSync returned %x\n", ret ); + check_gl_error( GL_NO_ERROR ); + + pglDeleteSync( sync ); + check_gl_error( GL_NO_ERROR ); + wglMakeCurrent( hdc, old_rc ); } diff --git a/dlls/opengl32/thunks.c b/dlls/opengl32/thunks.c index 437ae70fe9c..a9d08f300d9 100644 --- a/dlls/opengl32/thunks.c +++ b/dlls/opengl32/thunks.c @@ -4207,9 +4207,10 @@ static void WINAPI glClientWaitSemaphoreui64NVX( GLsizei fenceObjectCount, const static GLenum WINAPI glClientWaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) { - struct glClientWaitSync_params args = { .teb = NtCurrentTeb(), .sync = sync, .flags = flags, .timeout = timeout }; + struct glClientWaitSync_params args = { .teb = NtCurrentTeb(), .flags = flags, .timeout = timeout }; NTSTATUS status; TRACE( "sync %p, flags %d, timeout %s\n", sync, flags, wine_dbgstr_longlong(timeout) ); + if (!get_sync_from_handle( sync, &args.sync )) { set_gl_error( GL_INVALID_VALUE ); return 0; } if ((status = UNIX_CALL( glClientWaitSync, &args ))) WARN( "glClientWaitSync returned %#lx\n", status ); return args.ret; } @@ -5461,15 +5462,6 @@ static void WINAPI glCreateStatesNV( GLsizei n, GLuint *states ) if ((status = UNIX_CALL( glCreateStatesNV, &args ))) WARN( "glCreateStatesNV returned %#lx\n", status ); } -static GLsync WINAPI glCreateSyncFromCLeventARB( struct _cl_context *context, struct _cl_event *event, GLbitfield flags ) -{ - struct glCreateSyncFromCLeventARB_params args = { .teb = NtCurrentTeb(), .context = context, .event = event, .flags = flags }; - NTSTATUS status; - TRACE( "context %p, event %p, flags %d\n", context, event, flags ); - if ((status = UNIX_CALL( glCreateSyncFromCLeventARB, &args ))) WARN( "glCreateSyncFromCLeventARB returned %#lx\n", status ); - return args.ret; -} - static void WINAPI glCreateTextures( GLenum target, GLsizei n, GLuint *textures ) { struct glCreateTextures_params args = { .teb = NtCurrentTeb(), .target = target, .n = n, .textures = textures }; @@ -5870,14 +5862,6 @@ static void WINAPI glDeleteStatesNV( GLsizei n, const GLuint *states ) if ((status = UNIX_CALL( glDeleteStatesNV, &args ))) WARN( "glDeleteStatesNV returned %#lx\n", status ); } -static void WINAPI glDeleteSync( GLsync sync ) -{ - struct glDeleteSync_params args = { .teb = NtCurrentTeb(), .sync = sync }; - NTSTATUS status; - TRACE( "sync %p\n", sync ); - if ((status = UNIX_CALL( glDeleteSync, &args ))) WARN( "glDeleteSync returned %#lx\n", status ); -} - static void WINAPI glDeleteTexturesEXT( GLsizei n, const GLuint *textures ) { struct glDeleteTexturesEXT_params args = { .teb = NtCurrentTeb(), .n = n, .textures = textures }; @@ -6814,15 +6798,6 @@ static void WINAPI glFeedbackBufferxOES( GLsizei n, GLenum type, const GLfixed * if ((status = UNIX_CALL( glFeedbackBufferxOES, &args ))) WARN( "glFeedbackBufferxOES returned %#lx\n", status ); } -static GLsync WINAPI glFenceSync( GLenum condition, GLbitfield flags ) -{ - struct glFenceSync_params args = { .teb = NtCurrentTeb(), .condition = condition, .flags = flags }; - NTSTATUS status; - TRACE( "condition %d, flags %d\n", condition, flags ); - if ((status = UNIX_CALL( glFenceSync, &args ))) WARN( "glFenceSync returned %#lx\n", status ); - return args.ret; -} - static void WINAPI glFinalCombinerInputNV( GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage ) { struct glFinalCombinerInputNV_params args = { .teb = NtCurrentTeb(), .variable = variable, .input = input, .mapping = mapping, .componentUsage = componentUsage }; @@ -10077,9 +10052,10 @@ static GLint WINAPI glGetSubroutineUniformLocation( GLuint program, GLenum shade static void WINAPI glGetSynciv( GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values ) { - struct glGetSynciv_params args = { .teb = NtCurrentTeb(), .sync = sync, .pname = pname, .count = count, .length = length, .values = values }; + struct glGetSynciv_params args = { .teb = NtCurrentTeb(), .pname = pname, .count = count, .length = length, .values = values }; NTSTATUS status; TRACE( "sync %p, pname %d, count %d, length %p, values %p\n", sync, pname, count, length, values ); + if (!get_sync_from_handle( sync, &args.sync )) { set_gl_error( GL_INVALID_VALUE ); return; } if ((status = UNIX_CALL( glGetSynciv, &args ))) WARN( "glGetSynciv returned %#lx\n", status ); } @@ -11422,15 +11398,6 @@ static void WINAPI glImportSemaphoreWin32NameEXT( GLuint semaphore, GLenum handl if ((status = UNIX_CALL( glImportSemaphoreWin32NameEXT, &args ))) WARN( "glImportSemaphoreWin32NameEXT returned %#lx\n", status ); } -static GLsync WINAPI glImportSyncEXT( GLenum external_sync_type, GLintptr external_sync, GLbitfield flags ) -{ - struct glImportSyncEXT_params args = { .teb = NtCurrentTeb(), .external_sync_type = external_sync_type, .external_sync = external_sync, .flags = flags }; - NTSTATUS status; - TRACE( "external_sync_type %d, external_sync %Id, flags %d\n", external_sync_type, external_sync, flags ); - if ((status = UNIX_CALL( glImportSyncEXT, &args ))) WARN( "glImportSyncEXT returned %#lx\n", status ); - return args.ret; -} - static void WINAPI glIndexFormatNV( GLenum type, GLsizei stride ) { struct glIndexFormatNV_params args = { .teb = NtCurrentTeb(), .type = type, .stride = stride }; @@ -11891,9 +11858,10 @@ static GLboolean WINAPI glIsStateNV( GLuint state ) static GLboolean WINAPI glIsSync( GLsync sync ) { - struct glIsSync_params args = { .teb = NtCurrentTeb(), .sync = sync }; + struct glIsSync_params args = { .teb = NtCurrentTeb() }; NTSTATUS status; TRACE( "sync %p\n", sync ); + if (!get_sync_from_handle( sync, &args.sync )) return 0; if ((status = UNIX_CALL( glIsSync, &args ))) WARN( "glIsSync returned %#lx\n", status ); return args.ret; } @@ -24143,9 +24111,10 @@ static void WINAPI glWaitSemaphoreui64NVX( GLuint waitGpu, GLsizei fenceObjectCo static void WINAPI glWaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) { - struct glWaitSync_params args = { .teb = NtCurrentTeb(), .sync = sync, .flags = flags, .timeout = timeout }; + struct glWaitSync_params args = { .teb = NtCurrentTeb(), .flags = flags, .timeout = timeout }; NTSTATUS status; TRACE( "sync %p, flags %d, timeout %s\n", sync, flags, wine_dbgstr_longlong(timeout) ); + if (!get_sync_from_handle( sync, &args.sync )) { set_gl_error( GL_INVALID_VALUE ); return; } if ((status = UNIX_CALL( glWaitSync, &args ))) WARN( "glWaitSync returned %#lx\n", status ); } @@ -24823,7 +24792,11 @@ static BOOL WINAPI wglSwapIntervalEXT( int interval ) return args.ret; } +extern GLsync WINAPI glCreateSyncFromCLeventARB( struct _cl_context *context, struct _cl_event *event, GLbitfield flags ); +extern void WINAPI glDeleteSync( GLsync sync ); +extern GLsync WINAPI glFenceSync( GLenum condition, GLbitfield flags ); extern const GLubyte * WINAPI glGetStringi( GLenum name, GLuint index ); +extern GLsync WINAPI glImportSyncEXT( GLenum external_sync_type, GLintptr external_sync, GLbitfield flags ); extern BOOL WINAPI wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats ); extern HGLRC WINAPI wglCreateContextAttribsARB( HDC hDC, HGLRC hShareContext, const int *attribList ); extern HPBUFFERARB WINAPI wglCreatePbufferARB( HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList ); diff --git a/dlls/opengl32/unix_private.h b/dlls/opengl32/unix_private.h index e1076fe7831..d5ec8cee7c4 100644 --- a/dlls/opengl32/unix_private.h +++ b/dlls/opengl32/unix_private.h @@ -69,6 +69,11 @@ static inline const struct opengl_funcs *get_context_funcs( HGLRC client_context return client_context ? (struct opengl_funcs *)(UINT_PTR)client->unix_funcs : NULL; } +static inline GLsync get_unix_sync( GLsync sync ) +{ + return (GLsync)(UINT_PTR)sync->unix_handle; +} + #ifdef _WIN64 static inline void *copy_wow64_ptr32s( UINT_PTR address, ULONG count ) diff --git a/dlls/opengl32/unix_thunks.c b/dlls/opengl32/unix_thunks.c index 41ce0f2d5e1..07314125675 100644 --- a/dlls/opengl32/unix_thunks.c +++ b/dlls/opengl32/unix_thunks.c @@ -5240,7 +5240,7 @@ static NTSTATUS ext_glClientWaitSync( void *args ) struct glClientWaitSync_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glClientWaitSync) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->p_glClientWaitSync( params->sync, params->flags, params->timeout ); + params->ret = funcs->p_glClientWaitSync( get_unix_sync( params->sync ), params->flags, params->timeout ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -6805,7 +6805,7 @@ static NTSTATUS ext_glCreateSyncFromCLeventARB( void *args ) struct glCreateSyncFromCLeventARB_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glCreateSyncFromCLeventARB) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->p_glCreateSyncFromCLeventARB( params->context, params->event, params->flags ); + params->ret = wrap_glCreateSyncFromCLeventARB( params->teb, params->context, params->event, params->flags, params->ret ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -7315,7 +7315,7 @@ static NTSTATUS ext_glDeleteSync( void *args ) struct glDeleteSync_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glDeleteSync) return STATUS_NOT_IMPLEMENTED; - funcs->p_glDeleteSync( params->sync ); + funcs->p_glDeleteSync( get_unix_sync( params->sync ) ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -8495,7 +8495,7 @@ static NTSTATUS ext_glFenceSync( void *args ) struct glFenceSync_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glFenceSync) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->p_glFenceSync( params->condition, params->flags ); + params->ret = wrap_glFenceSync( params->teb, params->condition, params->flags, params->ret ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -12299,7 +12299,7 @@ static NTSTATUS ext_glGetSynciv( void *args ) struct glGetSynciv_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glGetSynciv) return STATUS_NOT_IMPLEMENTED; - funcs->p_glGetSynciv( params->sync, params->pname, params->count, params->length, params->values ); + funcs->p_glGetSynciv( get_unix_sync( params->sync ), params->pname, params->count, params->length, params->values ); return STATUS_SUCCESS; } @@ -13824,7 +13824,7 @@ static NTSTATUS ext_glImportSyncEXT( void *args ) struct glImportSyncEXT_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glImportSyncEXT) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->p_glImportSyncEXT( params->external_sync_type, params->external_sync, params->flags ); + params->ret = wrap_glImportSyncEXT( params->teb, params->external_sync_type, params->external_sync, params->flags, params->ret ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -14332,7 +14332,7 @@ static NTSTATUS ext_glIsSync( void *args ) struct glIsSync_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glIsSync) return STATUS_NOT_IMPLEMENTED; - params->ret = funcs->p_glIsSync( params->sync ); + params->ret = funcs->p_glIsSync( get_unix_sync( params->sync ) ); return STATUS_SUCCESS; } @@ -29588,7 +29588,7 @@ static NTSTATUS ext_glWaitSync( void *args ) struct glWaitSync_params *params = args; const struct opengl_funcs *funcs = params->teb->glTable; if (!funcs->p_glWaitSync) return STATUS_NOT_IMPLEMENTED; - funcs->p_glWaitSync( params->sync, params->flags, params->timeout ); + funcs->p_glWaitSync( get_unix_sync( params->sync ), params->flags, params->timeout ); set_context_attribute( params->teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -42408,9 +42408,7 @@ static NTSTATUS wow64_ext_glClientWaitSync( void *args ) TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; if (!funcs->p_glClientWaitSync) return STATUS_NOT_IMPLEMENTED; - pthread_mutex_lock( &wgl_lock ); - params->ret = wow64_glClientWaitSync( teb, ULongToPtr(params->sync), params->flags, params->timeout ); - pthread_mutex_unlock( &wgl_lock ); + params->ret = funcs->p_glClientWaitSync( get_unix_sync( ULongToPtr(params->sync) ), params->flags, params->timeout ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -45411,8 +45409,12 @@ static NTSTATUS wow64_ext_glCreateSyncFromCLeventARB( void *args ) GLbitfield flags; PTR32 ret; } *params = args; - FIXME( "params %p stub!\n", params ); - return STATUS_NOT_IMPLEMENTED; + TEB *teb = get_teb64( params->teb ); + const struct opengl_funcs *funcs = teb->glTable; + if (!funcs->p_glCreateSyncFromCLeventARB) return STATUS_NOT_IMPLEMENTED; + params->ret = (UINT_PTR)wrap_glCreateSyncFromCLeventARB( teb, ULongToPtr(params->context), ULongToPtr(params->event), params->flags, UlongToHandle( params->ret ) ); + set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); + return STATUS_SUCCESS; } static NTSTATUS wow64_ext_glCreateTextures( void *args ) @@ -46264,9 +46266,7 @@ static NTSTATUS wow64_ext_glDeleteSync( void *args ) TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; if (!funcs->p_glDeleteSync) return STATUS_NOT_IMPLEMENTED; - pthread_mutex_lock( &wgl_lock ); - wow64_glDeleteSync( teb, ULongToPtr(params->sync) ); - pthread_mutex_unlock( &wgl_lock ); + funcs->p_glDeleteSync( get_unix_sync( ULongToPtr(params->sync) ) ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -48232,7 +48232,7 @@ static NTSTATUS wow64_ext_glFenceSync( void *args ) TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; if (!funcs->p_glFenceSync) return STATUS_NOT_IMPLEMENTED; - params->ret = (UINT_PTR)wow64_glFenceSync( teb, params->condition, params->flags ); + params->ret = (UINT_PTR)wrap_glFenceSync( teb, params->condition, params->flags, UlongToHandle( params->ret ) ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -55016,9 +55016,7 @@ static NTSTATUS wow64_ext_glGetSynciv( void *args ) TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; if (!funcs->p_glGetSynciv) return STATUS_NOT_IMPLEMENTED; - pthread_mutex_lock( &wgl_lock ); - wow64_glGetSynciv( teb, ULongToPtr(params->sync), params->pname, params->count, ULongToPtr(params->length), ULongToPtr(params->values) ); - pthread_mutex_unlock( &wgl_lock ); + funcs->p_glGetSynciv( get_unix_sync( ULongToPtr(params->sync) ), params->pname, params->count, ULongToPtr(params->length), ULongToPtr(params->values) ); return STATUS_SUCCESS; } @@ -57774,8 +57772,12 @@ static NTSTATUS wow64_ext_glImportSyncEXT( void *args ) GLbitfield flags; PTR32 ret; } *params = args; - FIXME( "params %p stub!\n", params ); - return STATUS_NOT_IMPLEMENTED; + TEB *teb = get_teb64( params->teb ); + const struct opengl_funcs *funcs = teb->glTable; + if (!funcs->p_glImportSyncEXT) return STATUS_NOT_IMPLEMENTED; + params->ret = (UINT_PTR)wrap_glImportSyncEXT( teb, params->external_sync_type, (GLintptr)ULongToPtr(params->external_sync), params->flags, UlongToHandle( params->ret ) ); + set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); + return STATUS_SUCCESS; } static NTSTATUS wow64_ext_glIndexFormatNV( void *args ) @@ -58633,9 +58635,7 @@ static NTSTATUS wow64_ext_glIsSync( void *args ) TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; if (!funcs->p_glIsSync) return STATUS_NOT_IMPLEMENTED; - pthread_mutex_lock( &wgl_lock ); - params->ret = wow64_glIsSync( teb, ULongToPtr(params->sync) ); - pthread_mutex_unlock( &wgl_lock ); + params->ret = funcs->p_glIsSync( get_unix_sync( ULongToPtr(params->sync) ) ); return STATUS_SUCCESS; } @@ -85342,9 +85342,7 @@ static NTSTATUS wow64_ext_glWaitSync( void *args ) TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; if (!funcs->p_glWaitSync) return STATUS_NOT_IMPLEMENTED; - pthread_mutex_lock( &wgl_lock ); - wow64_glWaitSync( teb, ULongToPtr(params->sync), params->flags, params->timeout ); - pthread_mutex_unlock( &wgl_lock ); + funcs->p_glWaitSync( get_unix_sync( ULongToPtr(params->sync) ), params->flags, params->timeout ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } diff --git a/dlls/opengl32/unix_thunks.h b/dlls/opengl32/unix_thunks.h index e23c9e9e5bd..2c0824e0268 100644 --- a/dlls/opengl32/unix_thunks.h +++ b/dlls/opengl32/unix_thunks.h @@ -23,10 +23,12 @@ extern const GLubyte *wrap_glGetString( TEB *teb, GLenum name ); extern void wrap_glReadBuffer( TEB *teb, GLenum src ); 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 GLsync wrap_glCreateSyncFromCLeventARB( TEB *teb, struct _cl_context *context, struct _cl_event *event, GLbitfield flags, GLsync handle ); extern void wrap_glDebugMessageCallback( TEB *teb, GLDEBUGPROC callback, const void *userParam ); extern void wrap_glDebugMessageCallbackAMD( TEB *teb, GLDEBUGPROCAMD callback, void *userParam ); extern void wrap_glDebugMessageCallbackARB( TEB *teb, GLDEBUGPROCARB callback, const void *userParam ); extern void wrap_glDrawBuffers( TEB *teb, GLsizei n, const GLenum *bufs ); +extern GLsync wrap_glFenceSync( TEB *teb, GLenum condition, GLbitfield flags, GLsync handle ); extern void wrap_glFramebufferDrawBufferEXT( TEB *teb, GLuint framebuffer, GLenum mode ); extern void wrap_glFramebufferDrawBuffersEXT( TEB *teb, GLuint framebuffer, GLsizei n, const GLenum *bufs ); extern void wrap_glFramebufferReadBufferEXT( TEB *teb, GLuint framebuffer, GLenum mode ); @@ -34,6 +36,7 @@ extern void wrap_glGetFramebufferParameterivEXT( TEB *teb, GLuint framebuffer, G extern void wrap_glGetInteger64v( TEB *teb, GLenum pname, GLint64 *data ); extern const GLubyte *wrap_glGetStringi( TEB *teb, GLenum name, GLuint index ); extern void wrap_glGetUnsignedBytevEXT( TEB *teb, GLenum pname, GLubyte *data ); +extern GLsync wrap_glImportSyncEXT( TEB *teb, GLenum external_sync_type, GLintptr external_sync, GLbitfield flags, GLsync handle ); extern void wrap_glNamedFramebufferDrawBuffer( TEB *teb, GLuint framebuffer, GLenum buf ); extern void wrap_glNamedFramebufferDrawBuffers( TEB *teb, GLuint framebuffer, GLsizei n, const GLenum *bufs ); extern void wrap_glNamedFramebufferReadBuffer( TEB *teb, GLuint framebuffer, GLenum src ); @@ -42,10 +45,7 @@ extern BOOL wrap_wglMakeContextCurrentARB( TEB *teb, HDC hDrawDC, HDC hReadDC, H #ifdef _WIN64 extern void wow64_glBufferStorage( TEB *teb, GLenum target, GLsizeiptr size, const void *data, GLbitfield flags ); -extern GLenum wow64_glClientWaitSync( TEB *teb, GLsync sync, GLbitfield flags, GLuint64 timeout ); extern void wow64_glDeleteBuffers( TEB *teb, GLsizei n, const GLuint *buffers ); -extern void wow64_glDeleteSync( TEB *teb, GLsync sync ); -extern GLsync wow64_glFenceSync( TEB *teb, GLenum condition, GLbitfield flags ); extern void wow64_glFlushMappedBufferRange( TEB *teb, GLenum target, GLintptr offset, GLsizeiptr length ); extern void wow64_glFlushMappedNamedBufferRange( TEB *teb, GLuint buffer, GLintptr offset, GLsizeiptr length ); extern void wow64_glFlushMappedNamedBufferRangeEXT( TEB *teb, GLuint buffer, GLintptr offset, GLsizeiptr length ); @@ -53,8 +53,6 @@ extern void wow64_glGetBufferPointerv( TEB *teb, GLenum target, GLenum pname, PT extern void wow64_glGetBufferPointervARB( TEB *teb, GLenum target, GLenum pname, PTR32 *params ); extern void wow64_glGetNamedBufferPointerv( TEB *teb, GLuint buffer, GLenum pname, PTR32 *params ); extern void wow64_glGetNamedBufferPointervEXT( TEB *teb, GLuint buffer, GLenum pname, PTR32 *params ); -extern void wow64_glGetSynciv( TEB *teb, GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values ); -extern GLboolean wow64_glIsSync( TEB *teb, GLsync sync ); extern void *wow64_glMapBuffer( TEB *teb, GLenum target, GLenum access ); extern void *wow64_glMapBufferARB( TEB *teb, GLenum target, GLenum access ); extern void *wow64_glMapBufferRange( TEB *teb, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ); @@ -68,5 +66,4 @@ extern GLboolean wow64_glUnmapBuffer( TEB *teb, GLenum target ); extern GLboolean wow64_glUnmapBufferARB( TEB *teb, GLenum target ); extern GLboolean wow64_glUnmapNamedBuffer( TEB *teb, GLuint buffer ); extern GLboolean wow64_glUnmapNamedBufferEXT( TEB *teb, GLuint buffer ); -extern void wow64_glWaitSync( TEB *teb, GLsync sync, GLbitfield flags, GLuint64 timeout ); #endif diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index c061450b140..09b1bbf063b 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -56,14 +56,6 @@ static BOOL is_wow64(void) static UINT64 call_gl_debug_message_callback; pthread_mutex_t wgl_lock = PTHREAD_MUTEX_INITIALIZER; -/* handle management */ - -enum wgl_handle_type -{ - HANDLE_GLSYNC = 2 << 12, - HANDLE_TYPE_MASK = 15 << 12, -}; - /* context state management */ struct pixel_mode_state @@ -1976,6 +1968,45 @@ GLenum wrap_glGetError( TEB *teb ) return wrapped ? wrapped : error; } +GLsync wrap_glCreateSyncFromCLeventARB( TEB *teb, struct _cl_context *context, struct _cl_event *event, GLbitfield flags, GLsync client_sync ) +{ + const struct opengl_funcs *funcs = teb->glTable; + GLsync sync; + + FIXME( "stub!\n" ); + + if (!(sync = funcs->p_glCreateSyncFromCLeventARB( context, event, flags ))) return NULL; + client_sync->unix_handle = (UINT_PTR)sync; + + return client_sync; +} + +GLsync wrap_glFenceSync( TEB *teb, GLenum condition, GLbitfield flags, GLsync client_sync ) +{ + const struct opengl_funcs *funcs = teb->glTable; + GLsync sync; + + TRACE( "condition %#x, flags %#x, client_sync %p\n", condition, flags, client_sync ); + + if (!(sync = funcs->p_glFenceSync( condition, flags ))) return NULL; + client_sync->unix_handle = (UINT_PTR)sync; + + return client_sync; +} + +GLsync wrap_glImportSyncEXT( TEB *teb, GLenum external_sync_type, GLintptr external_sync, GLbitfield flags, GLsync client_sync ) +{ + const struct opengl_funcs *funcs = teb->glTable; + GLsync sync; + + FIXME( "stub!\n" ); + + if (!(sync = funcs->p_glImportSyncEXT( external_sync_type, external_sync, flags ))) return NULL; + client_sync->unix_handle = (UINT_PTR)sync; + + return client_sync; +} + NTSTATUS process_attach( void *args ) { struct process_attach_params *params = args; @@ -2074,136 +2105,6 @@ NTSTATUS return_wow64_string( const void *str, PTR32 *wow64_str ) return STATUS_BUFFER_TOO_SMALL; } -struct wgl_handle -{ - UINT handle; - const struct opengl_funcs *funcs; - union - { - GLsync sync; /* for HANDLE_GLSYNC */ - struct wgl_handle *next; /* for free handles */ - void *data; - } u; -}; - -#define MAX_WGL_HANDLES 1024 -static struct wgl_handle wgl_handles[MAX_WGL_HANDLES]; -static struct wgl_handle *next_free; -static unsigned int handle_count; - -static HANDLE next_handle( struct wgl_handle *ptr, enum wgl_handle_type type ) -{ - WORD generation = HIWORD( ptr->handle ) + 1; - if (!generation) generation++; - ptr->handle = MAKELONG( ptr - wgl_handles, generation ) | type; - return ULongToHandle( ptr->handle ); -} - -static HANDLE alloc_handle( enum wgl_handle_type type, const struct opengl_funcs *funcs, void *user_ptr ) -{ - HANDLE handle = 0; - struct wgl_handle *ptr = NULL; - - if ((ptr = next_free)) - next_free = next_free->u.next; - else if (handle_count < MAX_WGL_HANDLES) - ptr = &wgl_handles[handle_count++]; - - if (ptr) - { - ptr->funcs = funcs; - ptr->u.data = user_ptr; - handle = next_handle( ptr, type ); - } - else RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY ); - return handle; -} - -static void free_handle_ptr( struct wgl_handle *ptr ) -{ - ptr->handle |= 0xffff; - ptr->u.next = next_free; - ptr->funcs = NULL; - next_free = ptr; -} - -static struct wgl_handle *get_handle_ptr( HANDLE handle ) -{ - unsigned int index = LOWORD( handle ) & ~HANDLE_TYPE_MASK; - - if (index < handle_count && ULongToHandle(wgl_handles[index].handle) == handle) - return &wgl_handles[index]; - - RtlSetLastWin32Error( ERROR_INVALID_HANDLE ); - return NULL; -} - -static struct wgl_handle *get_sync_ptr( TEB *teb, GLsync sync ) -{ - struct wgl_handle *handle = get_handle_ptr( sync ); - if (!handle) set_gl_error( teb, GL_INVALID_VALUE ); - return handle; -} - -GLenum wow64_glClientWaitSync( TEB *teb, GLsync sync, GLbitfield flags, GLuint64 timeout ) -{ - const struct opengl_funcs *funcs = teb->glTable; - struct wgl_handle *handle; - - if (!(handle = get_sync_ptr( teb, sync ))) return GL_INVALID_VALUE; - return funcs->p_glClientWaitSync( handle->u.sync, flags, timeout ); -} - -void wow64_glDeleteSync( TEB *teb, GLsync sync ) -{ - const struct opengl_funcs *funcs = teb->glTable; - struct wgl_handle *handle; - - if ((handle = get_sync_ptr( teb, sync ))) - { - funcs->p_glDeleteSync( handle->u.sync ); - free_handle_ptr( handle ); - } -} - -GLsync wow64_glFenceSync( TEB *teb, GLenum condition, GLbitfield flags ) -{ - const struct opengl_funcs *funcs = teb->glTable; - GLsync sync, handle; - - if (!(sync = funcs->p_glFenceSync( condition, flags ))) return NULL; - - pthread_mutex_lock( &wgl_lock ); - if (!(handle = alloc_handle( HANDLE_GLSYNC, NULL, sync ))) funcs->p_glDeleteSync( sync ); - pthread_mutex_unlock( &wgl_lock ); - return handle; -} - -void wow64_glGetSynciv( TEB *teb, GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values ) -{ - const struct opengl_funcs *funcs = teb->glTable; - struct wgl_handle *handle; - - if ((handle = get_sync_ptr( teb, sync ))) funcs->p_glGetSynciv( handle->u.sync, pname, count, length, values ); -} - -GLboolean wow64_glIsSync( TEB *teb, GLsync sync ) -{ - const struct opengl_funcs *funcs = teb->glTable; - struct wgl_handle *handle; - - if (!(handle = get_handle_ptr( sync ))) return FALSE; - return funcs->p_glIsSync( handle->u.sync ); -} - -void wow64_glWaitSync( TEB *teb, GLsync sync, GLbitfield flags, GLuint64 timeout ) -{ - const struct opengl_funcs *funcs = teb->glTable; - struct wgl_handle *handle; - - if ((handle = get_sync_ptr( teb, sync ))) funcs->p_glWaitSync( handle->u.sync, flags, timeout ); -} - static GLint get_buffer_param( TEB *teb, GLenum target, GLenum param ) { const struct opengl_funcs *funcs = teb->glTable; diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index de39feb3405..9999bbdae2f 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -238,6 +238,17 @@ BOOL WINAPI wglDestroyPbufferARB( HPBUFFERARB handle ) return args.ret; } +struct context +{ + struct opengl_client_context base; + struct handle_table syncs; +}; + +static struct context *context_from_opengl_client_context( struct opengl_client_context *base ) +{ + return CONTAINING_RECORD( base, struct context, base ); +} + static struct opengl_client_context *opengl_client_context_from_handle( HGLRC handle ) { struct handle_entry *ptr; @@ -245,16 +256,21 @@ static struct opengl_client_context *opengl_client_context_from_handle( HGLRC ha return ptr->context; } +static struct context *context_from_handle( HGLRC handle ) +{ + return context_from_opengl_client_context( opengl_client_context_from_handle( handle ) ); +} + BOOL get_context_from_handle( HGLRC handle, HGLRC *obj ) { - struct opengl_client_context *context = opengl_client_context_from_handle( handle ); - *obj = context ? &context->obj : NULL; + struct context *context = context_from_handle( handle ); + *obj = context ? &context->base.obj : NULL; return context || !handle; } static struct handle_entry *alloc_client_context(void) { - struct opengl_client_context *context; + struct context *context; struct handle_entry *ptr; if (!(context = calloc( 1, sizeof(*context) ))) return NULL; @@ -269,11 +285,18 @@ static struct handle_entry *alloc_client_context(void) static void free_client_context( struct handle_entry *ptr ) { - struct opengl_client_context *context = ptr->context; + struct context *context = context_from_opengl_client_context( ptr->context ); free_handle( &contexts, ptr ); free( context ); } +void set_gl_error( GLenum error ) +{ + struct opengl_client_context *context; + if (!(context = opengl_client_context_from_handle( NtCurrentTeb()->glCurrentRC ))) return; + if (!context->last_error && !(context->last_error = glGetError())) context->last_error = error; +} + HGLRC WINAPI wglCreateContext( HDC hdc ) { struct wglCreateContext_params args = { .teb = NtCurrentTeb(), .hDc = hdc }; @@ -1846,6 +1869,128 @@ GLint WINAPI glDebugEntry( GLint unknown1, GLint unknown2 ) return 0; } +static GLsync sync_from_handle( GLsync handle ) +{ + struct handle_entry *ptr; + struct context *ctx; + + if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return NULL; + if (!(ptr = get_handle_ptr( &ctx->syncs, handle ))) return NULL; + return ptr->user_data; +} + +BOOL get_sync_from_handle( GLsync handle, GLsync *obj ) +{ + *obj = sync_from_handle( handle ); + return *obj || !handle; +} + +static struct handle_entry *alloc_client_sync( struct context *ctx ) +{ + struct handle_entry *ptr; + GLsync *sync; + + if (!(sync = calloc( 1, sizeof(*sync) ))) return NULL; + if (!(ptr = alloc_handle( &ctx->syncs, sync ))) + { + free( sync ); + return NULL; + } + + return ptr; +} + +static void free_client_sync( struct context *ctx, struct handle_entry *ptr ) +{ + GLsync sync = ptr->user_data; + free_handle( &ctx->syncs, ptr ); + free( sync ); +} + +GLsync WINAPI glCreateSyncFromCLeventARB( struct _cl_context *context, struct _cl_event *event, GLbitfield flags ) +{ + TEB *teb = NtCurrentTeb(); + struct glCreateSyncFromCLeventARB_params args = { .teb = teb, .context = context, .event = event, .flags = flags }; + struct handle_entry *ptr; + struct context *ctx; + NTSTATUS status; + + TRACE( "context %p, event %p, flags %d\n", context, event, flags ); + + if (!(ctx = context_from_handle( teb->glCurrentRC ))) return NULL; + if (!(ptr = alloc_client_sync( ctx ))) return NULL; + args.ret = ptr->user_data; + + if ((status = UNIX_CALL( glCreateSyncFromCLeventARB, &args ))) WARN( "glCreateSyncFromCLeventARB returned %#lx\n", status ); + assert( args.ret == ptr->user_data || !args.ret ); + + if (!status && args.ret) return UlongToHandle( ptr->handle ); + free_client_context( ptr ); + return NULL; +} + +void WINAPI glDeleteSync( GLsync sync ) +{ + TEB *teb = NtCurrentTeb(); + struct glDeleteSync_params args = { .teb = teb }; + struct handle_entry *ptr; + struct context *ctx; + NTSTATUS status; + + TRACE( "sync %p\n", sync ); + + if (!(ctx = context_from_handle( teb->glCurrentRC ))) return; + if (!(ptr = get_handle_ptr( &ctx->syncs, sync ))) return set_gl_error( GL_INVALID_VALUE ); + args.sync = ptr->user_data; + + if ((status = UNIX_CALL( glDeleteSync, &args ))) WARN( "glDeleteSync returned %#lx\n", status ); + if (!status) free_client_sync( ctx, ptr ); +} + +GLsync WINAPI glFenceSync( GLenum condition, GLbitfield flags ) +{ + TEB *teb = NtCurrentTeb(); + struct glFenceSync_params args = { .teb = teb, .condition = condition, .flags = flags }; + struct handle_entry *ptr; + struct context *ctx; + NTSTATUS status; + + TRACE( "condition %d, flags %d\n", condition, flags ); + + if (!(ctx = context_from_handle( teb->glCurrentRC ))) return NULL; + if (!(ptr = alloc_client_sync( ctx ))) return NULL; + args.ret = ptr->user_data; + + if ((status = UNIX_CALL( glFenceSync, &args ))) WARN( "glFenceSync returned %#lx\n", status ); + assert( args.ret == ptr->user_data || !args.ret ); + + if (!status && args.ret) return UlongToHandle( ptr->handle ); + free_client_context( ptr ); + return NULL; +} + +GLsync WINAPI glImportSyncEXT( GLenum external_sync_type, GLintptr external_sync, GLbitfield flags ) +{ + TEB *teb = NtCurrentTeb(); + struct glImportSyncEXT_params args = { .teb = teb, .external_sync_type = external_sync_type, .external_sync = external_sync, .flags = flags }; + struct handle_entry *ptr; + struct context *ctx; + NTSTATUS status; + + TRACE( "external_sync_type %d, external_sync %Id, flags %d\n", external_sync_type, external_sync, flags ); + + if (!(ctx = context_from_handle( teb->glCurrentRC ))) return NULL; + if (!(ptr = alloc_client_sync( ctx ))) return NULL; + args.ret = ptr->user_data; + + if ((status = UNIX_CALL( glImportSyncEXT, &args ))) WARN( "glImportSyncEXT returned %#lx\n", status ); + assert( args.ret == ptr->user_data || !args.ret ); + + if (!status && args.ret) return UlongToHandle( ptr->handle ); + free_client_context( ptr ); + return NULL; +} + const GLubyte * WINAPI glGetStringi( GLenum name, GLuint index ) { struct glGetStringi_params args = diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 366f600e002..f740303f4de 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -84,6 +84,12 @@ static inline struct opengl_client_pbuffer *opengl_client_pbuffer_from_client( H return CONTAINING_RECORD( client_pbuffer, struct opengl_client_pbuffer, obj ); } +/* client-side opengl sync */ +struct __GLsync +{ + UINT64 unix_handle; +}; + #ifdef WINE_UNIX_LIB #include "wine/gdi_driver.h" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9953