From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 131 ++++++++++++++++++++++++++++++++++++- dlls/win32u/tests/d3dkmt.c | 44 ++++++------- server/d3dkmt.c | 86 ++++++++++++++++++++++++ server/protocol.def | 10 +++ 4 files changed, 247 insertions(+), 24 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index f21a7728581..e47a95d9c85 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -252,6 +252,99 @@ static void d3dkmt_object_free( struct d3dkmt_object *object ) free( object ); }
+/* create a struct security_descriptor and contained information in one contiguous piece of memory */ +static unsigned int alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret, + data_size_t *ret_len ) +{ + unsigned int len = sizeof(**ret); + SID *owner = NULL, *group = NULL; + ACL *dacl = NULL, *sacl = NULL; + SECURITY_DESCRIPTOR *sd; + + *ret = NULL; + *ret_len = 0; + + if (!attr) return STATUS_SUCCESS; + + if (attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER; + + if ((sd = attr->SecurityDescriptor)) + { + len += sizeof(struct security_descriptor); + if (sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; + if (sd->Control & SE_SELF_RELATIVE) + { + SECURITY_DESCRIPTOR_RELATIVE *rel = (SECURITY_DESCRIPTOR_RELATIVE *)sd; + if (rel->Owner) owner = (PSID)((BYTE *)rel + rel->Owner); + if (rel->Group) group = (PSID)((BYTE *)rel + rel->Group); + if ((sd->Control & SE_SACL_PRESENT) && rel->Sacl) sacl = (PSID)((BYTE *)rel + rel->Sacl); + if ((sd->Control & SE_DACL_PRESENT) && rel->Dacl) dacl = (PSID)((BYTE *)rel + rel->Dacl); + } + else + { + owner = sd->Owner; + group = sd->Group; + if (sd->Control & SE_SACL_PRESENT) sacl = sd->Sacl; + if (sd->Control & SE_DACL_PRESENT) dacl = sd->Dacl; + } + + if (owner) len += offsetof( SID, SubAuthority[owner->SubAuthorityCount] ); + if (group) len += offsetof( SID, SubAuthority[group->SubAuthorityCount] ); + if (sacl) len += sacl->AclSize; + if (dacl) len += dacl->AclSize; + + /* fix alignment for the Unicode name that follows the structure */ + len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1); + } + + if (attr->ObjectName) + { + if ((ULONG_PTR)attr->ObjectName->Buffer & (sizeof(WCHAR) - 1)) return STATUS_DATATYPE_MISALIGNMENT; + if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID; + len += attr->ObjectName->Length; + } + else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID; + + len = (len + 3) & ~3; /* DWORD-align the entire structure */ + + if (!(*ret = calloc( len, 1 ))) return STATUS_NO_MEMORY; + + (*ret)->rootdir = wine_server_obj_handle( attr->RootDirectory ); + (*ret)->attributes = attr->Attributes; + + if (attr->SecurityDescriptor) + { + struct security_descriptor *descr = (struct security_descriptor *)(*ret + 1); + unsigned char *ptr = (unsigned char *)(descr + 1); + + descr->control = sd->Control & ~SE_SELF_RELATIVE; + if (owner) descr->owner_len = offsetof( SID, SubAuthority[owner->SubAuthorityCount] ); + if (group) descr->group_len = offsetof( SID, SubAuthority[group->SubAuthorityCount] ); + if (sacl) descr->sacl_len = sacl->AclSize; + if (dacl) descr->dacl_len = dacl->AclSize; + + memcpy( ptr, owner, descr->owner_len ); + ptr += descr->owner_len; + memcpy( ptr, group, descr->group_len ); + ptr += descr->group_len; + memcpy( ptr, sacl, descr->sacl_len ); + ptr += descr->sacl_len; + memcpy( ptr, dacl, descr->dacl_len ); + (*ret)->sd_len = (sizeof(*descr) + descr->owner_len + descr->group_len + descr->sacl_len + + descr->dacl_len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1); + } + + if (attr->ObjectName) + { + unsigned char *ptr = (unsigned char *)(*ret + 1) + (*ret)->sd_len; + (*ret)->name_len = attr->ObjectName->Length; + memcpy( ptr, attr->ObjectName->Buffer, (*ret)->name_len ); + } + + *ret_len = len; + return STATUS_SUCCESS; +} + static VkInstance d3dkmt_vk_instance; /* Vulkan instance for D3DKMT functions */ static PFN_vkGetPhysicalDeviceMemoryProperties2KHR pvkGetPhysicalDeviceMemoryProperties2KHR; static PFN_vkGetPhysicalDeviceMemoryProperties pvkGetPhysicalDeviceMemoryProperties; @@ -815,8 +908,42 @@ void free_vulkan_gpu( struct vulkan_gpu *gpu ) NTSTATUS WINAPI NtGdiDdDDIShareObjects( UINT count, const D3DKMT_HANDLE *handles, OBJECT_ATTRIBUTES *attr, UINT access, HANDLE *handle ) { - FIXME( "count %u, handles %p, attr %p, access %#x, handle %p stub!\n", count, handles, attr, access, handle ); - return STATUS_NOT_IMPLEMENTED; + struct d3dkmt_object *object, *sync; + struct object_attributes *objattr; + data_size_t len; + NTSTATUS status; + + TRACE( "count %u, handles %p, attr %p, access %#x, handle %p\n", count, handles, attr, access, handle ); + + if (count == 1) + { + if (!(object = get_d3dkmt_object( handles[0], -1 )) || !object->shared) goto failed; + if (object->type == D3DKMT_SYNC) sync = object; + else goto failed; + } + else goto failed; + + if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status; + + SERVER_START_REQ( d3dkmt_share_objects ) + { + req->access = access | STANDARD_RIGHTS_ALL; + req->sync = sync->global; + wine_server_add_data( req, objattr, len ); + status = wine_server_call( req ); + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + + free( objattr ); + + if (status) WARN( "Failed to share objects, status %#x\n", status ); + else TRACE( "Shared objects with handle %p\n", *handle ); + return status; + +failed: + WARN( "Unsupported object count / types / handles\n" ); + return STATUS_INVALID_PARAMETER; }
/****************************************************************************** diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index 83ed9f0dfd0..56ac8f81b1e 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -2155,7 +2155,7 @@ static void test_D3DKMTShareObjects( void ) ok_nt( STATUS_SUCCESS, status ); handle = (HANDLE)0xdeadbeef; status = D3DKMTShareObjects( 1, &create_sync.hSyncObject, &attr, STANDARD_RIGHTS_WRITE, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); if (broken( !status )) CloseHandle( handle ); destroy_sync.hSyncObject = create_sync.hSyncObject; status = D3DKMTDestroySynchronizationObject( &destroy_sync ); @@ -2168,7 +2168,7 @@ static void test_D3DKMTShareObjects( void ) ok_nt( STATUS_SUCCESS, status ); handle = (HANDLE)0xdeadbeef; status = D3DKMTShareObjects( 1, &create_sync2.hSyncObject, &attr, STANDARD_RIGHTS_WRITE, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); if (broken( !status )) CloseHandle( handle ); destroy_sync.hSyncObject = create_sync2.hSyncObject; status = D3DKMTDestroySynchronizationObject( &destroy_sync ); @@ -2179,7 +2179,7 @@ static void test_D3DKMTShareObjects( void ) ok_nt( STATUS_SUCCESS, status ); handle = (HANDLE)0xdeadbeef; status = D3DKMTShareObjects( 1, &create_sync2.hSyncObject, &attr, STANDARD_RIGHTS_WRITE, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); if (broken( !status )) CloseHandle( handle ); destroy_sync.hSyncObject = create_sync2.hSyncObject; status = D3DKMTDestroySynchronizationObject( &destroy_sync ); @@ -2192,12 +2192,12 @@ static void test_D3DKMTShareObjects( void ) InitializeObjectAttributes( &attr, &name, 0, 0, NULL ); handle = (HANDLE)0xdeadbeef; status = D3DKMTShareObjects( 1, &create_sync2.hSyncObject, &attr, STANDARD_RIGHTS_WRITE, &handle ); - todo_wine ok_nt( STATUS_SUCCESS, status ); + ok_nt( STATUS_SUCCESS, status ); /* handle isn't a D3DKMT_HANDLE */ - todo_wine ok( !((UINT_PTR)handle & 0xc0000000), "got %p\n", handle ); + ok( !((UINT_PTR)handle & 0xc0000000), "got %p\n", handle );
- todo_wine check_object_type( handle, L"DxgkSharedSyncObject" ); - todo_wine check_object_name( handle, name.Buffer ); + check_object_type( handle, L"DxgkSharedSyncObject" ); + check_object_name( handle, name.Buffer );
/* cannot destroy the handle */ destroy_sync.hSyncObject = (UINT_PTR)handle; @@ -2221,7 +2221,7 @@ static void test_D3DKMTShareObjects( void ) /* objects opened with D3DKMTOpenSyncObjectFromNtHandle cannot be reshared */ InitializeObjectAttributes( &attr, &name, 0, 0, NULL ); status = D3DKMTShareObjects( 1, &create_sync2.hSyncObject, &attr, STANDARD_RIGHTS_WRITE, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
destroy_sync.hSyncObject = open_sync.hSyncObject; status = D3DKMTDestroySynchronizationObject( &destroy_sync ); @@ -2312,9 +2312,9 @@ static void test_D3DKMTShareObjects( void ) status = D3DKMTCreateKeyedMutex( &create_mutex ); ok_nt( STATUS_SUCCESS, status ); status = D3DKMTShareObjects( 1, &create_mutex.hKeyedMutex, &attr, STANDARD_RIGHTS_WRITE, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + 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 ); + ok_nt( STATUS_INVALID_PARAMETER, status ); destroy_mutex.hKeyedMutex = create_mutex.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy_mutex ); ok_nt( STATUS_SUCCESS, status ); @@ -2323,7 +2323,7 @@ static void test_D3DKMTShareObjects( void ) status = D3DKMTCreateKeyedMutex2( &create_mutex2 ); ok_nt( STATUS_SUCCESS, status ); status = D3DKMTShareObjects( 1, &create_mutex2.hKeyedMutex, &attr, STANDARD_RIGHTS_WRITE, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); destroy_mutex.hKeyedMutex = create_mutex2.hKeyedMutex; status = D3DKMTDestroyKeyedMutex( &destroy_mutex ); ok_nt( STATUS_SUCCESS, status ); @@ -2354,9 +2354,9 @@ static void test_D3DKMTShareObjects( void ) check_d3dkmt_local( alloc.hAllocation, NULL );
status = D3DKMTShareObjects( 1, &alloc.hAllocation, &attr, STANDARD_RIGHTS_READ, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); status = D3DKMTShareObjects( 1, &create_alloc.hResource, &attr, STANDARD_RIGHTS_READ, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
destroy_alloc.hDevice = create_device.hDevice; destroy_alloc.hResource = create_alloc.hResource; @@ -2374,9 +2374,9 @@ static void test_D3DKMTShareObjects( void ) check_d3dkmt_local( alloc.hAllocation, NULL );
status = D3DKMTShareObjects( 1, &alloc.hAllocation, &attr, STANDARD_RIGHTS_READ, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); status = D3DKMTShareObjects( 1, &create_alloc.hResource, &attr, STANDARD_RIGHTS_READ, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
destroy_alloc.hResource = create_alloc.hResource; status = D3DKMTDestroyAllocation( &destroy_alloc ); @@ -2394,7 +2394,7 @@ static void test_D3DKMTShareObjects( void )
/* can only share resources, not allocations */ status = D3DKMTShareObjects( 1, &alloc.hAllocation, &attr, STANDARD_RIGHTS_READ, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status ); status = D3DKMTShareObjects( 1, &create_alloc.hResource, &attr, STANDARD_RIGHTS_READ, &handle ); todo_wine ok_nt( STATUS_SUCCESS, status );
@@ -2527,35 +2527,35 @@ static void test_D3DKMTShareObjects( void ) objects[1] = create_alloc.hResource; objects[2] = create_alloc.hResource; status = D3DKMTShareObjects( 3, objects, &attr, STANDARD_RIGHTS_ALL, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
objects[0] = create_alloc.hResource; objects[1] = create_mutex2.hKeyedMutex; status = D3DKMTShareObjects( 2, objects, &attr, STANDARD_RIGHTS_ALL, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
objects[0] = create_alloc.hResource; objects[1] = create_sync2.hSyncObject; status = D3DKMTShareObjects( 2, objects, &attr, STANDARD_RIGHTS_ALL, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
objects[0] = create_mutex2.hKeyedMutex; objects[1] = create_sync2.hSyncObject; status = D3DKMTShareObjects( 2, objects, &attr, STANDARD_RIGHTS_ALL, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
objects[0] = create_alloc.hResource; objects[1] = create_mutex2.hKeyedMutex; objects[2] = create_sync2.hSyncObject; objects[3] = create_sync2.hSyncObject; status = D3DKMTShareObjects( 4, objects, &attr, STANDARD_RIGHTS_ALL, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
objects[0] = create_alloc.hResource; objects[1] = create_sync2.hSyncObject; objects[2] = create_mutex2.hKeyedMutex; status = D3DKMTShareObjects( 3, objects, &attr, STANDARD_RIGHTS_ALL, &handle ); - todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + ok_nt( STATUS_INVALID_PARAMETER, status );
objects[0] = create_alloc.hResource; objects[1] = create_mutex2.hKeyedMutex; diff --git a/server/d3dkmt.c b/server/d3dkmt.c index 23f0e6d4a71..95032ede3d1 100644 --- a/server/d3dkmt.c +++ b/server/d3dkmt.c @@ -72,6 +72,72 @@ static const struct object_ops d3dkmt_object_ops = d3dkmt_object_destroy, /* destroy */ };
+#define DXGK_SHARED_SYNC_QUERY_STATE 0x0001 +#define DXGK_SHARED_SYNC_MODIFY_STATE 0x0002 +#define DXGK_SHARED_SYNC_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +static const WCHAR dxgk_shared_sync_name[] = {'D','x','g','k','S','h','a','r','e','d','S','y','n','c','O','b','j','e','c','t'}; + +struct type_descr dxgk_shared_sync_type = +{ + { dxgk_shared_sync_name, sizeof(dxgk_shared_sync_name) }, /* name */ + DXGK_SHARED_SYNC_ALL_ACCESS, /* valid_access */ + { /* mapping */ + STANDARD_RIGHTS_READ | DXGK_SHARED_SYNC_QUERY_STATE, + STANDARD_RIGHTS_WRITE | DXGK_SHARED_SYNC_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, + DXGK_SHARED_SYNC_ALL_ACCESS, + }, +}; + +struct dxgk_shared_sync +{ + struct object obj; /* object header */ + struct object *sync; /* shared sync object */ +}; + +static void dxgk_shared_sync_dump( struct object *obj, int verbose ); +static void dxgk_shared_sync_destroy( struct object *obj ); + +static const struct object_ops dxgk_shared_sync_ops = +{ + sizeof(struct dxgk_shared_sync), /* size */ + &dxgk_shared_sync_type, /* type */ + dxgk_shared_sync_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 */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + dxgk_shared_sync_destroy, /* destroy */ +}; + +static void dxgk_shared_sync_dump( struct object *obj, int verbose ) +{ + struct dxgk_shared_sync *shared = (struct dxgk_shared_sync *)obj; + assert( obj->ops == &dxgk_shared_sync_ops ); + fprintf( stderr, "sync=%p\n", shared->sync ); +} + +static void dxgk_shared_sync_destroy( struct object *obj ) +{ + struct dxgk_shared_sync *shared = (struct dxgk_shared_sync *)obj; + assert( obj->ops == &dxgk_shared_sync_ops ); + release_object( shared->sync ); +} + static struct d3dkmt_object **objects, **objects_end, **objects_next;
#define D3DKMT_HANDLE_BIT 0x40000000 @@ -260,3 +326,23 @@ DECL_HANDLER(d3dkmt_object_open)
release_object( object ); } + +/* share global d3dkmt objects together */ +DECL_HANDLER(d3dkmt_share_objects) +{ + struct object *sync = NULL; + const struct object_attributes *objattr; + const struct security_descriptor *sd; + struct dxgk_shared_sync *shared; + struct unicode_str name; + struct object *root; + + objattr = get_req_object_attributes( &sd, &name, &root ); + + if (!(sync = get_d3dkmt_object( req->sync, D3DKMT_SYNC ))) return; + + if (!(shared = create_named_object( root, &dxgk_shared_sync_ops, &name, objattr->attributes | OBJ_CASE_INSENSITIVE, NULL ))) return; + shared->sync = grab_object( sync ); + reply->handle = alloc_handle( current->process, shared, req->access, OBJ_INHERIT ); + release_object( shared ); +} diff --git a/server/protocol.def b/server/protocol.def index 6b1d1dd1cfb..819ea6e8311 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4182,3 +4182,13 @@ enum inproc_sync_type data_size_t runtime_size; /* size of client runtime data */ VARARG(runtime,bytes); /* client runtime data */ @END + + +/* Share d3dkmt objects together */ +@REQ(d3dkmt_share_objects) + d3dkmt_handle_t sync; /* sync global handle */ + unsigned int access; /* wanted access rights */ + VARARG(objattr,object_attributes); /* object attributes */ +@REPLY + obj_handle_t handle; /* shared object handle */ +@END