From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winevulkan/vulkan.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 3ff313e5b83..2ac12df6e7c 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -329,7 +329,7 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi BOOL have_memory_placed = FALSE, have_map_memory2 = FALSE; uint32_t num_host_properties, num_properties = 0; VkExtensionProperties *host_properties = NULL; - BOOL have_external_memory_host = FALSE; + BOOL have_external_memory_host = FALSE, have_external_semaphore = FALSE; VkResult res; unsigned int i, j;
@@ -380,6 +380,8 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi } if (!strcmp(host_properties[i].extensionName, "VK_EXT_external_memory_host")) have_external_memory_host = TRUE; + else if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_semaphore_win32"))) + have_external_semaphore = TRUE; else if (!strcmp(host_properties[i].extensionName, "VK_EXT_map_memory_placed")) have_memory_placed = TRUE; else if (!strcmp(host_properties[i].extensionName, "VK_EXT_surface_maintenance1")) @@ -388,6 +390,8 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi physical_device->has_swapchain_maintenance1 = true; else if (!strcmp(host_properties[i].extensionName, "VK_KHR_map_memory2")) have_map_memory2 = TRUE; + else if (!strcmp(host_properties[i].extensionName, "VK_KHR_timeline_semaphore")) + num_properties++; }
TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties); @@ -449,6 +453,11 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi
for (i = 0, j = 0; i < num_host_properties; i++) { + if (have_external_semaphore && !strcmp(host_properties[i].extensionName, "VK_KHR_timeline_semaphore")) + { + strcpy(physical_device->extensions[j].extensionName, "VK_KHR_win32_keyed_mutex"); + physical_device->extensions[j++].specVersion = VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION; + } if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_memory_win32"))) { if (zero_bits && !physical_device->map_placed_align) @@ -593,6 +602,7 @@ static VkResult wine_vk_device_convert_create_info(struct vulkan_physical_device if (!strcmp(*extension, "VK_EXT_swapchain_maintenance1")) has_swapchain_maintenance1 = true; if (!strcmp(*extension, "VK_EXT_surface_maintenance1")) has_surface_maintenance1 = true; if (!strcmp(*extension, "VK_KHR_swapchain")) has_swapchain = true; + if (!strcmp(*extension, "VK_KHR_win32_keyed_mutex")) *extension = "VK_KHR_timeline_semaphore"; if (!strcmp(*extension, "VK_KHR_external_memory_win32")) { if (zero_bits && !physical_device->map_placed_align)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/tests/d3dkmt.c | 226 ++++++++++++++++++++++++++++++++++++- 1 file changed, 224 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index b3a9baf4785..5b76832538b 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -225,8 +225,8 @@ static void check_dxgi_runtime_desc_( struct dxgi_runtime_desc *desc, const stru else if (!d3d12) ok_x4( desc->unknown_0, ==, 0 ); ok_x4( desc->unknown_1, ==, 0 ); ok_x4( desc->keyed_mutex, ==, expect->keyed_mutex ); - if (desc->keyed_mutex) check_d3dkmt_global( desc->mutex_handle ); - if (desc->keyed_mutex) check_d3dkmt_global( desc->sync_handle ); + if (desc->keyed_mutex && !desc->nt_shared) check_d3dkmt_global( desc->mutex_handle ); + if (desc->keyed_mutex && !desc->nt_shared) check_d3dkmt_global( desc->sync_handle ); ok_x4( desc->nt_shared, ==, expect->nt_shared ); ok_x4( desc->unknown_2, ==, 0 ); ok_x4( desc->unknown_3, ==, 0 ); @@ -2661,6 +2661,7 @@ static void test_D3DKMTShareObjects( void ) D3DKMT_CLOSEADAPTER close_adapter = {0};
D3DKMT_QUERYRESOURCEINFOFROMNTHANDLE query_resource = {0}; + D3DKMT_OPENKEYEDMUTEXFROMNTHANDLE open_mutex_nt = {0}; D3DKMT_OPENRESOURCEFROMNTHANDLE open_resource = {0}; D3DKMT_CREATESTANDARDALLOCATION standard = {0}; D3DKMT_DESTROYALLOCATION destroy_alloc = {0}; @@ -3189,6 +3190,12 @@ static void test_D3DKMTShareObjects( void ) ok_nt( STATUS_SUCCESS, status ); open_resource.hSyncObject = 0;
+ /* D3DKMTOpenKeyedMutexFromNtHandle doesn't work with resource handle */ + open_mutex_nt.hNtHandle = handle; + open_mutex_nt.hKeyedMutex = 0xdeadbeef; + status = D3DKMTOpenKeyedMutexFromNtHandle( &open_mutex_nt ); + todo_wine ok_nt( STATUS_OBJECT_TYPE_MISMATCH, status ); + memset( &open_resource, 0, sizeof(open_resource) ); CloseHandle( handle );
@@ -3452,6 +3459,7 @@ static struct vulkan_device *create_vulkan_device( LUID *luid ) "VK_KHR_dedicated_allocation", "VK_KHR_external_memory", "VK_KHR_external_memory_win32", + "VK_KHR_win32_keyed_mutex", };
VkDeviceQueueCreateInfo queue_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; @@ -4054,6 +4062,190 @@ static HRESULT get_d3d12_shared_handle( ID3D12Device *d3d12, IUnknown *obj, cons return hr; }
+static void test_shared_keyed_mutex( LUID luid, struct vulkan_device *vulkan_imp, struct vulkan_image *img, HANDLE handle, BOOL shared ) +{ + uint64_t release_key = 0, acquire_key = 0; + uint32_t acquire_timeout = 100; + + VkWin32KeyedMutexAcquireReleaseInfoKHR mutex_acquire = + { + .sType = VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR, + .acquireCount = 1, + .pAcquireSyncs = &img->memory, + .pAcquireKeys = &acquire_key, + .pAcquireTimeouts = &acquire_timeout, + }; + VkWin32KeyedMutexAcquireReleaseInfoKHR mutex_release = + { + .sType = VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR, + .releaseCount = 1, + .pReleaseSyncs = &img->memory, + .pReleaseKeys = &release_key, + }; + VkSubmitInfo submit_acquire = + { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = &mutex_acquire, + }; + VkSubmitInfo submit_release = + { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = &mutex_release, + }; + LARGE_INTEGER timeout = {.QuadPart = 10 * -10000}; + PFN_vkGetDeviceQueue p_vkGetDeviceQueue; + D3DKMT_DESTROYKEYEDMUTEX destroy = {0}; + D3DKMT_ACQUIREKEYEDMUTEX acquire = {0}; + D3DKMT_RELEASEKEYEDMUTEX release = {0}; + D3DKMT_HANDLE next_local = 0, mutex = 0; + PFN_vkQueueSubmit p_vkQueueSubmit; + NTSTATUS status; + VkQueue queue; + VkResult vr; + + if (is_d3dkmt_handle( handle )) + { + D3DKMT_OPENKEYEDMUTEX open = {0}; + + open.hSharedHandle = HandleToULong( handle ); + open.hKeyedMutex = 0xdeadbeef; + status = D3DKMTOpenKeyedMutex( &open ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( open.hKeyedMutex, &next_local ); + mutex = open.hKeyedMutex; + } + else + { + D3DKMT_DESTROYSYNCHRONIZATIONOBJECT destroy_sync = {0}; + D3DKMT_QUERYRESOURCEINFOFROMNTHANDLE query = {0}; + D3DKMT_OPENADAPTERFROMLUID open_adapter = {0}; + D3DKMT_DESTROYALLOCATION destroy_alloc = {0}; + D3DDDI_OPENALLOCATIONINFO2 open_alloc = {0}; + D3DKMT_OPENRESOURCEFROMNTHANDLE open = {0}; + D3DKMT_DESTROYDEVICE destroy_device = {0}; + D3DKMT_CREATEDEVICE create_device = {0}; + D3DKMT_CLOSEADAPTER close_adapter = {0}; + char resource_data[0x100] = {0}; + char runtime_data[0x400] = {0}; + char driver_data[0x4000] = {0}; + + open_adapter.AdapterLuid = luid; + status = D3DKMTOpenAdapterFromLuid( &open_adapter ); + ok_nt( status, STATUS_SUCCESS ); + check_d3dkmt_local( open_adapter.hAdapter, NULL ); + create_device.hAdapter = open_adapter.hAdapter; + status = D3DKMTCreateDevice( &create_device ); + ok_nt( status, STATUS_SUCCESS ); + check_d3dkmt_local( create_device.hDevice, NULL ); + + query.hDevice = create_device.hDevice; + query.hNtHandle = handle; + query.pPrivateRuntimeData = runtime_data; + query.PrivateRuntimeDataSize = sizeof(runtime_data); + status = D3DKMTQueryResourceInfoFromNtHandle( &query ); + ok_nt( STATUS_SUCCESS, status ); + + open.hDevice = create_device.hDevice; + open.hNtHandle = handle; + open.NumAllocations = 1; + open.pOpenAllocationInfo2 = &open_alloc; + open.pPrivateRuntimeData = runtime_data; + open.PrivateRuntimeDataSize = query.PrivateRuntimeDataSize; + open.pResourcePrivateDriverData = resource_data; + open.ResourcePrivateDriverDataSize = query.ResourcePrivateDriverDataSize; + open.pTotalPrivateDriverDataBuffer = driver_data; + open.TotalPrivateDriverDataBufferSize = query.TotalPrivateDriverDataSize; + /* exported NT handle doesn't seem to bundle the keyed mutex */ + status = D3DKMTOpenResourceFromNtHandle( &open ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( open.hResource, NULL ); + check_d3dkmt_local( open.hKeyedMutex, NULL ); + check_d3dkmt_local( open.hSyncObject, NULL ); + todo_wine check_d3dkmt_local( open_alloc.hAllocation, NULL ); + todo_wine ok_x4( open_alloc.PrivateDriverDataSize, >, 0 ); + + destroy_alloc.hDevice = create_device.hDevice; + destroy_alloc.hResource = open.hResource; + status = D3DKMTDestroyAllocation( &destroy_alloc ); + ok_nt( STATUS_SUCCESS, status ); + + destroy_sync.hSyncObject = open.hSyncObject; + status = D3DKMTDestroySynchronizationObject( &destroy_sync ); + ok_nt( STATUS_SUCCESS, status ); + + destroy_device.hDevice = create_device.hDevice; + status = D3DKMTDestroyDevice( &destroy_device ); + ok_nt( status, STATUS_SUCCESS ); + close_adapter.hAdapter = open_adapter.hAdapter; + status = D3DKMTCloseAdapter( &close_adapter ); + ok_nt( status, STATUS_SUCCESS ); + + mutex = open.hKeyedMutex; + } + + p_vkGetDeviceQueue = (void *)p_vkGetDeviceProcAddr( vulkan_imp->device, "vkGetDeviceQueue" ); + ok_ptr( p_vkGetDeviceQueue, !=, NULL ); + p_vkQueueSubmit = (void *)p_vkGetDeviceProcAddr( vulkan_imp->device, "vkQueueSubmit" ); + ok_ptr( p_vkQueueSubmit, !=, NULL ); + + p_vkGetDeviceQueue( vulkan_imp->device, get_vulkan_queue_family( vulkan_imp->instance, vulkan_imp->physical_device ), 0, &queue ); + ok_ptr( queue, !=, VK_NULL_HANDLE ); + + vr = p_vkQueueSubmit( queue, 1, &submit_acquire, VK_NULL_HANDLE ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( queue, 1, &submit_release, VK_NULL_HANDLE ); + ok_vk( VK_SUCCESS, vr ); + + vr = p_vkQueueSubmit( queue, 1, &submit_acquire, VK_NULL_HANDLE ); + ok_vk( VK_SUCCESS, vr ); + /* acquiring again from vulkan-owned mutex generates an error */ + vr = p_vkQueueSubmit( queue, 1, &submit_acquire, VK_NULL_HANDLE ); + ok( vr == VK_ERROR_UNKNOWN || vr == VK_ERROR_INITIALIZATION_FAILED, "got %d\n", vr ); + + vr = p_vkQueueSubmit( queue, 1, &submit_release, VK_NULL_HANDLE ); + ok_vk( VK_SUCCESS, vr ); + /* releasing a non-owned mutex may succeed or generate an error */ + vr = p_vkQueueSubmit( queue, 1, &submit_release, VK_NULL_HANDLE ); + ok( vr == VK_SUCCESS /* NVIDIA */ || vr == VK_ERROR_UNKNOWN /* AMD */, "got %d\n", vr ); + + acquire.hKeyedMutex = mutex; + acquire.Key = 0; + acquire.pTimeout = &timeout; + acquire.FenceValue = 0xdeadbeef; + status = D3DKMTAcquireKeyedMutex( &acquire ); + ok_nt( STATUS_SUCCESS, status ); + ok_x8( acquire.FenceValue, ==, 2 ); + /* acquiring from non-vulkan-owned mutex generates a timeout */ + vr = p_vkQueueSubmit( queue, 1, &submit_acquire, VK_NULL_HANDLE ); + ok_vk( VK_TIMEOUT, vr ); + + release.hKeyedMutex = mutex; + release.Key = 0; + release.FenceValue = 0; /* reset the fence value */ + status = D3DKMTReleaseKeyedMutex( &release ); + ok_nt( STATUS_SUCCESS, status ); + /* releasing a non-owned mutex may succeed or generate an error */ + vr = p_vkQueueSubmit( queue, 1, &submit_release, VK_NULL_HANDLE ); + ok( vr == VK_SUCCESS /* NVIDIA */ || vr == VK_ERROR_UNKNOWN /* AMD */, "got %d\n", vr ); + + vr = p_vkQueueSubmit( queue, 1, &submit_acquire, VK_NULL_HANDLE ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( queue, 1, &submit_release, VK_NULL_HANDLE ); + ok_vk( VK_SUCCESS, vr ); + + /* mutex fence value reset seems to be accepted by vulkan */ + acquire.FenceValue = 0xdeadbeef; + status = D3DKMTAcquireKeyedMutex( &acquire ); + ok_nt( STATUS_SUCCESS, status ); + ok_x8( acquire.FenceValue, ==, 1 ); + status = D3DKMTReleaseKeyedMutex( &release ); + ok_nt( STATUS_SUCCESS, status ); + + destroy.hKeyedMutex = mutex; + status = D3DKMTDestroyKeyedMutex( &destroy ); + ok_nt( STATUS_SUCCESS, status ); +} + static void test_shared_resources(void) { struct vulkan_device *vulkan_imp = NULL, *vulkan_exp = NULL; @@ -4557,6 +4749,25 @@ static void test_shared_resources(void) check_d3d11_runtime_desc( (struct d3d11_runtime_desc *)runtime_desc, &desc ); break; } + case MAKETEST(2, 2, 4): + { + const struct dxgi_runtime_desc dxgi = {.size = 0x68, .version = 4, .keyed_mutex = 1, .nt_shared = 1}; + const struct d3d11_runtime_desc desc = {.dxgi = dxgi, .dimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D, .d3d11_2d = { + .Width = width_2d, .Height = height_2d, .MipLevels = 1, .ArraySize = 1, .Format = DXGI_FORMAT_R8G8B8A8_UNORM, .SampleDesc.Count = 1, + .Usage = D3D11_USAGE_DEFAULT, .BindFlags = D3D11_BIND_SHADER_RESOURCE, .CPUAccessFlags = D3D11_CPU_ACCESS_WRITE, + .MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE, + }}; + hr = ID3D11Device1_CreateTexture2D( d3d11_exp, &desc.d3d11_2d, NULL, (ID3D11Texture2D **)&export ); + ok_hr( S_OK, hr ); + hr = get_dxgi_global_handle( export, &handle ); + todo_wine ok_hr( E_INVALIDARG, hr ); + hr = get_dxgi_shared_handle( export, name, &handle ); + todo_wine ok_hr( S_OK, hr ); + if (hr != S_OK) break; + get_d3dkmt_resource_desc( luid, handle, FALSE, sizeof(desc), runtime_desc ); + check_d3d11_runtime_desc( (struct d3d11_runtime_desc *)runtime_desc, &desc ); + break; + } case MAKETEST(2, 3, 0): { const struct dxgi_runtime_desc dxgi = {.size = 0x68, .version = 4}; @@ -4995,6 +5206,8 @@ static void test_shared_resources(void)
if (vulkan_imp) { + struct dxgi_runtime_desc *desc = (struct dxgi_runtime_desc *)runtime_desc; + HANDLE mutex_handle = desc->keyed_mutex && !desc->nt_shared ? UlongToHandle(desc->mutex_handle) : handle; struct vulkan_buffer *buf_imp = NULL; struct vulkan_image *img_imp = NULL; VkResult vr; @@ -5017,6 +5230,7 @@ static void test_shared_resources(void) destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_1d, 1, array_1d, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, &img_imp ); ok_vk( VK_SUCCESS, vr ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); destroy_vulkan_image( vulkan_imp, img_imp ); break; case 2: @@ -5025,6 +5239,7 @@ static void test_shared_resources(void) destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_2d, height_2d, 1, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, &img_imp ); ok_vk( VK_SUCCESS, vr ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); destroy_vulkan_image( vulkan_imp, img_imp ); break; case 3: @@ -5033,6 +5248,7 @@ static void test_shared_resources(void) destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_3d, height_3d, depth_3d, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, &img_imp ); ok_vk( VK_SUCCESS, vr ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); destroy_vulkan_image( vulkan_imp, img_imp ); break; } @@ -5057,10 +5273,12 @@ static void test_shared_resources(void) ok_vk( VK_SUCCESS, vr ); destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_1d, 1, array_1d, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, &img_imp ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); ok_vk( VK_SUCCESS, vr ); destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_1d, 1, array_1d, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, &img_imp ); ok_vk( VK_SUCCESS, vr ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); destroy_vulkan_image( vulkan_imp, img_imp ); break; case 2: @@ -5068,9 +5286,11 @@ static void test_shared_resources(void) ok_vk( VK_SUCCESS, vr ); destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_2d, height_2d, 1, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, &img_imp ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); ok_vk( VK_SUCCESS, vr ); destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_2d, height_2d, 1, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, &img_imp ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); ok_vk( VK_SUCCESS, vr ); destroy_vulkan_image( vulkan_imp, img_imp ); break; @@ -5080,9 +5300,11 @@ static void test_shared_resources(void) destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_3d, height_3d, depth_3d, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, &img_imp ); ok_vk( VK_SUCCESS, vr ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); destroy_vulkan_image( vulkan_imp, img_imp ); vr = import_vulkan_image( vulkan_imp, width_3d, height_3d, depth_3d, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, &img_imp ); ok_vk( VK_SUCCESS, vr ); + if (desc->keyed_mutex) test_shared_keyed_mutex( luid, vulkan_imp, img_imp, mutex_handle, desc->nt_shared ); destroy_vulkan_image( vulkan_imp, img_imp ); break; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 23 +++++++++++++++++++++++ dlls/winevulkan/vulkan.c | 6 +++++- include/wine/vulkan_driver.h | 1 + 3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index c075fad1c37..a31563e07c8 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -71,6 +71,7 @@ struct device_memory
D3DKMT_HANDLE sync; D3DKMT_HANDLE mutex; + VkSemaphore semaphore; };
static inline struct device_memory *device_memory_from_handle( VkDeviceMemory handle ) @@ -359,6 +360,26 @@ static VkResult win32u_vkAllocateMemory( VkDevice client_device, const VkMemoryA break; }
+ if (device->has_win32_keyed_mutex && memory->sync) + { + VkSemaphoreTypeCreateInfo semaphore_type = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO}; + VkSemaphoreCreateInfo semaphore_create = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, .pNext = &semaphore_type}; + VkImportSemaphoreFdInfoKHR fd_info = {.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR}; + + semaphore_type.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + if ((res = device->p_vkCreateSemaphore( device->host.device, &semaphore_create, NULL, &memory->semaphore ))) goto failed; + + fd_info.handleType = get_host_external_semaphore_type(); + fd_info.semaphore = memory->semaphore; + if ((fd_info.fd = d3dkmt_object_get_fd( memory->sync )) < 0) + { + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto failed; + } + + if ((res = device->p_vkImportSemaphoreFdKHR( device->host.device, &fd_info ))) goto failed; + } + if ((fd_info.fd = d3dkmt_object_get_fd( memory->local )) < 0) { res = VK_ERROR_INVALID_EXTERNAL_HANDLE; @@ -409,6 +430,7 @@ static VkResult win32u_vkAllocateMemory( VkDevice client_device, const VkMemoryA failed: WARN( "Failed to allocate memory, res %d\n", res ); if (host_device_memory) device->p_vkFreeMemory( device->host.device, host_device_memory, NULL ); + if (memory->semaphore) device->p_vkDestroySemaphore( device->host.device, memory->semaphore, NULL ); d3dkmt_destroy_resource( memory->local ); d3dkmt_destroy_mutex( memory->mutex ); d3dkmt_destroy_sync( memory->sync ); @@ -446,6 +468,7 @@ static void win32u_vkFreeMemory( VkDevice client_device, VkDeviceMemory client_m NtFreeVirtualMemory( GetCurrentProcess(), &memory->vm_map, &alloc_size, MEM_RELEASE ); }
+ if (memory->semaphore) device->p_vkDestroySemaphore( device->host.device, memory->semaphore, NULL ); if (memory->shared) NtClose( memory->shared ); d3dkmt_destroy_resource( memory->local ); d3dkmt_destroy_mutex( memory->mutex ); diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 2ac12df6e7c..ec326dda168 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -602,7 +602,11 @@ static VkResult wine_vk_device_convert_create_info(struct vulkan_physical_device if (!strcmp(*extension, "VK_EXT_swapchain_maintenance1")) has_swapchain_maintenance1 = true; if (!strcmp(*extension, "VK_EXT_surface_maintenance1")) has_surface_maintenance1 = true; if (!strcmp(*extension, "VK_KHR_swapchain")) has_swapchain = true; - if (!strcmp(*extension, "VK_KHR_win32_keyed_mutex")) *extension = "VK_KHR_timeline_semaphore"; + if (!strcmp(*extension, "VK_KHR_win32_keyed_mutex")) + { + device->obj.has_win32_keyed_mutex = true; + *extension = "VK_KHR_timeline_semaphore"; + } if (!strcmp(*extension, "VK_KHR_external_memory_win32")) { if (zero_bits && !physical_device->map_placed_align) diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h index 54570c3e017..fbc639f69fa 100644 --- a/include/wine/vulkan_driver.h +++ b/include/wine/vulkan_driver.h @@ -116,6 +116,7 @@ struct vulkan_device { VULKAN_OBJECT_HEADER( VkDevice, device ); struct vulkan_physical_device *physical_device; + bool has_win32_keyed_mutex; #define USE_VK_FUNC(x) PFN_ ## x p_ ## x; ALL_VK_DEVICE_FUNCS #undef USE_VK_FUNC
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 112 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index a31563e07c8..1eea15024a5 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -59,6 +59,40 @@ static const UINT EXTERNAL_SEMAPHORE_WIN32_BITS = VK_EXTERNAL_SEMAPHORE_HANDLE_T static const UINT EXTERNAL_FENCE_WIN32_BITS = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT | VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
+#define ROUND_SIZE(size, mask) ((((SIZE_T)(size) + (mask)) & ~(SIZE_T)(mask))) + +struct mempool +{ + struct mempool *next; + size_t mem_used; + char mem[2048]; +}; + +static void mem_free( struct mempool *pool ) +{ + struct mempool *iter, *next = pool->next; + while ((iter = next)) { next = iter->next; free( iter ); } + pool->mem_used = 0; + pool->next = NULL; +} + +static void *mem_alloc( struct mempool *pool, size_t size ) +{ + struct mempool *next = pool; + if (pool->mem_used + size > sizeof(pool->mem)) next = pool->next; + if (next && next->mem_used <= sizeof(next->mem) && next->mem_used + size <= sizeof(next->mem)) + { + void *ret = next->mem + next->mem_used; + next->mem_used += ROUND_SIZE( size, sizeof(UINT64) - 1 ); + return ret; + } + if (!(next = malloc( max( sizeof(*next), offsetof(struct mempool, mem[size]) ) ))) return NULL; + next->next = pool->next; + next->mem_used = size; + pool->next = next; + return next->mem; +} + struct device_memory { struct vulkan_device_memory obj; @@ -1367,6 +1401,8 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons struct vulkan_fence *fence = client_fence ? vulkan_fence_from_handle( client_fence ) : NULL; struct vulkan_queue *queue = vulkan_queue_from_handle( client_queue ); struct vulkan_device *device = queue->device; + VkResult res = VK_ERROR_OUT_OF_HOST_MEMORY; + struct mempool pool = {0};
TRACE( "queue %p, count %u, submits %p, fence %p\n", queue, count, submits, fence );
@@ -1374,6 +1410,13 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons { VkSubmitInfo *submit = (VkSubmitInfo *)submits + i; /* cast away const, chain has been copied in the thunks */ VkBaseOutStructure **next, *prev = (VkBaseOutStructure *)submit; + VkSemaphore *wait_semaphores, *signal_semaphores; + VkTimelineSemaphoreSubmitInfo *timeline = NULL; + VkDeviceGroupSubmitInfo *device_group = NULL; + UINT wait_count = 0, signal_count = 0; + VkPipelineStageFlags *wait_stages; + uint32_t *indexes; + uint64_t *values;
for (uint32_t j = 0; j < submit->commandBufferCount; j++) { @@ -1404,23 +1447,86 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons FIXME( "VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR not implemented!\n" ); *next = (*next)->pNext; next = &prev; break; - case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: break; + case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: + device_group = (VkDeviceGroupSubmitInfo *)*next; + break; case VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT: break; case VK_STRUCTURE_TYPE_FRAME_BOUNDARY_TENSORS_ARM: break; case VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV: break; case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: break; case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO: break; - case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: break; + case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: + timeline = (VkTimelineSemaphoreSubmitInfo *)*next; + break; case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR: + { + VkWin32KeyedMutexAcquireReleaseInfoKHR *mutex_info = (VkWin32KeyedMutexAcquireReleaseInfoKHR *)*next; FIXME( "VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR not implemented!\n" ); + wait_count = mutex_info->acquireCount; + signal_count = mutex_info->releaseCount; *next = (*next)->pNext; next = &prev; break; + } default: FIXME( "Unhandled sType %u.\n", (*next)->sType ); break; } } + + if (wait_count) /* extra wait semaphores, need to update arrays and counts */ + { + if (!(wait_semaphores = mem_alloc( &pool, (submit->waitSemaphoreCount + wait_count) * sizeof(*wait_semaphores) ))) goto failed; + memcpy( wait_semaphores, submit->pWaitSemaphores, submit->waitSemaphoreCount * sizeof(*wait_semaphores) ); + submit->pWaitSemaphores = wait_semaphores; + + if (!(wait_stages = mem_alloc( &pool, (submit->waitSemaphoreCount + wait_count) * sizeof(*wait_stages) ))) goto failed; + memcpy( wait_stages, submit->pWaitDstStageMask, submit->waitSemaphoreCount * sizeof(*wait_stages) ); + submit->pWaitDstStageMask = wait_stages; + + if (timeline) + { + if (!(values = mem_alloc( &pool, (timeline->waitSemaphoreValueCount + wait_count) * sizeof(*values) ))) goto failed; + memcpy( values, timeline->pWaitSemaphoreValues, timeline->waitSemaphoreValueCount * sizeof(*values) ); + timeline->waitSemaphoreValueCount = submit->waitSemaphoreCount; + timeline->pWaitSemaphoreValues = values; + } + + if (device_group) + { + if (!(indexes = mem_alloc( &pool, submit->waitSemaphoreCount * sizeof(*indexes) ))) goto failed; + memcpy( indexes, device_group->pWaitSemaphoreDeviceIndices, device_group->waitSemaphoreCount * sizeof(*indexes) ); + device_group->waitSemaphoreCount = submit->waitSemaphoreCount; + device_group->pWaitSemaphoreDeviceIndices = indexes; + } + } + + if (signal_count) /* extra signal semaphores, need to update arrays and counts */ + { + if (!(signal_semaphores = mem_alloc( &pool, (submit->signalSemaphoreCount + signal_count) * sizeof(*signal_semaphores) ))) goto failed; + memcpy( signal_semaphores, submit->pSignalSemaphores, submit->signalSemaphoreCount * sizeof(*signal_semaphores) ); + submit->pSignalSemaphores = signal_semaphores; + + if (timeline) + { + if (!(values = mem_alloc( &pool, submit->signalSemaphoreCount * sizeof(*values) ))) goto failed; + memcpy( values, timeline->pSignalSemaphoreValues, timeline->signalSemaphoreValueCount * sizeof(*values) ); + timeline->signalSemaphoreValueCount = submit->signalSemaphoreCount; + timeline->pSignalSemaphoreValues = values; + } + + if (device_group) + { + if (!(indexes = mem_alloc( &pool, submit->signalSemaphoreCount * sizeof(*indexes) ))) goto failed; + memcpy( indexes, device_group->pSignalSemaphoreDeviceIndices, device_group->signalSemaphoreCount * sizeof(*indexes) ); + device_group->signalSemaphoreCount = submit->signalSemaphoreCount; + device_group->pSignalSemaphoreDeviceIndices = indexes; + } + } }
- return device->p_vkQueueSubmit( queue->host.queue, count, submits, fence ? fence->host.fence : 0 ); + res = device->p_vkQueueSubmit( queue->host.queue, count, submits, fence ? fence->host.fence : 0 ); + +failed: + mem_free( &pool ); + return res; }
static VkResult win32u_vkQueueSubmit2( VkQueue client_queue, uint32_t count, const VkSubmitInfo2 *submits, VkFence client_fence )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 1eea15024a5..bab97bd435d 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -1402,16 +1402,20 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons struct vulkan_queue *queue = vulkan_queue_from_handle( client_queue ); struct vulkan_device *device = queue->device; VkResult res = VK_ERROR_OUT_OF_HOST_MEMORY; + VkTimelineSemaphoreSubmitInfo *timelines; struct mempool pool = {0};
TRACE( "queue %p, count %u, submits %p, fence %p\n", queue, count, submits, fence );
+ if (!(timelines = mem_alloc( &pool, count * sizeof(*timelines) ))) return VK_ERROR_OUT_OF_HOST_MEMORY; + memset( timelines, 0, count * sizeof(*timelines) ); + for (uint32_t i = 0; i < count; i++) { VkSubmitInfo *submit = (VkSubmitInfo *)submits + i; /* cast away const, chain has been copied in the thunks */ VkBaseOutStructure **next, *prev = (VkBaseOutStructure *)submit; + VkTimelineSemaphoreSubmitInfo *timeline = timelines + i; VkSemaphore *wait_semaphores, *signal_semaphores; - VkTimelineSemaphoreSubmitInfo *timeline = NULL; VkDeviceGroupSubmitInfo *device_group = NULL; UINT wait_count = 0, signal_count = 0; VkPipelineStageFlags *wait_stages; @@ -1456,7 +1460,9 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: break; case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO: break; case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: - timeline = (VkTimelineSemaphoreSubmitInfo *)*next; + if (timeline->sType) ERR( "Duplicated timeline semaphore submit info!\n" ); + *timeline = *(VkTimelineSemaphoreSubmitInfo *)*next; + *next = (*next)->pNext; next = &prev; /* remove it from the chain, we'll add it back below */ break; case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR: { @@ -1481,13 +1487,10 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons memcpy( wait_stages, submit->pWaitDstStageMask, submit->waitSemaphoreCount * sizeof(*wait_stages) ); submit->pWaitDstStageMask = wait_stages;
- if (timeline) - { - if (!(values = mem_alloc( &pool, (timeline->waitSemaphoreValueCount + wait_count) * sizeof(*values) ))) goto failed; - memcpy( values, timeline->pWaitSemaphoreValues, timeline->waitSemaphoreValueCount * sizeof(*values) ); - timeline->waitSemaphoreValueCount = submit->waitSemaphoreCount; - timeline->pWaitSemaphoreValues = values; - } + if (!(values = mem_alloc( &pool, (timeline->waitSemaphoreValueCount + wait_count) * sizeof(*values) ))) goto failed; + memcpy( values, timeline->pWaitSemaphoreValues, timeline->waitSemaphoreValueCount * sizeof(*values) ); + timeline->waitSemaphoreValueCount = submit->waitSemaphoreCount; + timeline->pWaitSemaphoreValues = values;
if (device_group) { @@ -1504,13 +1507,10 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons memcpy( signal_semaphores, submit->pSignalSemaphores, submit->signalSemaphoreCount * sizeof(*signal_semaphores) ); submit->pSignalSemaphores = signal_semaphores;
- if (timeline) - { - if (!(values = mem_alloc( &pool, submit->signalSemaphoreCount * sizeof(*values) ))) goto failed; - memcpy( values, timeline->pSignalSemaphoreValues, timeline->signalSemaphoreValueCount * sizeof(*values) ); - timeline->signalSemaphoreValueCount = submit->signalSemaphoreCount; - timeline->pSignalSemaphoreValues = values; - } + if (!(values = mem_alloc( &pool, submit->signalSemaphoreCount * sizeof(*values) ))) goto failed; + memcpy( values, timeline->pSignalSemaphoreValues, timeline->signalSemaphoreValueCount * sizeof(*values) ); + timeline->signalSemaphoreValueCount = submit->signalSemaphoreCount; + timeline->pSignalSemaphoreValues = values;
if (device_group) { @@ -1520,6 +1520,14 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons device_group->pSignalSemaphoreDeviceIndices = indexes; } } + + /* insert the timeline semaphore values in the chain if it was there */ + if (timeline->sType) + { + timeline->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline->pNext = submit->pNext; + submit->pNext = timeline; + } }
res = device->p_vkQueueSubmit( queue->host.queue, count, submits, fence ? fence->host.fence : 0 );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 144 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 137 insertions(+), 7 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index bab97bd435d..47ceee74afb 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -106,6 +106,7 @@ struct device_memory D3DKMT_HANDLE sync; D3DKMT_HANDLE mutex; VkSemaphore semaphore; + UINT64 semaphore_value; };
static inline struct device_memory *device_memory_from_handle( VkDeviceMemory handle ) @@ -1396,6 +1397,112 @@ static VkResult win32u_vkQueuePresentKHR( VkQueue client_queue, const VkPresentI return res; }
+static LARGE_INTEGER *get_nt_timeout( LARGE_INTEGER *time, DWORD timeout ) +{ + if (timeout == INFINITE) return NULL; + time->QuadPart = (ULONGLONG)timeout * -10000; + return time; +} + +static VkResult acquire_keyed_mutexes( VkWin32KeyedMutexAcquireReleaseInfoKHR *mutex_info, struct mempool *pool, + const VkSemaphoreSubmitInfo **semaphores, UINT *semaphores_count ) +{ + UINT i, count = *semaphores_count; + VkSemaphoreSubmitInfo *submits; + NTSTATUS status; + + if (!(submits = mem_alloc( pool, (count + mutex_info->acquireCount) * sizeof(*submits) ))) return VK_ERROR_OUT_OF_HOST_MEMORY; + memcpy( submits, *semaphores, count * sizeof(*submits) ); + memset( submits + count, 0, mutex_info->acquireCount * sizeof(*submits) ); + + for (i = 0; i < mutex_info->acquireCount; i++) + { + LARGE_INTEGER timeout; + struct device_memory *memory = device_memory_from_handle( mutex_info->pAcquireSyncs[i] ); + D3DKMT_ACQUIREKEYEDMUTEX acquire = + { + .hKeyedMutex = memory->mutex, + .Key = mutex_info->pAcquireKeys[i], + .pTimeout = get_nt_timeout( &timeout, mutex_info->pAcquireTimeouts[i] ), + }; + VkSemaphoreSubmitInfo submit = + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = memory->semaphore, + .stageMask = 0, + .deviceIndex = 0, + }; + + if ((status = NtGdiDdDDIAcquireKeyedMutex( &acquire ))) goto error; + submit.value = memory->semaphore_value = acquire.FenceValue; + submits[count++] = submit; + } + + *semaphores = submits; + *semaphores_count = count; + return VK_SUCCESS; + +error: + WARN( "Failed to acquire keyed mutex 0x%s key 0x%s, status %#x\n", wine_dbgstr_longlong( mutex_info->pAcquireSyncs[i] ), + wine_dbgstr_longlong( mutex_info->pAcquireKeys[i] ), status ); + + while (i--) + { + struct device_memory *memory = device_memory_from_handle( mutex_info->pAcquireSyncs[i] ); + D3DKMT_RELEASEKEYEDMUTEX release = + { + .hKeyedMutex = memory->mutex, + .Key = mutex_info->pAcquireKeys[i], + .FenceValue = memory->semaphore_value, + }; + NtGdiDdDDIReleaseKeyedMutex( &release ); + } + return status == STATUS_TIMEOUT ? VK_TIMEOUT : VK_ERROR_UNKNOWN; +} + +static VkResult release_keyed_mutexes( VkWin32KeyedMutexAcquireReleaseInfoKHR *mutex_info, struct mempool *pool, + const VkSemaphoreSubmitInfo **semaphores, UINT *semaphores_count ) +{ + UINT i, count = *semaphores_count; + VkSemaphoreSubmitInfo *submits; + NTSTATUS status; + + if (!(submits = mem_alloc( pool, (count + mutex_info->releaseCount) * sizeof(*submits) ))) return VK_ERROR_OUT_OF_HOST_MEMORY; + memcpy( submits, *semaphores, count * sizeof(*submits) ); + memset( submits + count, 0, mutex_info->releaseCount * sizeof(*submits) ); + + for (i = 0; i < mutex_info->releaseCount; i++) + { + struct device_memory *memory = device_memory_from_handle( mutex_info->pReleaseSyncs[i] ); + D3DKMT_RELEASEKEYEDMUTEX release = + { + .hKeyedMutex = memory->mutex, + .Key = mutex_info->pReleaseKeys[i], + .FenceValue = memory->semaphore_value + 1, + }; + VkSemaphoreSubmitInfo submit = + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = memory->semaphore, + .stageMask = 0, + .deviceIndex = 0, + }; + + if ((status = NtGdiDdDDIReleaseKeyedMutex( &release ))) goto failed; + submit.value = memory->semaphore_value + 1; + submits[count++] = submit; + } + + *semaphores = submits; + *semaphores_count = count; + return VK_SUCCESS; + +failed: + WARN( "Failed to release keyed mutex 0x%s key 0x%s, status %#x\n", wine_dbgstr_longlong( mutex_info->pReleaseSyncs[i] ), + wine_dbgstr_longlong( mutex_info->pReleaseKeys[i] ), status ); + return VK_ERROR_UNKNOWN; +} + static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, const VkSubmitInfo *submits, VkFence client_fence ) { struct vulkan_fence *fence = client_fence ? vulkan_fence_from_handle( client_fence ) : NULL; @@ -1413,6 +1520,7 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons for (uint32_t i = 0; i < count; i++) { VkSubmitInfo *submit = (VkSubmitInfo *)submits + i; /* cast away const, chain has been copied in the thunks */ + const VkSemaphoreSubmitInfo *wait_infos = NULL, *signal_infos = NULL; VkBaseOutStructure **next, *prev = (VkBaseOutStructure *)submit; VkTimelineSemaphoreSubmitInfo *timeline = timelines + i; VkSemaphore *wait_semaphores, *signal_semaphores; @@ -1467,9 +1575,8 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR: { VkWin32KeyedMutexAcquireReleaseInfoKHR *mutex_info = (VkWin32KeyedMutexAcquireReleaseInfoKHR *)*next; - FIXME( "VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR not implemented!\n" ); - wait_count = mutex_info->acquireCount; - signal_count = mutex_info->releaseCount; + if ((res = acquire_keyed_mutexes( mutex_info, &pool, &wait_infos, &wait_count ))) goto failed; + if ((res = release_keyed_mutexes( mutex_info, &pool, &signal_infos, &signal_count ))) goto failed; *next = (*next)->pNext; next = &prev; break; } @@ -1487,8 +1594,16 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons memcpy( wait_stages, submit->pWaitDstStageMask, submit->waitSemaphoreCount * sizeof(*wait_stages) ); submit->pWaitDstStageMask = wait_stages;
+ for (uint32_t j = 0; j < wait_count; j++) + { + wait_semaphores[submit->waitSemaphoreCount + j] = wait_infos[j].semaphore; + wait_stages[submit->waitSemaphoreCount + j] = wait_infos[j].stageMask; + } + submit->waitSemaphoreCount += wait_count; + if (!(values = mem_alloc( &pool, (timeline->waitSemaphoreValueCount + wait_count) * sizeof(*values) ))) goto failed; memcpy( values, timeline->pWaitSemaphoreValues, timeline->waitSemaphoreValueCount * sizeof(*values) ); + for (uint32_t j = 0; j < wait_count; j++) values[submit->waitSemaphoreCount + j] = wait_infos[j].value; timeline->waitSemaphoreValueCount = submit->waitSemaphoreCount; timeline->pWaitSemaphoreValues = values;
@@ -1496,6 +1611,7 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons { if (!(indexes = mem_alloc( &pool, submit->waitSemaphoreCount * sizeof(*indexes) ))) goto failed; memcpy( indexes, device_group->pWaitSemaphoreDeviceIndices, device_group->waitSemaphoreCount * sizeof(*indexes) ); + for (uint32_t j = 0; j < wait_count; j++) indexes[device_group->waitSemaphoreCount + j] = wait_infos[j].deviceIndex; device_group->waitSemaphoreCount = submit->waitSemaphoreCount; device_group->pWaitSemaphoreDeviceIndices = indexes; } @@ -1505,10 +1621,13 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons { if (!(signal_semaphores = mem_alloc( &pool, (submit->signalSemaphoreCount + signal_count) * sizeof(*signal_semaphores) ))) goto failed; memcpy( signal_semaphores, submit->pSignalSemaphores, submit->signalSemaphoreCount * sizeof(*signal_semaphores) ); + for (uint32_t j = 0; j < signal_count; j++) signal_semaphores[submit->signalSemaphoreCount + j] = signal_infos[j].semaphore; + submit->signalSemaphoreCount += signal_count; submit->pSignalSemaphores = signal_semaphores;
if (!(values = mem_alloc( &pool, submit->signalSemaphoreCount * sizeof(*values) ))) goto failed; memcpy( values, timeline->pSignalSemaphoreValues, timeline->signalSemaphoreValueCount * sizeof(*values) ); + for (uint32_t j = 0; j < signal_count; j++) values[submit->signalSemaphoreCount + j] = signal_infos[j].value; timeline->signalSemaphoreValueCount = submit->signalSemaphoreCount; timeline->pSignalSemaphoreValues = values;
@@ -1516,13 +1635,14 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons { if (!(indexes = mem_alloc( &pool, submit->signalSemaphoreCount * sizeof(*indexes) ))) goto failed; memcpy( indexes, device_group->pSignalSemaphoreDeviceIndices, device_group->signalSemaphoreCount * sizeof(*indexes) ); + for (uint32_t j = 0; j < signal_count; j++) indexes[device_group->signalSemaphoreCount + j] = signal_infos[j].deviceIndex; device_group->signalSemaphoreCount = submit->signalSemaphoreCount; device_group->pSignalSemaphoreDeviceIndices = indexes; } }
- /* insert the timeline semaphore values in the chain if it was there */ - if (timeline->sType) + /* insert the timeline semaphore values in the chain if it was there or has been created */ + if (timeline->sType || wait_count || signal_count) { timeline->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; timeline->pNext = submit->pNext; @@ -1542,6 +1662,8 @@ static VkResult win32u_vkQueueSubmit2( VkQueue client_queue, uint32_t count, con struct vulkan_fence *fence = client_fence ? vulkan_fence_from_handle( client_fence ) : NULL; struct vulkan_queue *queue = vulkan_queue_from_handle( client_queue ); struct vulkan_device *device = queue->device; + struct mempool pool = {0}; + VkResult res;
TRACE( "queue %p, count %u, submits %p, fence %p\n", queue, count, submits, fence );
@@ -1583,15 +1705,23 @@ static VkResult win32u_vkQueueSubmit2( VkQueue client_queue, uint32_t count, con case VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV: break; case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: break; case VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR: - FIXME( "VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR not implemented!\n" ); + { + VkWin32KeyedMutexAcquireReleaseInfoKHR *mutex_info = (VkWin32KeyedMutexAcquireReleaseInfoKHR *)*next; + if ((res = acquire_keyed_mutexes( mutex_info, &pool, &submit->pWaitSemaphoreInfos, &submit->waitSemaphoreInfoCount ))) goto failed; + if ((res = release_keyed_mutexes( mutex_info, &pool, &submit->pSignalSemaphoreInfos, &submit->signalSemaphoreInfoCount ))) goto failed; *next = (*next)->pNext; next = &prev; break; + } default: FIXME( "Unhandled sType %u.\n", (*next)->sType ); break; } } }
- return device->p_vkQueueSubmit2( queue->host.queue, count, submits, fence ? fence->host.fence : 0 ); + res = device->p_vkQueueSubmit2( queue->host.queue, count, submits, fence ? fence->host.fence : 0 ); + +failed: + mem_free( &pool ); + return res; }
static HANDLE create_shared_semaphore_handle( D3DKMT_HANDLE local, const VkExportSemaphoreWin32HandleInfoKHR *info )