diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index e0e8dd68e4..91bd77dba6 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -4079,9 +4079,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CheckFeatureSupport(d3d12_device_i return E_INVALIDARG; } - data->MSPrimitivesPipelineStatisticIncludesCulledPrimitives = D3D12_TRI_STATE_UNKNOWN; - data->EnhancedBarriersSupported = FALSE; - data->RelaxedFormatCastingSupported = FALSE; + *data = device->d3d12_caps.options12; + TRACE("RelaxedFormatCasting supported %u.\n", data->RelaxedFormatCastingSupported); + TRACE("EnhancedBarriers supported %u.\n", data->EnhancedBarriersSupported); + TRACE("MSPrimitivesPipelineStatisticIncludesCulledPrimitives %u.\n", + data->MSPrimitivesPipelineStatisticIncludesCulledPrimitives); return S_OK; } @@ -5922,7 +5924,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource1(d3d12_devi d3d12_resource_promote_desc(desc, &desc1); if (FAILED(hr = d3d12_resource_create_reserved(device, &desc1, - initial_state, optimized_clear_value, &object))) + initial_state, optimized_clear_value, 0, NULL, &object))) return hr; return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource); @@ -6142,9 +6144,16 @@ static D3D12_RESOURCE_ALLOCATION_INFO* STDMETHODCALLTYPE d3d12_device_GetResourc for (i = 0; i < count; i++) { const D3D12_RESOURCE_DESC1 *desc = &resource_descs[i]; + const DXGI_FORMAT *p_castable_formats = NULL; + UINT num_castable_formats = 0; hasMsaaResource |= desc->SampleDesc.Count > 1; - if (FAILED(d3d12_resource_validate_desc(desc, device))) + if (p_num_castable_formats) + num_castable_formats = p_num_castable_formats[i]; + if (pp_castable_formats) + p_castable_formats = pp_castable_formats[i]; + + if (FAILED(d3d12_resource_validate_desc(desc, num_castable_formats, p_castable_formats, device))) { WARN("Invalid resource desc.\n"); goto invalid; @@ -6157,7 +6166,7 @@ static D3D12_RESOURCE_ALLOCATION_INFO* STDMETHODCALLTYPE d3d12_device_GetResourc } else { - if (FAILED(vkd3d_get_image_allocation_info(device, desc, &resource_info))) + if (FAILED(vkd3d_get_image_allocation_info(device, desc, num_castable_formats, p_castable_formats, &resource_info))) { WARN("Failed to get allocation info for texture.\n"); goto invalid; @@ -6224,7 +6233,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource2(d3d12_dev FIXME("Ignoring protected session %p.\n", protected_session); if (FAILED(hr = d3d12_resource_create_committed(device, desc, heap_properties, - heap_flags, initial_state, optimized_clear_value, NULL, &object))) + heap_flags, initial_state, optimized_clear_value, 0, NULL, NULL, &object))) { if (resource) *resource = NULL; @@ -6250,7 +6259,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePlacedResource1(d3d12_device optimized_clear_value, debugstr_guid(iid), resource); if (FAILED(hr = d3d12_resource_create_placed(device, resource_desc, heap_object, - heap_offset, initial_state, optimized_clear_value, &object))) + heap_offset, initial_state, optimized_clear_value, 0, NULL, &object))) return hr; return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource); @@ -6303,7 +6312,7 @@ static void STDMETHODCALLTYPE d3d12_device_GetCopyableFootprints1(d3d12_device_i goto end; } - if (FAILED(d3d12_resource_validate_desc(desc, device))) + if (FAILED(d3d12_resource_validate_desc(desc, 0, NULL, device))) { WARN("Invalid resource desc.\n"); goto end; @@ -6395,19 +6404,107 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandQueue1(d3d12_device_i return d3d12_device_CreateCommandQueue(iface, desc, iid, command_queue); } +static D3D12_RESOURCE_STATES vkd3d_barrier_layout_to_resource_state(D3D12_BARRIER_LAYOUT layout, D3D12_RESOURCE_FLAGS flags) +{ + if (flags & D3D12_RESOURCE_FLAG_RAYTRACING_ACCELERATION_STRUCTURE) + return D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; + + /* We cannot make meaningful use of the DIRECT_QUEUE and COMPUTE_QUEUE special layouts. + * There is no explicit ownership transfer in D3D12 like in Vulkan, so we have to use CONCURRENT either way. */ + switch (layout) + { + case D3D12_BARRIER_LAYOUT_COMMON: + case D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON: + case D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON: + return D3D12_RESOURCE_STATE_COMMON; + + case D3D12_BARRIER_LAYOUT_GENERIC_READ: + case D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ: + case D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ: + return D3D12_RESOURCE_STATE_GENERIC_READ; + + case D3D12_BARRIER_LAYOUT_RENDER_TARGET: + return D3D12_RESOURCE_STATE_RENDER_TARGET; + case D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS: + case D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS: + case D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS: + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + + case D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE: + return D3D12_RESOURCE_STATE_DEPTH_WRITE; + + case D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ: + return D3D12_RESOURCE_STATE_DEPTH_READ; + + case D3D12_BARRIER_LAYOUT_SHADER_RESOURCE: + case D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE: + return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + case D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE: + return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + + case D3D12_BARRIER_LAYOUT_COPY_SOURCE: + case D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE: + case D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE: + return D3D12_RESOURCE_STATE_COPY_SOURCE; + case D3D12_BARRIER_LAYOUT_COPY_DEST: + case D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST: + case D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_DEST: + return D3D12_RESOURCE_STATE_COPY_DEST; + + case D3D12_BARRIER_LAYOUT_RESOLVE_SOURCE: + return D3D12_RESOURCE_STATE_RESOLVE_SOURCE; + case D3D12_BARRIER_LAYOUT_RESOLVE_DEST: + return D3D12_RESOURCE_STATE_RESOLVE_DEST; + case D3D12_BARRIER_LAYOUT_SHADING_RATE_SOURCE: + return D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE; + + default: + /* Generic fallback. + * It is unclear what the intention of initial layout = D3D12_BARRIER_LAYOUT_UNDEFINED means. + * To be defensive, fall back to COMMON here. The first use of such a resource must be a DISCARD + * barrier either way which will elide any initial transition. */ + return D3D12_RESOURCE_STATE_COMMON; + } +} + static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource3(d3d12_device_iface *iface, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, const D3D12_RESOURCE_DESC1 *desc, D3D12_BARRIER_LAYOUT initial_layout, const D3D12_CLEAR_VALUE *optimized_clear_value, ID3D12ProtectedResourceSession *protected_session, UINT32 num_castable_formats, const DXGI_FORMAT *castable_formats, REFIID iid, void **resource) { - FIXME("iface %p, heap_properties %p, heap_flags %u, desc %p, initial_layout %u, " + struct d3d12_device *device = impl_from_ID3D12Device(iface); + struct d3d12_resource *object; + HRESULT hr; + + TRACE("iface %p, heap_properties %p, heap_flags %u, desc %p, initial_layout %u, " "optimized_clear_value %p, protected_session %p, num_castable_formats %u, " "castable_formats %p, iid %s, resource %p stub!\n", iface, heap_properties, heap_flags, desc, initial_layout, optimized_clear_value, protected_session, num_castable_formats, castable_formats, debugstr_guid(iid), resource); - return E_NOTIMPL; + if (protected_session) + FIXME("Ignoring protected session %p.\n", protected_session); + + if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && initial_layout != D3D12_BARRIER_LAYOUT_UNDEFINED) + { + WARN("Using non-undefined layout for buffer. This is not allowed.\n"); + return E_INVALIDARG; + } + + /* For initial resource state, we cannot make use of the enhanced barrier layouts in any meaningful way. + * Just collapse them into the equivalent legacy layout. + * This can be refactored later if need be. */ + if (FAILED(hr = d3d12_resource_create_committed(device, desc, heap_properties, + heap_flags, vkd3d_barrier_layout_to_resource_state(initial_layout, desc->Flags), + optimized_clear_value, num_castable_formats, castable_formats, NULL, &object))) + { + if (resource) + *resource = NULL; + return hr; + } + + return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource); } static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePlacedResource2(d3d12_device_iface *iface, @@ -6415,12 +6512,28 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePlacedResource2(d3d12_device const D3D12_CLEAR_VALUE *optimized_clear_value, UINT32 num_castable_formats, const DXGI_FORMAT *castable_formats, REFIID iid, void **resource) { - FIXME("iface %p, heap %p, heap_offset %#"PRIx64", desc %p, initial_layout %u, optimized_clear_value %p, " + struct d3d12_heap *heap_object = impl_from_ID3D12Heap(heap); + struct d3d12_device *device = impl_from_ID3D12Device(iface); + struct d3d12_resource *object; + HRESULT hr; + + TRACE("iface %p, heap %p, heap_offset %#"PRIx64", desc %p, initial_layout %u, optimized_clear_value %p, " "num_castable_formats %u, castable_formats %p, iid %s, resource %p stub!\n", iface, heap, heap_offset, desc, initial_layout, optimized_clear_value, num_castable_formats, castable_formats, debugstr_guid(iid), resource); - return E_NOTIMPL; + if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER && initial_layout != D3D12_BARRIER_LAYOUT_UNDEFINED) + { + WARN("Using non-undefined layout for buffer. This is not allowed.\n"); + return E_INVALIDARG; + } + + if (FAILED(hr = d3d12_resource_create_placed(device, desc, heap_object, + heap_offset, vkd3d_barrier_layout_to_resource_state(initial_layout, desc->Flags), + optimized_clear_value, num_castable_formats, castable_formats, &object))) + return hr; + + return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource); } static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource2(d3d12_device_iface *iface, @@ -6428,12 +6541,27 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource2(d3d12_devi ID3D12ProtectedResourceSession *protected_session, UINT32 num_castable_formats, const DXGI_FORMAT *castable_formats, REFIID iid, void **resource) { - FIXME("iface %p, desc %p, initial_layout %u, optimized_clear_value %p, protected_session %p, " + struct d3d12_device *device = impl_from_ID3D12Device(iface); + struct d3d12_resource *object; + D3D12_RESOURCE_DESC1 desc1; + HRESULT hr; + + TRACE("iface %p, desc %p, initial_layout %u, optimized_clear_value %p, protected_session %p, " "num_castable_formats %u, castable_formats %p, iid %s, resource %p stub!\n", iface, desc, initial_layout, optimized_clear_value, protected_session, num_castable_formats, castable_formats, debugstr_guid(iid), resource); - return E_NOTIMPL; + if (protected_session) + FIXME("Ignoring protected session %p.\n", protected_session); + + d3d12_resource_promote_desc(desc, &desc1); + + if (FAILED(hr = d3d12_resource_create_reserved(device, &desc1, + vkd3d_barrier_layout_to_resource_state(initial_layout, desc1.Flags), optimized_clear_value, + num_castable_formats, castable_formats, &object))) + return hr; + + return return_interface(&object->ID3D12Resource_iface, &IID_ID3D12Resource, iid, resource); } /* Gotta love C sometimes ... :') */ @@ -6970,6 +7098,15 @@ static void d3d12_device_caps_init_feature_options11(struct d3d12_device *device device->device_info.properties2.properties.limits.minStorageBufferOffsetAlignment <= 16; } +static void d3d12_device_caps_init_feature_options12(struct d3d12_device *device) +{ + D3D12_FEATURE_DATA_D3D12_OPTIONS12 *options12 = &device->d3d12_caps.options12; + + /* Exposing this without EnhancedBarrier is somewhat meaningless, + * but this allows us to implement the enhanced barrier API piecemeal. */ + options12->RelaxedFormatCastingSupported = TRUE; +} + static void d3d12_device_caps_init_feature_level(struct d3d12_device *device) { const VkPhysicalDeviceFeatures *features = &device->device_info.features2.features; @@ -7291,6 +7428,7 @@ static void d3d12_device_caps_init(struct d3d12_device *device) d3d12_device_caps_init_feature_options9(device); d3d12_device_caps_init_feature_options10(device); d3d12_device_caps_init_feature_options11(device); + d3d12_device_caps_init_feature_options12(device); d3d12_device_caps_init_feature_level(device); d3d12_device_caps_shader_model_override(device); diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index e9d8e7440d..b775ef177d 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -244,8 +244,58 @@ static unsigned int max_miplevel_count(const D3D12_RESOURCE_DESC1 *desc) return vkd3d_log2i(size) + 1; } +static bool vkd3d_get_castable_format_compatibility_list(const struct d3d12_device *device, + const D3D12_RESOURCE_DESC1 *desc, UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct vkd3d_format_compatibility_list *out_list, VkImageCreateFlags *vk_flags) +{ + const struct vkd3d_format *format = vkd3d_get_format(device, desc->Format, false); + struct vkd3d_format_compatibility_list list; + bool base_format_is_compressed; + unsigned int i; + + base_format_is_compressed = vkd3d_format_is_compressed(format); + + memset(&list, 0, sizeof(list)); + vkd3d_format_compatibility_list_add_format(&list, format->vk_format); + + for (i = 0; i < num_castable_formats; i++) + { + format = vkd3d_get_format(device, castable_formats[i], false); + vkd3d_format_compatibility_list_add_format(&list, format->vk_format); + if (base_format_is_compressed && !vkd3d_format_is_compressed(format)) + *vk_flags |= VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT; + } + + /* See vkd3d_get_format_compatibility_list for rationale. */ + if ((desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) && + device->device_info.shader_image_atomic_int64_features.shaderImageInt64Atomics) + { + for (i = 0; i < list.format_count; i++) + { + if (list.vk_formats[i] == VK_FORMAT_R32G32_UINT) + { + vkd3d_format_compatibility_list_add_format(&list, VK_FORMAT_R64_UINT); + break; + } + } + } + + if (list.format_count < 2) + return false; + + *vk_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + + /* If we overflow the format list for whatever reason, + * just fall back to plain MUTABLE_FORMAT_BIT. */ + if (list.format_count > ARRAY_SIZE(list.vk_formats)) + return false; + + *out_list = list; + return true; +} + static bool vkd3d_get_format_compatibility_list(const struct d3d12_device *device, - const D3D12_RESOURCE_DESC1 *desc, struct vkd3d_format_compatibility_list *out_list) + const D3D12_RESOURCE_DESC1 *desc, struct vkd3d_format_compatibility_list *out_list, VkImageCreateFlags *vk_flags) { static const VkFormat r32_uav_formats[] = { VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, VK_FORMAT_R32_SFLOAT }; const struct vkd3d_format *format = vkd3d_get_format(device, desc->Format, false); @@ -289,6 +339,8 @@ static bool vkd3d_get_format_compatibility_list(const struct d3d12_device *devic if (list.format_count < 2) return false; + assert(list.format_count <= ARRAY_SIZE(list.vk_formats)); + *vk_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; *out_list = list; return true; } @@ -496,6 +548,7 @@ struct vkd3d_image_create_info static HRESULT vkd3d_get_image_create_info(struct d3d12_device *device, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, const D3D12_RESOURCE_DESC1 *desc, struct d3d12_resource *resource, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, struct vkd3d_image_create_info *create_info) { struct vkd3d_format_compatibility_list *compat_list = &create_info->format_compat_list; @@ -561,15 +614,28 @@ static HRESULT vkd3d_get_image_create_info(struct d3d12_device *device, * For now, keep this as a specific workaround until we understand the problem scope better. */ image_info->flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; } - else if (vkd3d_get_format_compatibility_list(device, desc, compat_list)) + else { - format_list->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; - format_list->pNext = image_info->pNext; - format_list->viewFormatCount = compat_list->format_count; - format_list->pViewFormats = compat_list->vk_formats; + bool requires_format_list = false; + if (num_castable_formats) + { + requires_format_list = vkd3d_get_castable_format_compatibility_list(device, desc, + num_castable_formats, castable_formats, compat_list, &image_info->flags); + } + else + { + requires_format_list = vkd3d_get_format_compatibility_list(device, desc, + compat_list, &image_info->flags); + } - image_info->pNext = format_list; - image_info->flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + if (requires_format_list) + { + format_list->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; + format_list->pNext = image_info->pNext; + format_list->viewFormatCount = compat_list->format_count; + format_list->pViewFormats = compat_list->vk_formats; + image_info->pNext = format_list; + } } } @@ -740,7 +806,9 @@ static HRESULT vkd3d_get_image_create_info(struct d3d12_device *device, static HRESULT vkd3d_create_image(struct d3d12_device *device, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, - const D3D12_RESOURCE_DESC1 *desc, struct d3d12_resource *resource, VkImage *vk_image) + const D3D12_RESOURCE_DESC1 *desc, struct d3d12_resource *resource, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + VkImage *vk_image) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct vkd3d_image_create_info create_info; @@ -748,7 +816,7 @@ static HRESULT vkd3d_create_image(struct d3d12_device *device, HRESULT hr; if (FAILED(hr = vkd3d_get_image_create_info(device, heap_properties, - heap_flags, desc, resource, &create_info))) + heap_flags, desc, resource, num_castable_formats, castable_formats, &create_info))) return hr; if ((vr = VK_CALL(vkCreateImage(device->vk_device, &create_info.image_info, NULL, vk_image))) < 0) @@ -761,7 +829,9 @@ static size_t vkd3d_compute_resource_layouts_from_desc(struct d3d12_device *devi const D3D12_RESOURCE_DESC1 *desc, struct vkd3d_subresource_layout *layouts); HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device, - const D3D12_RESOURCE_DESC1 *desc, D3D12_RESOURCE_ALLOCATION_INFO *allocation_info) + const D3D12_RESOURCE_DESC1 *desc, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + D3D12_RESOURCE_ALLOCATION_INFO *allocation_info) { static const D3D12_HEAP_PROPERTIES heap_properties = {D3D12_HEAP_TYPE_DEFAULT}; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; @@ -773,7 +843,7 @@ HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device, HRESULT hr; assert(desc->Dimension != D3D12_RESOURCE_DIMENSION_BUFFER); - assert(d3d12_resource_validate_desc(desc, device) == S_OK); + assert(d3d12_resource_validate_desc(desc, num_castable_formats, castable_formats, device) == S_OK); if (!desc->MipLevels) { @@ -782,7 +852,9 @@ HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device, desc = &validated_desc; } - if (FAILED(hr = vkd3d_get_image_create_info(device, &heap_properties, 0, desc, NULL, &create_info))) + if (FAILED(hr = vkd3d_get_image_create_info(device, &heap_properties, 0, desc, NULL, + num_castable_formats, castable_formats, + &create_info))) return hr; requirement_info.sType = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS; @@ -2175,9 +2247,13 @@ void d3d12_resource_promote_desc(const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE desc1->SamplerFeedbackMipRegion.Depth = 0; } -HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC1 *desc, struct d3d12_device *device) +HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC1 *desc, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_device *device) { + const struct vkd3d_format *cast_format; const struct vkd3d_format *format; + UINT i; switch (desc->Dimension) { @@ -2241,6 +2317,95 @@ HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC1 *desc, struct d3 return E_INVALIDARG; } + /* Validate format cast list. */ + if (num_castable_formats) + { + if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) + { + /* D3D12 runtime allows this, even if it is nonsensical. */ + for (i = 0; i < num_castable_formats; i++) + if (castable_formats[i] != DXGI_FORMAT_UNKNOWN) + return E_INVALIDARG; + } + else + { + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VkFormatFeatureFlags required_flags = 0; + VkFormatFeatureFlags total_flags = 0; + VkFormatProperties format_properties; + + format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0); + if (!format) + { + WARN("Unrecognized format #%x.\n", desc->Format); + return E_INVALIDARG; + } + + if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) + required_flags |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + if (desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) + required_flags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + /* Depth-stencil is special and will never use MUTABLE. */ + + /* Need special validation here. With extended usage, all required usage flags must be satisfiable by + * at least one potential format. Otherwise, we are required to fail the call. */ + VK_CALL(vkGetPhysicalDeviceFormatProperties(device->vk_physical_device, + format->vk_format, &format_properties)); + total_flags |= format_properties.optimalTilingFeatures; + + for (i = 0; i < num_castable_formats; i++) + { + cast_format = vkd3d_get_format(device, castable_formats[i], false); + if (!cast_format) + { + WARN("Unrecognized format #%x.\n", castable_formats[i]); + return E_INVALIDARG; + } + + VK_CALL(vkGetPhysicalDeviceFormatProperties(device->vk_physical_device, + cast_format->vk_format, &format_properties)); + total_flags |= format_properties.optimalTilingFeatures; + + if (vkd3d_format_is_compressed(format)) + { + if (vkd3d_format_is_compressed(cast_format)) + { + if (format->block_byte_count != cast_format->block_byte_count) + { + WARN("Cannot cast to block format of different size.\n"); + return E_INVALIDARG; + } + } + else + { + if (format->block_byte_count != cast_format->byte_count) + { + WARN("Cannot cast to non-compressed format with different size.\n"); + return E_INVALIDARG; + } + } + } + else if (vkd3d_format_is_compressed(cast_format)) + { + WARN("Cannot cast uncompressed to block-compressed format.\n"); + return E_INVALIDARG; + } + else if (format->byte_count != cast_format->byte_count) + { + WARN("Cannot cast to type of different bit width.\n"); + return E_INVALIDARG; + } + } + + if ((total_flags & required_flags) != required_flags) + { + WARN("Requested resource flags #%x, but no format in cast list supports it.\n", + desc->Flags); + return E_INVALIDARG; + } + } + } + return d3d12_validate_resource_flags(desc->Flags); } @@ -2322,11 +2487,13 @@ static HRESULT d3d12_resource_validate_heap_properties(const D3D12_RESOURCE_DESC static HRESULT d3d12_resource_validate_create_info(const D3D12_RESOURCE_DESC1 *desc, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_device *device) + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_device *device) { HRESULT hr; - if (FAILED(hr = d3d12_resource_validate_desc(desc, device))) + if (FAILED(hr = d3d12_resource_validate_desc(desc, num_castable_formats, castable_formats, device))) return hr; if (initial_state == D3D12_RESOURCE_STATE_RENDER_TARGET && !(desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) @@ -2685,7 +2852,9 @@ static void d3d12_resource_destroy_and_release_device(struct d3d12_resource *res d3d12_device_release(device); } -static HRESULT d3d12_resource_create_vk_resource(struct d3d12_resource *resource, struct d3d12_device *device) +static HRESULT d3d12_resource_create_vk_resource(struct d3d12_resource *resource, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_device *device) { const D3D12_HEAP_PROPERTIES *heap_properties; HRESULT hr; @@ -2707,7 +2876,9 @@ static HRESULT d3d12_resource_create_vk_resource(struct d3d12_resource *resource resource->desc.MipLevels = max_miplevel_count(&resource->desc); if (FAILED(hr = vkd3d_create_image(device, heap_properties, - D3D12_HEAP_FLAG_NONE, &resource->desc, resource, &resource->res.vk_image))) + D3D12_HEAP_FLAG_NONE, &resource->desc, resource, + num_castable_formats, castable_formats, + &resource->res.vk_image))) return hr; } @@ -2762,7 +2933,9 @@ static size_t d3d12_resource_init_subresource_layouts(struct d3d12_resource *res static HRESULT d3d12_resource_create(struct d3d12_device *device, uint32_t flags, const D3D12_RESOURCE_DESC1 *desc, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource) + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_resource **resource) { const D3D12_RESOURCE_FLAGS high_priority_resource_flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | @@ -2772,7 +2945,8 @@ static HRESULT d3d12_resource_create(struct d3d12_device *device, uint32_t flags HRESULT hr; if (FAILED(hr = d3d12_resource_validate_create_info(desc, - heap_properties, initial_state, optimized_clear_value, device))) + heap_properties, initial_state, optimized_clear_value, + num_castable_formats, castable_formats, device))) return hr; if (!(object = vkd3d_malloc(sizeof(*object)))) @@ -2873,14 +3047,18 @@ static void d3d12_resource_tag_debug_name(struct d3d12_resource *resource, HRESULT d3d12_resource_create_committed(struct d3d12_device *device, const D3D12_RESOURCE_DESC1 *desc, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, HANDLE shared_handle, struct d3d12_resource **resource) + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + HANDLE shared_handle, struct d3d12_resource **resource) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct d3d12_resource *object; HRESULT hr; if (FAILED(hr = d3d12_resource_create(device, VKD3D_RESOURCE_COMMITTED | VKD3D_RESOURCE_ALLOCATION, - desc, heap_properties, heap_flags, initial_state, optimized_clear_value, &object))) + desc, heap_properties, heap_flags, initial_state, optimized_clear_value, + num_castable_formats, castable_formats, + &object))) return hr; if (d3d12_resource_is_texture(object)) @@ -2900,7 +3078,7 @@ HRESULT d3d12_resource_create_committed(struct d3d12_device *device, const D3D12 VkExportMemoryAllocateInfo export_info; #endif - if (FAILED(hr = d3d12_resource_create_vk_resource(object, device))) + if (FAILED(hr = d3d12_resource_create_vk_resource(object, num_castable_formats, castable_formats, device))) goto fail; image_info.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; @@ -3109,7 +3287,9 @@ static HRESULT d3d12_resource_validate_heap(const D3D12_RESOURCE_DESC1 *resource HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RESOURCE_DESC1 *desc, struct d3d12_heap *heap, uint64_t heap_offset, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource) + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_resource **resource) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct vkd3d_allocate_memory_info allocate_info; @@ -3130,7 +3310,9 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE heap->desc.Flags & ~(D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES), - initial_state, optimized_clear_value, NULL, resource))) + initial_state, optimized_clear_value, + num_castable_formats, castable_formats, + NULL, resource))) { ERR("Failed to create fallback committed resource.\n"); } @@ -3138,7 +3320,9 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE } if (FAILED(hr = d3d12_resource_create(device, VKD3D_RESOURCE_PLACED, desc, - &heap->desc.Properties, heap->desc.Flags, initial_state, optimized_clear_value, &object))) + &heap->desc.Properties, heap->desc.Flags, initial_state, optimized_clear_value, + num_castable_formats, castable_formats, + &object))) return hr; /* https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createheap#remarks. @@ -3147,7 +3331,7 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE if (d3d12_resource_is_texture(object)) { - if (FAILED(hr = d3d12_resource_create_vk_resource(object, device))) + if (FAILED(hr = d3d12_resource_create_vk_resource(object, num_castable_formats, castable_formats, device))) goto fail; /* Align manually. This works because we padded the required allocation size reported to the app. */ @@ -3267,16 +3451,20 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE HRESULT d3d12_resource_create_reserved(struct d3d12_device *device, const D3D12_RESOURCE_DESC1 *desc, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource) + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_resource **resource) { struct d3d12_resource *object; HRESULT hr; if (FAILED(hr = d3d12_resource_create(device, VKD3D_RESOURCE_RESERVED, desc, - NULL, D3D12_HEAP_FLAG_NONE, initial_state, optimized_clear_value, &object))) + NULL, D3D12_HEAP_FLAG_NONE, initial_state, optimized_clear_value, + num_castable_formats, castable_formats, + &object))) return hr; - if (FAILED(hr = d3d12_resource_create_vk_resource(object, device))) + if (FAILED(hr = d3d12_resource_create_vk_resource(object, num_castable_formats, castable_formats, device))) goto fail; if (FAILED(hr = d3d12_resource_init_sparse_info(object, device, &object->sparse))) diff --git a/libs/vkd3d/swapchain.c b/libs/vkd3d/swapchain.c index a350a88a91..27a55c8b5b 100644 --- a/libs/vkd3d/swapchain.c +++ b/libs/vkd3d/swapchain.c @@ -448,7 +448,7 @@ static HRESULT dxgi_vk_swap_chain_allocate_user_buffer(struct dxgi_vk_swap_chain heap_props.VisibleNodeMask = 1; return d3d12_resource_create_committed(device, &resource_desc, &heap_props, D3D12_HEAP_FLAG_NONE, - D3D12_RESOURCE_STATE_PRESENT, NULL, NULL, ppResource); + D3D12_RESOURCE_STATE_PRESENT, NULL, 0, NULL, NULL, ppResource); } static HRESULT dxgi_vk_swap_chain_reallocate_user_buffers(struct dxgi_vk_swap_chain *chain) diff --git a/libs/vkd3d/utils.c b/libs/vkd3d/utils.c index b11717e5ef..9168d4b8c3 100644 --- a/libs/vkd3d/utils.c +++ b/libs/vkd3d/utils.c @@ -396,8 +396,15 @@ void vkd3d_format_compatibility_list_add_format(struct vkd3d_format_compatibilit if (!found) { - assert(list->format_count < ARRAY_SIZE(list->vk_formats)); - list->vk_formats[list->format_count++] = vk_format; + if (list->format_count < ARRAY_SIZE(list->vk_formats)) + { + list->vk_formats[list->format_count++] = vk_format; + } + else + { + /* Mark overflow. Caller can fall back to plain MUTABLE_FORMAT_BIT without format list. */ + list->format_count = UINT32_MAX; + } } } diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index d9251a4da0..7404d0cc11 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -998,7 +998,9 @@ LONG64 vkd3d_allocate_cookie(); bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource); void d3d12_resource_promote_desc(const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_DESC1 *desc1); -HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC1 *desc, struct d3d12_device *device); +HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC1 *desc, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_device *device); VkImageSubresource d3d12_resource_get_vk_subresource(const struct d3d12_resource *resource, uint32_t subresource_idx, bool all_aspects); VkImageAspectFlags vk_image_aspect_flags_from_d3d12( @@ -1013,13 +1015,19 @@ UINT d3d12_plane_index_from_vk_aspect(VkImageAspectFlagBits aspect); HRESULT d3d12_resource_create_committed(struct d3d12_device *device, const D3D12_RESOURCE_DESC1 *desc, const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, HANDLE shared_handle, struct d3d12_resource **resource); + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + HANDLE shared_handle, struct d3d12_resource **resource); HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RESOURCE_DESC1 *desc, struct d3d12_heap *heap, uint64_t heap_offset, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource); + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_resource **resource); HRESULT d3d12_resource_create_reserved(struct d3d12_device *device, const D3D12_RESOURCE_DESC1 *desc, D3D12_RESOURCE_STATES initial_state, - const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource); + const D3D12_CLEAR_VALUE *optimized_clear_value, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + struct d3d12_resource **resource); static inline struct d3d12_resource *impl_from_ID3D12Resource2(ID3D12Resource2 *iface) { @@ -1049,7 +1057,9 @@ HRESULT vkd3d_create_buffer(struct d3d12_device *device, HRESULT vkd3d_create_buffer_explicit_usage(struct d3d12_device *device, VkBufferUsageFlags vk_usage, VkDeviceSize vk_size, VkBuffer *vk_buffer); HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device, - const D3D12_RESOURCE_DESC1 *desc, D3D12_RESOURCE_ALLOCATION_INFO *allocation_info); + const D3D12_RESOURCE_DESC1 *desc, + UINT num_castable_formats, const DXGI_FORMAT *castable_formats, + D3D12_RESOURCE_ALLOCATION_INFO *allocation_info); enum vkd3d_view_type { @@ -4017,6 +4027,7 @@ struct d3d12_caps D3D12_FEATURE_DATA_D3D12_OPTIONS9 options9; D3D12_FEATURE_DATA_D3D12_OPTIONS10 options10; D3D12_FEATURE_DATA_D3D12_OPTIONS11 options11; + D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12; D3D_FEATURE_LEVEL max_feature_level; D3D_SHADER_MODEL max_shader_model;