From: Józef Kucia jkucia@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com ---
We could generate format info tables from a single source. Code generation could also be beneficial in other modules, e.g. SPIR-V builder functions could be generated.
--- libs/vkd3d/device.c | 11 +- libs/vkd3d/resource.c | 30 +++++ libs/vkd3d/utils.c | 229 ++++++++++++++++++++++++++++++++++++- libs/vkd3d/vkd3d_private.h | 23 +++- 4 files changed, 280 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 0060afe475a3..18c7bf66c8a2 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -124,6 +124,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(KHR_DEDICATED_ALLOCATION, KHR_dedicated_allocation), VK_EXTENSION(KHR_DRAW_INDIRECT_COUNT, KHR_draw_indirect_count), VK_EXTENSION(KHR_GET_MEMORY_REQUIREMENTS_2, KHR_get_memory_requirements2), + VK_EXTENSION(KHR_IMAGE_FORMAT_LIST, KHR_image_format_list), VK_EXTENSION(KHR_MAINTENANCE3, KHR_maintenance3), VK_EXTENSION(KHR_PUSH_DESCRIPTOR, KHR_push_descriptor), /* EXT extensions */ @@ -1989,7 +1990,7 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface)
vkd3d_private_store_destroy(&device->private_store);
- vkd3d_cleanup_depth_stencil_formats(device); + vkd3d_cleanup_format_info(device); vkd3d_destroy_null_resources(&device->null_resources, device); vkd3d_gpu_va_allocator_cleanup(&device->gpu_va_allocator); vkd3d_render_pass_cache_cleanup(&device->render_pass_cache, device); @@ -3218,11 +3219,11 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, if (FAILED(hr = vkd3d_fence_worker_start(&device->fence_worker, device))) goto out_free_private_store;
- if (FAILED(hr = vkd3d_init_depth_stencil_formats(device))) + if (FAILED(hr = vkd3d_init_format_info(device))) goto out_stop_fence_worker;
if (FAILED(hr = vkd3d_init_null_resources(&device->null_resources, device))) - goto out_cleanup_depth_stencil_formats; + goto out_cleanup_format_info;
vkd3d_render_pass_cache_init(&device->render_pass_cache); vkd3d_gpu_va_allocator_init(&device->gpu_va_allocator); @@ -3232,8 +3233,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
return S_OK;
-out_cleanup_depth_stencil_formats: - vkd3d_cleanup_depth_stencil_formats(device); +out_cleanup_format_info: + vkd3d_cleanup_format_info(device); out_stop_fence_worker: vkd3d_fence_worker_stop(&device->fence_worker, device); out_free_private_store: diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 0f7ce5ee702f..3a4eefebf78d 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -781,12 +781,28 @@ static unsigned int max_miplevel_count(const D3D12_RESOURCE_DESC *desc) return vkd3d_log2i(size) + 1; }
+static const struct vkd3d_format_compatibility_list *vkd3d_get_format_compatibility_list( + const struct d3d12_device *device, DXGI_FORMAT dxgi_format) +{ + unsigned int i; + + for (i = 0; i < device->format_compatibility_list_count; ++i) + { + if (device->format_compatibility_lists[i].typeless_format == dxgi_format) + return &device->format_compatibility_lists[i]; + } + + return NULL; +} + static HRESULT vkd3d_create_image(struct d3d12_device *device, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, const D3D12_RESOURCE_DESC *desc, VkImage *vk_image) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + const struct vkd3d_format_compatibility_list *compat_list; const bool sparse_resource = !heap_properties; + VkImageFormatListCreateInfoKHR format_list; const struct vkd3d_format *format; VkImageCreateInfo image_info; VkResult vr; @@ -801,7 +817,21 @@ static HRESULT vkd3d_create_image(struct d3d12_device *device, image_info.pNext = NULL; image_info.flags = 0; if (!(desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) && format->type == VKD3D_FORMAT_TYPE_TYPELESS) + { image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + + /* Format compatibility rules are more relaxed for UAVs. */ + if (!(desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) + && (compat_list = vkd3d_get_format_compatibility_list(device, desc->Format))) + { + format_list.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; + format_list.pNext = NULL; + format_list.viewFormatCount = compat_list->format_count; + format_list.pViewFormats = compat_list->vk_formats; + + image_info.pNext = &format_list; + } + } if (desc->Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc->Width == desc->Height && desc->DepthOrArraySize >= 6 && desc->SampleDesc.Count == 1) diff --git a/libs/vkd3d/utils.c b/libs/vkd3d/utils.c index cdc55126d197..0329499ff771 100644 --- a/libs/vkd3d/utils.c +++ b/libs/vkd3d/utils.c @@ -139,7 +139,213 @@ static const struct vkd3d_format vkd3d_depth_stencil_formats[] = #undef SINT #undef UINT
-HRESULT vkd3d_init_depth_stencil_formats(struct d3d12_device *device) +static const struct vkd3d_format_compatibility_info +{ + DXGI_FORMAT format; + DXGI_FORMAT typeless_format; +} +vkd3d_format_compatibility_info[] = +{ + /* DXGI_FORMAT_R32G32B32A32_TYPELESS */ + {DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_TYPELESS}, + {DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_TYPELESS}, + {DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_TYPELESS}, + /* DXGI_FORMAT_R32G32B32_TYPELESS */ + {DXGI_FORMAT_R32G32B32_UINT, DXGI_FORMAT_R32G32B32_TYPELESS}, + {DXGI_FORMAT_R32G32B32_SINT, DXGI_FORMAT_R32G32B32_TYPELESS}, + {DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R32G32B32_TYPELESS}, + /* DXGI_FORMAT_R16G16B16A16_TYPELESS */ + {DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_TYPELESS}, + {DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16B16A16_TYPELESS}, + {DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_TYPELESS}, + {DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_TYPELESS}, + {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_TYPELESS}, + /* DXGI_FORMAT_R32G32_TYPELESS */ + {DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_TYPELESS}, + {DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_TYPELESS}, + {DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_TYPELESS}, + /* DXGI_FORMAT_R32G8X24_TYPELESS */ + {DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_R32G8X24_TYPELESS}, + {DXGI_FORMAT_X32_TYPELESS_G8X24_UINT, DXGI_FORMAT_R32G8X24_TYPELESS}, + {DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGI_FORMAT_R32G8X24_TYPELESS}, + /* DXGI_FORMAT_R10G10B10A2_TYPELESS */ + {DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_TYPELESS}, + {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_TYPELESS}, + /* DXGI_FORMAT_R8G8B8A8_TYPELESS */ + {DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_TYPELESS}, + {DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_TYPELESS}, + {DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_TYPELESS}, + {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_TYPELESS}, + {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_TYPELESS}, + /* DXGI_FORMAT_R16G16_TYPELESS */ + {DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16_TYPELESS}, + {DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16_TYPELESS}, + {DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_TYPELESS}, + {DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_TYPELESS}, + {DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_TYPELESS}, + /* DXGI_FORMAT_R32_TYPELESS */ + {DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_R32_TYPELESS}, + {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_TYPELESS}, + {DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_TYPELESS}, + {DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_TYPELESS}, + /* DXGI_FORMAT_R24G8_TYPELESS */ + {DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_R24G8_TYPELESS}, + {DXGI_FORMAT_X24_TYPELESS_G8_UINT, DXGI_FORMAT_R24G8_TYPELESS}, + {DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_R24G8_TYPELESS}, + /* DXGI_FORMAT_R8G8_TYPELESS */ + {DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_TYPELESS}, + {DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_TYPELESS}, + {DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_TYPELESS}, + {DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_TYPELESS}, + /* DXGI_FORMAT_R16_TYPELESS */ + {DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_R16_TYPELESS}, + {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_TYPELESS}, + {DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_TYPELESS}, + {DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_TYPELESS}, + {DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_TYPELESS}, + {DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_TYPELESS}, + /* DXGI_FORMAT_R8_TYPELESS */ + {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_TYPELESS}, + {DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_TYPELESS}, + {DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_TYPELESS}, + {DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_TYPELESS}, + /* DXGI_FORMAT_BC1_TYPELESS */ + {DXGI_FORMAT_BC1_UNORM_SRGB, DXGI_FORMAT_BC1_TYPELESS}, + {DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_TYPELESS}, + /* DXGI_FORMAT_BC2_TYPELESS */ + {DXGI_FORMAT_BC2_UNORM_SRGB, DXGI_FORMAT_BC2_TYPELESS}, + {DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_TYPELESS}, + /* DXGI_FORMAT_BC3_TYPELESS */ + {DXGI_FORMAT_BC3_UNORM_SRGB, DXGI_FORMAT_BC3_TYPELESS}, + {DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_TYPELESS}, + /* DXGI_FORMAT_BC4_TYPELESS */ + {DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_TYPELESS}, + {DXGI_FORMAT_BC4_SNORM, DXGI_FORMAT_BC4_TYPELESS}, + /* DXGI_FORMAT_BC5_TYPELESS */ + {DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_TYPELESS}, + {DXGI_FORMAT_BC5_SNORM, DXGI_FORMAT_BC5_TYPELESS}, + /* DXGI_FORMAT_BC6H_TYPELESS */ + {DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_TYPELESS}, + {DXGI_FORMAT_BC6H_SF16, DXGI_FORMAT_BC6H_TYPELESS}, + /* DXGI_FORMAT_BC7_TYPELESS */ + {DXGI_FORMAT_BC7_UNORM_SRGB, DXGI_FORMAT_BC7_TYPELESS}, + {DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_TYPELESS}, + /* DXGI_FORMAT_B8G8R8A8_TYPELESS */ + {DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_FORMAT_B8G8R8A8_TYPELESS}, + {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_TYPELESS}, + /* DXGI_FORMAT_B8G8R8X8_TYPELESS */ + {DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, DXGI_FORMAT_B8G8R8X8_TYPELESS}, + {DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8X8_TYPELESS}, +}; + +static bool dxgi_format_is_depth_stencil(DXGI_FORMAT dxgi_format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vkd3d_formats); ++i) + { + const struct vkd3d_format *current = &vkd3d_formats[i]; + + if (current->dxgi_format == dxgi_format) + return current->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + } + + for (i = 0; i < ARRAY_SIZE(vkd3d_depth_stencil_formats); ++i) + { + if (vkd3d_depth_stencil_formats[i].dxgi_format == dxgi_format) + return true; + } + + return false; +} + +/* FIXME: This table should be generated at compile-time. */ +static HRESULT vkd3d_init_format_compatibility_lists(struct d3d12_device *device) +{ + struct vkd3d_format_compatibility_list *lists, *current_list; + const struct vkd3d_format_compatibility_info *current; + DXGI_FORMAT dxgi_format; + VkFormat vk_format; + unsigned int count; + unsigned int i, j; + + device->format_compatibility_list_count = 0; + device->format_compatibility_lists = NULL; + + if (!device->vk_info.KHR_image_format_list) + return S_OK; + + count = 1; + dxgi_format = vkd3d_format_compatibility_info[0].typeless_format; + for (i = 0; i < ARRAY_SIZE(vkd3d_format_compatibility_info); ++i) + { + DXGI_FORMAT typeless_format = vkd3d_format_compatibility_info[i].typeless_format; + + if (dxgi_format != typeless_format) + { + ++count; + dxgi_format = typeless_format; + } + } + + if (!(lists = vkd3d_calloc(count, sizeof(*lists)))) + return E_OUTOFMEMORY; + + count = 0; + current_list = lists; + current_list->typeless_format = vkd3d_format_compatibility_info[0].typeless_format; + for (i = 0; i < ARRAY_SIZE(vkd3d_format_compatibility_info); ++i) + { + current = &vkd3d_format_compatibility_info[i]; + + if (current_list->typeless_format != current->typeless_format) + { + /* Avoid empty format lists. */ + if (current_list->format_count) + { + ++current_list; + ++count; + } + + current_list->typeless_format = current->typeless_format; + } + + /* In Vulkan, each depth-stencil format is only compatible with itself. */ + if (dxgi_format_is_depth_stencil(current->format)) + continue; + + if (!(vk_format = vkd3d_get_vk_format(current->format))) + continue; + + for (j = 0; j < current_list->format_count; ++j) + { + if (current_list->vk_formats[j] == vk_format) + break; + } + + if (j >= current_list->format_count) + { + assert(current_list->format_count < VKD3D_MAX_COMPATIBLE_FORMAT_COUNT); + current_list->vk_formats[current_list->format_count++] = vk_format; + } + } + if (current_list->format_count) + ++count; + + device->format_compatibility_list_count = count; + device->format_compatibility_lists = lists; + return S_OK; +} + +static void vkd3d_cleanup_format_compatibility_lists(struct d3d12_device *device) +{ + vkd3d_free((void *)device->format_compatibility_lists); + + device->format_compatibility_lists = NULL; + device->format_compatibility_list_count = 0; +} + +static HRESULT vkd3d_init_depth_stencil_formats(struct d3d12_device *device) { const unsigned int count = ARRAY_SIZE(vkd3d_depth_stencil_formats); const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; @@ -178,7 +384,7 @@ HRESULT vkd3d_init_depth_stencil_formats(struct d3d12_device *device) return S_OK; }
-void vkd3d_cleanup_depth_stencil_formats(struct d3d12_device *device) +static void vkd3d_cleanup_depth_stencil_formats(struct d3d12_device *device) { if (vkd3d_depth_stencil_formats != device->depth_stencil_formats) vkd3d_free((void *)device->depth_stencil_formats); @@ -186,6 +392,25 @@ void vkd3d_cleanup_depth_stencil_formats(struct d3d12_device *device) device->depth_stencil_formats = NULL; }
+HRESULT vkd3d_init_format_info(struct d3d12_device *device) +{ + HRESULT hr; + + if (FAILED(hr = vkd3d_init_depth_stencil_formats(device))) + return hr; + + if FAILED(hr = vkd3d_init_format_compatibility_lists(device)) + vkd3d_cleanup_depth_stencil_formats(device); + + return hr; +} + +void vkd3d_cleanup_format_info(struct d3d12_device *device) +{ + vkd3d_cleanup_depth_stencil_formats(device); + vkd3d_cleanup_format_compatibility_lists(device); +} + /* We use overrides for depth/stencil formats. This is required in order to * properly support typeless formats because depth/stencil formats are only * compatible with themselves in Vulkan. diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 4398351a9054..4f2559c9ade9 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -48,10 +48,11 @@ #define VKD3D_DESCRIPTOR_MAGIC_DSV 0x00565344u #define VKD3D_DESCRIPTOR_MAGIC_RTV 0x00565452u
-#define VKD3D_MAX_QUEUE_FAMILY_COUNT 3u -#define VKD3D_MAX_SHADER_EXTENSIONS 1u -#define VKD3D_MAX_SHADER_STAGES 5u -#define VKD3D_MAX_VK_SYNC_OBJECTS 4u +#define VKD3D_MAX_COMPATIBLE_FORMAT_COUNT 6u +#define VKD3D_MAX_QUEUE_FAMILY_COUNT 3u +#define VKD3D_MAX_SHADER_EXTENSIONS 1u +#define VKD3D_MAX_SHADER_STAGES 5u +#define VKD3D_MAX_VK_SYNC_OBJECTS 4u
struct d3d12_command_list; struct d3d12_device; @@ -96,6 +97,7 @@ struct vkd3d_vulkan_info bool KHR_dedicated_allocation; bool KHR_draw_indirect_count; bool KHR_get_memory_requirements2; + bool KHR_image_format_list; bool KHR_maintenance3; bool KHR_push_descriptor; /* EXT device extensions */ @@ -1029,6 +1031,13 @@ HRESULT vkd3d_init_null_resources(struct vkd3d_null_resources *null_resources, void vkd3d_destroy_null_resources(struct vkd3d_null_resources *null_resources, struct d3d12_device *device) DECLSPEC_HIDDEN;
+struct vkd3d_format_compatibility_list +{ + DXGI_FORMAT typeless_format; + unsigned int format_count; + VkFormat vk_formats[VKD3D_MAX_COMPATIBLE_FORMAT_COUNT]; +}; + /* ID3D12Device */ struct d3d12_device { @@ -1070,6 +1079,8 @@ struct d3d12_device HRESULT removed_reason;
const struct vkd3d_format *depth_stencil_formats; + unsigned int format_compatibility_list_count; + const struct vkd3d_format_compatibility_list *format_compatibility_lists; struct vkd3d_null_resources null_resources; };
@@ -1133,8 +1144,8 @@ static inline bool vkd3d_format_is_compressed(const struct vkd3d_format *format) const struct vkd3d_format *vkd3d_get_format(const struct d3d12_device *device, DXGI_FORMAT dxgi_format, bool depth_stencil) DECLSPEC_HIDDEN;
-HRESULT vkd3d_init_depth_stencil_formats(struct d3d12_device *device) DECLSPEC_HIDDEN; -void vkd3d_cleanup_depth_stencil_formats(struct d3d12_device *device) DECLSPEC_HIDDEN; +HRESULT vkd3d_init_format_info(struct d3d12_device *device) DECLSPEC_HIDDEN; +void vkd3d_cleanup_format_info(struct d3d12_device *device) DECLSPEC_HIDDEN;
static inline const struct vkd3d_format *vkd3d_format_from_d3d12_resource_desc( const struct d3d12_device *device, const D3D12_RESOURCE_DESC *desc, DXGI_FORMAT view_format)