This implements all remaining unsupported image view dimensions and saves a small amount of resources because null buffers and images are no longer needed. It matches the D3D12 requirement that all reads return zero, which is not strictly true of the existing implementation using resources of small but non-zero size. Warnings on null view creation are silenced because there should no longer be a difference from D3D12 behaviour.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- README | 2 +- configure.ac | 2 +- libs/vkd3d/device.c | 8 ++++ libs/vkd3d/resource.c | 76 +++++++++++++++++++++++++------------- libs/vkd3d/vkd3d_private.h | 1 + 5 files changed, 61 insertions(+), 28 deletions(-)
diff --git a/README b/README index 066a24bc..465d5f91 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ similar, but not identical, to Direct3D 12. Building vkd3d ==============
-Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.1.113). +Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.2.139).
Vkd3d generates some of its headers from IDL files. If you are using the release tarballs, then these headers are pre-generated and are included. If diff --git a/configure.ac b/configure.ac index 53029d2c..308bdda1 100644 --- a/configure.ac +++ b/configure.ac @@ -81,7 +81,7 @@ AS_IF([test "x$ac_cv_header_spirv_unified1_GLSL_std_450_h" != "xyes" \ -a "x$ac_cv_header_vulkan_GLSL_std_450_h" != "xyes"], [AC_MSG_ERROR([GLSL.std.450.h not found.])])
-VKD3D_CHECK_VULKAN_HEADER_VERSION([113], [AC_MSG_ERROR([Vulkan headers are too old, 1.1.113 is required.])]) +VKD3D_CHECK_VULKAN_HEADER_VERSION([139], [AC_MSG_ERROR([Vulkan headers are too old, 1.2.139 is required.])])
AC_CHECK_DECL([SpvCapabilityDemoteToHelperInvocationEXT],, [AC_MSG_ERROR([SPIR-V headers are too old.])], [ #ifdef HAVE_SPIRV_UNIFIED1_SPIRV_H diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index d1629284..eb470c12 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -135,6 +135,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker), VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable), VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing), + VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2), VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation), VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export), VK_EXTENSION(EXT_TEXEL_BUFFER_ALIGNMENT, EXT_texel_buffer_alignment), @@ -797,6 +798,7 @@ struct vkd3d_physical_device_info VkPhysicalDeviceConditionalRenderingFeaturesEXT conditional_rendering_features; VkPhysicalDeviceDepthClipEnableFeaturesEXT depth_clip_features; VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_features; + VkPhysicalDeviceRobustness2FeaturesEXT robustness2_features; VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote_features; VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT texel_buffer_alignment_features; VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features; @@ -813,6 +815,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *vertex_divisor_properties; VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *buffer_alignment_properties; VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features; + VkPhysicalDeviceRobustness2FeaturesEXT *robustness2_features; VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features; VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features; VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features; @@ -827,6 +830,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i conditional_rendering_features = &info->conditional_rendering_features; depth_clip_features = &info->depth_clip_features; descriptor_indexing_features = &info->descriptor_indexing_features; + robustness2_features = &info->robustness2_features; descriptor_indexing_properties = &info->descriptor_indexing_properties; maintenance3_properties = &info->maintenance3_properties; demote_features = &info->demote_features; @@ -845,6 +849,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i vk_prepend_struct(&info->features2, depth_clip_features); descriptor_indexing_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; vk_prepend_struct(&info->features2, descriptor_indexing_features); + robustness2_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; + vk_prepend_struct(&info->features2, robustness2_features); demote_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT; vk_prepend_struct(&info->features2, demote_features); buffer_alignment_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT; @@ -1577,6 +1583,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device, vulkan_info->EXT_conditional_rendering = false; if (!physical_device_info->depth_clip_features.depthClipEnable) vulkan_info->EXT_depth_clip_enable = false; + if (!physical_device_info->robustness2_features.nullDescriptor) + vulkan_info->EXT_robustness2 = false; if (!physical_device_info->demote_features.shaderDemoteToHelperInvocation) vulkan_info->EXT_shader_demote_to_helper_invocation = false; if (!physical_device_info->texel_buffer_alignment_features.texelBufferAlignment) diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index cbbd4170..3c4aa53d 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -2423,10 +2423,10 @@ bool vkd3d_create_buffer_view(struct d3d12_device *device, VkBuffer vk_buffer, c VkDeviceSize offset, VkDeviceSize size, struct vkd3d_view **view) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VkBufferView vk_view = VK_NULL_HANDLE; struct vkd3d_view *object; - VkBufferView vk_view;
- if (!vkd3d_create_vk_buffer_view(device, vk_buffer, format, offset, size, &vk_view)) + if (vk_buffer && !vkd3d_create_vk_buffer_view(device, vk_buffer, format, offset, size, &vk_view)) return false;
if (!(object = vkd3d_view_create(VKD3D_VIEW_TYPE_BUFFER))) @@ -2711,28 +2711,31 @@ bool vkd3d_create_texture_view(struct d3d12_device *device, VkImage vk_image, const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; const struct vkd3d_format *format = desc->format; struct VkImageViewCreateInfo view_desc; + VkImageView vk_view = VK_NULL_HANDLE; struct vkd3d_view *object; - VkImageView vk_view; VkResult vr;
- view_desc.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - view_desc.pNext = NULL; - view_desc.flags = 0; - view_desc.image = vk_image; - view_desc.viewType = desc->view_type; - view_desc.format = format->vk_format; - vkd3d_set_view_swizzle_for_format(&view_desc.components, format, desc->allowed_swizzle); - if (desc->allowed_swizzle) - vk_component_mapping_compose(&view_desc.components, &desc->components); - view_desc.subresourceRange.aspectMask = desc->vk_image_aspect; - view_desc.subresourceRange.baseMipLevel = desc->miplevel_idx; - view_desc.subresourceRange.levelCount = desc->miplevel_count; - view_desc.subresourceRange.baseArrayLayer = desc->layer_idx; - view_desc.subresourceRange.layerCount = desc->layer_count; - if ((vr = VK_CALL(vkCreateImageView(device->vk_device, &view_desc, NULL, &vk_view))) < 0) - { - WARN("Failed to create Vulkan image view, vr %d.\n", vr); - return false; + if (vk_image) + { + view_desc.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_desc.pNext = NULL; + view_desc.flags = 0; + view_desc.image = vk_image; + view_desc.viewType = desc->view_type; + view_desc.format = format->vk_format; + vkd3d_set_view_swizzle_for_format(&view_desc.components, format, desc->allowed_swizzle); + if (desc->allowed_swizzle) + vk_component_mapping_compose(&view_desc.components, &desc->components); + view_desc.subresourceRange.aspectMask = desc->vk_image_aspect; + view_desc.subresourceRange.baseMipLevel = desc->miplevel_idx; + view_desc.subresourceRange.levelCount = desc->miplevel_count; + view_desc.subresourceRange.baseArrayLayer = desc->layer_idx; + view_desc.subresourceRange.layerCount = desc->layer_count; + if ((vr = VK_CALL(vkCreateImageView(device->vk_device, &view_desc, NULL, &vk_view))) < 0) + { + WARN("Failed to create Vulkan image view, vr %d.\n", vr); + return false; + } }
if (!(object = vkd3d_view_create(VKD3D_VIEW_TYPE_IMAGE))) @@ -2782,7 +2785,7 @@ void d3d12_desc_create_cbv(struct d3d12_desc *descriptor, /* NULL descriptor */ buffer_info->buffer = device->null_resources.vk_buffer; buffer_info->offset = 0; - buffer_info->range = VKD3D_NULL_BUFFER_SIZE; + buffer_info->range = VK_WHOLE_SIZE; }
descriptor->magic = VKD3D_DESCRIPTOR_MAGIC_CBV; @@ -2815,7 +2818,8 @@ static void vkd3d_create_null_srv(struct d3d12_desc *descriptor, switch (desc->ViewDimension) { case D3D12_SRV_DIMENSION_BUFFER: - WARN("Creating NULL buffer SRV %#x.\n", desc->Format); + if (!device->vk_info.EXT_robustness2) + WARN("Creating NULL buffer SRV %#x.\n", desc->Format);
if (vkd3d_create_buffer_view(device, null_resources->vk_buffer, vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false), @@ -2838,11 +2842,19 @@ static void vkd3d_create_null_srv(struct d3d12_desc *descriptor, break;
default: + if (device->vk_info.EXT_robustness2) + { + vk_image = VK_NULL_HANDLE; + /* view_type is not used for Vulkan null descriptors, but make it valid. */ + vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D; + break; + } FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension); return; }
- WARN("Creating NULL SRV %#x.\n", desc->ViewDimension); + if (!device->vk_info.EXT_robustness2) + WARN("Creating NULL SRV %#x.\n", desc->ViewDimension);
vkd3d_desc.format = vkd3d_get_format(device, VKD3D_NULL_VIEW_FORMAT, false); vkd3d_desc.miplevel_idx = 0; @@ -3052,7 +3064,8 @@ static void vkd3d_create_null_uav(struct d3d12_desc *descriptor, switch (desc->ViewDimension) { case D3D12_UAV_DIMENSION_BUFFER: - WARN("Creating NULL buffer UAV %#x.\n", desc->Format); + if (!device->vk_info.EXT_robustness2) + WARN("Creating NULL buffer UAV %#x.\n", desc->Format);
if (vkd3d_create_buffer_view(device, null_resources->vk_storage_buffer, vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false), @@ -3075,11 +3088,19 @@ static void vkd3d_create_null_uav(struct d3d12_desc *descriptor, break;
default: + if (device->vk_info.EXT_robustness2) + { + vk_image = VK_NULL_HANDLE; + /* view_type is not used for Vulkan null descriptors, but make it valid. */ + vkd3d_desc.view_type = VK_IMAGE_VIEW_TYPE_2D; + break; + } FIXME("Unhandled view dimension %#x.\n", desc->ViewDimension); return; }
- WARN("Creating NULL UAV %#x.\n", desc->ViewDimension); + if (!device->vk_info.EXT_robustness2) + WARN("Creating NULL UAV %#x.\n", desc->ViewDimension);
vkd3d_desc.format = vkd3d_get_format(device, VKD3D_NULL_VIEW_FORMAT, false); vkd3d_desc.miplevel_idx = 0; @@ -4421,6 +4442,9 @@ HRESULT vkd3d_init_null_resources(struct vkd3d_null_resources *null_resources,
memset(null_resources, 0, sizeof(*null_resources));
+ if (device->vk_info.EXT_robustness2) + return S_OK; + memset(&heap_properties, 0, sizeof(heap_properties)); heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index c28eb234..796dfefd 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -131,6 +131,7 @@ struct vkd3d_vulkan_info bool EXT_debug_marker; bool EXT_depth_clip_enable; bool EXT_descriptor_indexing; + bool EXT_robustness2; bool EXT_shader_demote_to_helper_invocation; bool EXT_shader_stencil_export; bool EXT_texel_buffer_alignment;
Binding a shader with the wrong null descriptor type works in Windows. The introduction of Vulkan-backed heaps may cause a regression in clients which do this, because the written index will remain unpopulated in all other sets, but a shader may access it in one of them.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/resource.c | 55 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 3c4aa53d..5d7f42d0 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -2131,6 +2131,7 @@ void vkd3d_view_decref(struct vkd3d_view *view, struct d3d12_device *device) vkd3d_view_destroy(view, device); }
+/* TODO: write null descriptors to all applicable sets (invalid behaviour workaround). */ static void d3d12_descriptor_heap_write_vk_descriptor_range(struct d3d12_descriptor_heap_vk_set *descriptor_set, struct d3d12_desc_copy_location *locations, unsigned int write_count) { @@ -2178,6 +2179,47 @@ static void d3d12_descriptor_heap_write_vk_descriptor_range(struct d3d12_descrip } }
+static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_heap *descriptor_heap, + uint32_t dst_array_element, const struct d3d12_device *device) +{ + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + struct d3d12_descriptor_heap_vk_set *descriptor_set; + VkBufferView vk_buffer_view = VK_NULL_HANDLE; + enum vkd3d_vk_descriptor_set_index i; + VkDescriptorBufferInfo vk_cbv_info; + + vk_cbv_info.buffer = VK_NULL_HANDLE; + vk_cbv_info.offset = 0; + vk_cbv_info.range = VK_WHOLE_SIZE; + + /* Binding a shader with the wrong null descriptor type works in Windows. + * To support that here we must write one to all applicable Vulkan sets. */ + for (i = VKD3D_SET_INDEX_UNIFORM_BUFFER; i <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++i) + { + descriptor_set = &descriptor_heap->vk_descriptor_sets[i]; + descriptor_set->vk_descriptor_writes[0].dstArrayElement = dst_array_element; + descriptor_set->vk_descriptor_writes[0].descriptorCount = 1; + switch (i) + { + case VKD3D_SET_INDEX_UNIFORM_BUFFER: + descriptor_set->vk_descriptor_writes[0].pBufferInfo = &vk_cbv_info; + break; + case VKD3D_SET_INDEX_SAMPLED_IMAGE: + case VKD3D_SET_INDEX_STORAGE_IMAGE: + descriptor_set->vk_image_infos[0].imageView = VK_NULL_HANDLE; + break; + case VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER: + case VKD3D_SET_INDEX_STORAGE_TEXEL_BUFFER: + descriptor_set->vk_descriptor_writes[0].pTexelBufferView = &vk_buffer_view; + break; + default: + assert(false); + break; + } + VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, descriptor_set->vk_descriptor_writes, 0, NULL)); + } +} + /* dst and src contain the same data unless another thread overwrites dst. The array index is * calculated from dst, and src is thread safe. */ static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct d3d12_desc *src, @@ -2186,6 +2228,7 @@ static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct struct d3d12_descriptor_heap_vk_set *descriptor_set; struct d3d12_descriptor_heap *descriptor_heap; const struct vkd3d_vk_device_procs *vk_procs; + bool is_null = false;
descriptor_heap = vkd3d_gpu_descriptor_allocator_heap_from_descriptor(&device->gpu_descriptor_allocator, dst); descriptor_set = &descriptor_heap->vk_descriptor_sets[vkd3d_vk_descriptor_set_index_from_vk_descriptor_type( @@ -2201,14 +2244,16 @@ static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct { case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: descriptor_set->vk_descriptor_writes[0].pBufferInfo = &src->u.vk_cbv_info; + is_null = !src->u.vk_cbv_info.buffer; break; case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - descriptor_set->vk_image_infos[0].imageView = src->u.view_info.view->u.vk_image_view; + is_null = !(descriptor_set->vk_image_infos[0].imageView = src->u.view_info.view->u.vk_image_view); break; case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: descriptor_set->vk_descriptor_writes[0].pTexelBufferView = &src->u.view_info.view->u.vk_buffer_view; + is_null = !src->u.view_info.view->u.vk_buffer_view; break; case VK_DESCRIPTOR_TYPE_SAMPLER: descriptor_set->vk_image_infos[0].sampler = src->u.view_info.view->u.vk_sampler; @@ -2217,6 +2262,14 @@ static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct ERR("Unhandled descriptor type %#x.\n", src->vk_descriptor_type); break; } + if (is_null && device->vk_info.EXT_robustness2) + { + d3d12_desc_write_vk_heap_null_descriptor(descriptor_heap, + descriptor_set->vk_descriptor_writes[0].dstArrayElement, device); + vkd3d_mutex_unlock(&descriptor_heap->vk_sets_mutex); + return; + } + VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, descriptor_set->vk_descriptor_writes, 0, NULL));
if (src->magic == VKD3D_DESCRIPTOR_MAGIC_UAV && src->u.view_info.view->vk_counter_view)
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=111127
Your paranoid android.
=== debian11 (build log) ===
error: patch failed: README:9 error: patch failed: configure.ac:81 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: README:9 error: patch failed: configure.ac:81 Task: Patch failed to apply