From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 72 ++++++++++++++++++++----- dlls/win32u/tests/d3dkmt.c | 63 ++++++++++++---------- dlls/wow64win/gdi.c | 3 ++ server/Makefile.in | 1 + server/d3dkmt.c | 105 +++++++++++++++++++++++++++++++++++++ server/protocol.def | 17 ++++++ 6 files changed, 219 insertions(+), 42 deletions(-) create mode 100644 server/d3dkmt.c
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 13f05f2d069..8b6d93126d0 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -33,17 +33,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
-enum d3dkmt_type -{ - D3DKMT_ADAPTER = 1, - D3DKMT_DEVICE = 2, - D3DKMT_SOURCE = 3, -}; - struct d3dkmt_object { enum d3dkmt_type type; /* object type */ D3DKMT_HANDLE local; /* object local handle */ + HANDLE handle; /* process-private handle of server object */ };
struct d3dkmt_adapter @@ -161,9 +155,29 @@ static NTSTATUS d3dkmt_object_alloc( UINT size, enum d3dkmt_type type, void **ob return STATUS_SUCCESS; }
+/* create a global D3DKMT object, either with a global handle or later shareable */ +static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *obj, BOOL shared ) +{ + NTSTATUS status; + + SERVER_START_REQ( d3dkmt_object_create ) + { + req->type = obj->type; + if (!(status = wine_server_call( req ))) + { + obj->handle = wine_server_ptr_handle( reply->handle ); + } + } + SERVER_END_REQ; + + if (status) return status; + return alloc_object_handle( obj ); +} + static void d3dkmt_object_free( struct d3dkmt_object *object ) { if (object->local) free_object_handle( object ); + if (object->handle) NtClose( object->handle ); free( object ); }
@@ -830,8 +844,23 @@ NTSTATUS WINAPI NtGdiDdDDIQueryResourceInfoFromNtHandle( D3DKMT_QUERYRESOURCEINF */ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex2( D3DKMT_CREATEKEYEDMUTEX2 *params ) { - FIXME( "params %p stub!\n", params ); - return STATUS_NOT_IMPLEMENTED; + struct d3dkmt_object *mutex; + NTSTATUS status; + + FIXME( "params %p semi-stub!\n", params ); + + if (!params) return STATUS_INVALID_PARAMETER; + + if ((status = d3dkmt_object_alloc( sizeof(*mutex), D3DKMT_MUTEX, (void **)&mutex ))) return status; + if ((status = d3dkmt_object_create( mutex, params->Flags.NtSecuritySharing ))) goto failed; + + params->hSharedHandle = 0; + params->hKeyedMutex = mutex->local; + return STATUS_SUCCESS; + +failed: + d3dkmt_object_free( mutex ); + return status; }
/****************************************************************************** @@ -839,8 +868,18 @@ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex2( D3DKMT_CREATEKEYEDMUTEX2 *params ) */ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex( D3DKMT_CREATEKEYEDMUTEX *params ) { - FIXME( "params %p stub!\n", params ); - return STATUS_NOT_IMPLEMENTED; + D3DKMT_CREATEKEYEDMUTEX2 params2 = {0}; + NTSTATUS status; + + TRACE( "params %p\n", params ); + + if (!params) return STATUS_INVALID_PARAMETER; + + params2.InitialValue = params->InitialValue; + status = NtGdiDdDDICreateKeyedMutex2( ¶ms2 ); + params->hSharedHandle = params2.hSharedHandle; + params->hKeyedMutex = params2.hKeyedMutex; + return status; }
/****************************************************************************** @@ -848,8 +887,15 @@ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex( D3DKMT_CREATEKEYEDMUTEX *params ) */ NTSTATUS WINAPI NtGdiDdDDIDestroyKeyedMutex( const D3DKMT_DESTROYKEYEDMUTEX *params ) { - FIXME( "params %p stub!\n", params ); - return STATUS_NOT_IMPLEMENTED; + struct d3dkmt_object *mutex; + + TRACE( "params %p\n", params ); + + if (!(mutex = get_d3dkmt_object( params->hKeyedMutex, D3DKMT_MUTEX ))) + return STATUS_INVALID_PARAMETER; + d3dkmt_object_free( mutex ); + + return STATUS_SUCCESS; }
/****************************************************************************** diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index 167071f5b0c..bdf39a1d83a 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -1446,11 +1446,11 @@ static void test_D3DKMTCreateKeyedMutex( void ) NTSTATUS status;
status = D3DKMTCreateKeyedMutex( NULL ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); create.hKeyedMutex = create.hSharedHandle = 0x1eadbeed; status = D3DKMTCreateKeyedMutex( &create ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine check_d3dkmt_local( create.hKeyedMutex, &next_local ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create.hKeyedMutex, &next_local ); todo_wine check_d3dkmt_global( create.hSharedHandle );
status = D3DKMTOpenKeyedMutex( &open ); @@ -1463,9 +1463,10 @@ static void test_D3DKMTCreateKeyedMutex( void ) status = D3DKMTOpenKeyedMutex( &open ); todo_wine ok_nt( STATUS_SUCCESS, status ); todo_wine check_d3dkmt_local( open.hKeyedMutex, &next_local ); + next_local = 0;
status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
if (0) { @@ -1480,11 +1481,11 @@ static void test_D3DKMTCreateKeyedMutex( void ) todo_wine ok_nt( STATUS_SUCCESS, status ); /* destroying multiple times fails */ status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
destroy.hKeyedMutex = create.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status );
/* the global D3DKMT_HANDLE is destroyed with last reference */ status = D3DKMTOpenKeyedMutex( &open ); @@ -1492,18 +1493,18 @@ static void test_D3DKMTCreateKeyedMutex( void )
status = D3DKMTCreateKeyedMutex2( NULL ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); create2.hKeyedMutex = create2.hSharedHandle = 0x1eadbeed; status = D3DKMTCreateKeyedMutex2( &create2 ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine check_d3dkmt_local( create2.hKeyedMutex, &next_local ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hKeyedMutex, &next_local ); todo_wine check_d3dkmt_global( create2.hSharedHandle ); destroy.hKeyedMutex = create2.hKeyedMutex;
create2.hKeyedMutex = create2.hSharedHandle = 0x1eadbeed; status = D3DKMTCreateKeyedMutex2( &create2 ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine check_d3dkmt_local( create2.hKeyedMutex, &next_local ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hKeyedMutex, &next_local ); todo_wine check_d3dkmt_global( create2.hSharedHandle );
status = D3DKMTOpenKeyedMutex2( &open2 ); @@ -1516,12 +1517,13 @@ static void test_D3DKMTCreateKeyedMutex( void ) status = D3DKMTOpenKeyedMutex2( &open2 ); todo_wine ok_nt( STATUS_SUCCESS, status ); todo_wine check_d3dkmt_local( open2.hKeyedMutex, &next_local ); + next_local = 0;
status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); destroy.hKeyedMutex = create2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); destroy.hKeyedMutex = open2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); todo_wine ok_nt( STATUS_SUCCESS, status ); @@ -1530,8 +1532,8 @@ static void test_D3DKMTCreateKeyedMutex( void ) /* PrivateRuntimeDataSize must be 0 if no buffer is provided */
status = D3DKMTCreateKeyedMutex2( &create2 ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine check_d3dkmt_local( create2.hKeyedMutex, &next_local ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hKeyedMutex, &next_local ); todo_wine check_d3dkmt_global( create2.hSharedHandle );
open2.hKeyedMutex = 0x1eadbeed; @@ -1543,6 +1545,7 @@ static void test_D3DKMTCreateKeyedMutex( void ) status = D3DKMTOpenKeyedMutex2( &open2 ); todo_wine ok_nt( STATUS_SUCCESS, status ); todo_wine check_d3dkmt_local( open2.hKeyedMutex, &next_local ); + next_local = 0; ok_x4( open2.PrivateRuntimeDataSize, ==, sizeof(buffer) );
destroy.hKeyedMutex = open2.hKeyedMutex; @@ -1550,14 +1553,14 @@ static void test_D3DKMTCreateKeyedMutex( void ) todo_wine ok_nt( STATUS_SUCCESS, status ); destroy.hKeyedMutex = create2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status );
create2.PrivateRuntimeDataSize = sizeof(runtime_data); create2.pPrivateRuntimeData = runtime_data; status = D3DKMTCreateKeyedMutex2( &create2 ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine check_d3dkmt_local( create2.hKeyedMutex, &next_local ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hKeyedMutex, &next_local ); todo_wine check_d3dkmt_global( create2.hSharedHandle );
open2.hKeyedMutex = 0x1eadbeed; @@ -1567,6 +1570,7 @@ static void test_D3DKMTCreateKeyedMutex( void ) status = D3DKMTOpenKeyedMutex2( &open2 ); todo_wine ok_nt( STATUS_SUCCESS, status ); todo_wine check_d3dkmt_local( open2.hKeyedMutex, &next_local ); + next_local = 0; ok_x4( open2.PrivateRuntimeDataSize, ==, 0 );
open2.PrivateRuntimeDataSize = sizeof(buffer); @@ -1581,6 +1585,7 @@ static void test_D3DKMTCreateKeyedMutex( void ) status = D3DKMTOpenKeyedMutex2( &open2 ); todo_wine ok_nt( STATUS_SUCCESS, status ); todo_wine check_d3dkmt_local( open2.hKeyedMutex, &next_local ); + next_local = 0; ok_x4( open2.PrivateRuntimeDataSize, ==, sizeof(runtime_data) ); ok_u1( buffer[0], ==, 0xcd );
@@ -1589,20 +1594,20 @@ static void test_D3DKMTCreateKeyedMutex( void ) todo_wine ok_nt( STATUS_SUCCESS, status ); destroy.hKeyedMutex = create2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status );
/* doesn't return a global D3DKMT_HANDLE with NtSecuritySharing = 1 */ create2.Flags.NtSecuritySharing = 1; create2.hKeyedMutex = create2.hSharedHandle = 0x1eadbeed; status = D3DKMTCreateKeyedMutex2( &create2 ); - todo_wine ok_nt( STATUS_SUCCESS, status ); - todo_wine check_d3dkmt_local( create2.hKeyedMutex, &next_local ); - todo_wine ok_x4( create2.hSharedHandle, ==, 0 ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hKeyedMutex, &next_local ); + ok_x4( create2.hSharedHandle, ==, 0 );
destroy.hKeyedMutex = create2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); }
static void test_D3DKMTCreateAllocation( void ) @@ -2251,23 +2256,23 @@ static void test_D3DKMTShareObjects( void )
/* D3DKMTShareObjects doesn't work with keyed mutex objects alone */ status = D3DKMTCreateKeyedMutex( &create_mutex ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); status = D3DKMTShareObjects( 1, &create_mutex.hKeyedMutex, &attr, STANDARD_RIGHTS_WRITE, &handle ); todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); status = D3DKMTShareObjects( 1, &create_mutex.hSharedHandle, &attr, STANDARD_RIGHTS_WRITE, &handle ); todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); destroy_mutex.hKeyedMutex = create_mutex.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy_mutex ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status );
create_mutex2.Flags.NtSecuritySharing = 1; status = D3DKMTCreateKeyedMutex2( &create_mutex2 ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); status = D3DKMTShareObjects( 1, &create_mutex2.hKeyedMutex, &attr, STANDARD_RIGHTS_WRITE, &handle ); todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); destroy_mutex.hKeyedMutex = create_mutex2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy_mutex ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status );
/* NtSecuritySharing = 1 is required for D3DKMTShareObjects */ @@ -2462,7 +2467,7 @@ static void test_D3DKMTShareObjects( void ) create_mutex2.PrivateRuntimeDataSize = sizeof(expect_mutex_data); create_mutex2.pPrivateRuntimeData = expect_mutex_data; status = D3DKMTCreateKeyedMutex2( &create_mutex2 ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status );
objects[0] = create_alloc.hResource; objects[1] = create_alloc.hResource; @@ -2510,7 +2515,7 @@ static void test_D3DKMTShareObjects( void )
destroy_mutex.hKeyedMutex = create_mutex2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy_mutex ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); create_mutex2.hKeyedMutex = 0;
destroy_sync.hSyncObject = create_sync2.hSyncObject; diff --git a/dlls/wow64win/gdi.c b/dlls/wow64win/gdi.c index 30c4a5b6d62..f8e3056c932 100644 --- a/dlls/wow64win/gdi.c +++ b/dlls/wow64win/gdi.c @@ -726,6 +726,8 @@ NTSTATUS WINAPI wow64_NtGdiDdDDICreateKeyedMutex2( UINT *args ) D3DKMT_CREATEKEYEDMUTEX2 desc; NTSTATUS status;
+ if (!desc32) return STATUS_INVALID_PARAMETER; + desc.InitialValue = desc32->InitialValue; desc.hSharedHandle = desc32->hSharedHandle; desc.hKeyedMutex = desc32->hKeyedMutex; @@ -734,6 +736,7 @@ NTSTATUS WINAPI wow64_NtGdiDdDDICreateKeyedMutex2( UINT *args ) desc.Flags = desc32->Flags; status = NtGdiDdDDICreateKeyedMutex2( &desc ); desc32->hKeyedMutex = desc.hKeyedMutex; + desc32->hSharedHandle = desc.hSharedHandle; return status; }
diff --git a/server/Makefile.in b/server/Makefile.in index 57250fd0332..d3d50b9aa5a 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -8,6 +8,7 @@ SOURCES = \ clipboard.c \ completion.c \ console.c \ + d3dkmt.c \ debugger.c \ device.c \ directory.c \ diff --git a/server/d3dkmt.c b/server/d3dkmt.c new file mode 100644 index 00000000000..64301548784 --- /dev/null +++ b/server/d3dkmt.c @@ -0,0 +1,105 @@ +/* + * Server-side D3DKMT resource management + * + * Copyright 2025 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> + +#include <unistd.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#include "ddk/wdm.h" + +#include "file.h" +#include "handle.h" +#include "request.h" +#include "security.h" + +struct d3dkmt_object +{ + struct object obj; /* object header */ + enum d3dkmt_type type; /* object type */ +}; + +static void d3dkmt_object_dump( struct object *obj, int verbose ); +static void d3dkmt_object_destroy( struct object *obj ); + +static const struct object_ops d3dkmt_object_ops = +{ + sizeof(struct d3dkmt_object), /* size */ + &no_type, /* type */ + d3dkmt_object_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_get_sync, /* get_sync */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + no_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + no_link_name, /* link_name */ + NULL, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + d3dkmt_object_destroy, /* destroy */ +}; + +static void d3dkmt_object_dump( struct object *obj, int verbose ) +{ + struct d3dkmt_object *object = (struct d3dkmt_object *)obj; + assert( obj->ops == &d3dkmt_object_ops ); + + fprintf( stderr, "type=%#x\n", object->type ); +} + +static void d3dkmt_object_destroy( struct object *obj ) +{ + assert( obj->ops == &d3dkmt_object_ops ); +} + +static struct d3dkmt_object *d3dkmt_object_create( enum d3dkmt_type type ) +{ + struct d3dkmt_object *object; + + if (!(object = alloc_object( &d3dkmt_object_ops ))) return NULL; + object->type = type; + + return object; +} + +/* create a global d3dkmt object */ +DECL_HANDLER(d3dkmt_object_create) +{ + struct d3dkmt_object *object; + + if (!(object = d3dkmt_object_create( req->type ))) return; + reply->handle = alloc_handle( current->process, object, STANDARD_RIGHTS_ALL, OBJ_INHERIT ); + release_object( object ); +} diff --git a/server/protocol.def b/server/protocol.def index 59c6436fa88..6ab783a7c5d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -968,6 +968,14 @@ union udp_endpoint } ipv6; };
+enum d3dkmt_type +{ + D3DKMT_ADAPTER = 1, + D3DKMT_DEVICE = 2, + D3DKMT_SOURCE = 3, + D3DKMT_MUTEX = 4, +}; + /****************************************************************/ /* shared session mapping structures */
@@ -4137,3 +4145,12 @@ enum inproc_sync_type int type; /* inproc sync type */ unsigned int access; /* handle access rights */ @END + + +/* Create a global d3dkmt object */ +@REQ(d3dkmt_object_create) + unsigned int type; /* d3dkmt object type */ +@REPLY + obj_handle_t handle; /* process-private handle */ +@END +