Compare commits

...

3 Commits

Author SHA1 Message Date
Joshua Ashton 15542b0fd5
tests: Add a test for MinLODClamp
Signed-off-by: Joshua Ashton <joshua@froggi.es>
2021-07-06 22:41:22 +01:00
Joshua Ashton 7ed7d98b4d
vkd3d: Make invalid RTV for attachment FIXME_ONCE
This spams constantly in Dirt 5.

Signed-off-by: Joshua Ashton <joshua@froggi.es>
2021-07-06 16:51:48 +01:00
Joshua Ashton 828606ef80
vkd3d: Implement MinLODClamp using VK_EXT_image_view_min_lod
Signed-off-by: Joshua Ashton <joshua@froggi.es>
2021-07-06 16:51:24 +01:00
6 changed files with 256 additions and 20 deletions

View File

@ -26,6 +26,7 @@ There are some hard requirements on drivers to be able to implement D3D12 in a r
- `VK_KHR_sampler_mirror_clamp_to_edge`
- `VK_EXT_robustness2`
- `VK_KHR_separate_depth_stencil_layouts`
- `VK_EXT_image_view_min_lod`
Some notable extensions that **should** be supported for optimal or correct behavior.
These extensions will likely become mandatory later.

View File

@ -4137,7 +4137,7 @@ static bool d3d12_command_list_update_current_framebuffer(struct d3d12_command_l
if (!list->rtvs[i].view)
{
FIXME("Invalid RTV for attachment %u.\n", i);
FIXME_ONCE("Invalid RTV for attachment %u.\n", i);
return false;
}

View File

@ -81,6 +81,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] =
VK_EXTENSION(EXT_CUSTOM_BORDER_COLOR, EXT_custom_border_color),
VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable),
VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing),
VK_EXTENSION(EXT_IMAGE_VIEW_MIN_LOD, EXT_image_view_min_lod),
VK_EXTENSION(EXT_INLINE_UNIFORM_BLOCK, EXT_inline_uniform_block),
VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2),
VK_EXTENSION(EXT_SAMPLER_FILTER_MINMAX, EXT_sampler_filter_minmax),
@ -1133,6 +1134,12 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
vk_prepend_struct(&info->features2, &info->mutable_descriptor_features);
}
if (vulkan_info->EXT_image_view_min_lod)
{
info->image_view_min_lod_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT;
vk_prepend_struct(&info->features2, &info->image_view_min_lod_features);
}
if (vulkan_info->KHR_acceleration_structure && vulkan_info->KHR_ray_tracing_pipeline &&
vulkan_info->KHR_deferred_host_operations && vulkan_info->KHR_spirv_1_4)
{

View File

@ -3399,6 +3399,7 @@ bool vkd3d_create_texture_view(struct d3d12_device *device, const struct vkd3d_t
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
const struct vkd3d_format *format = desc->format;
struct VkImageViewMinLodCreateInfoEXT min_lod_desc;
struct VkImageViewCreateInfo view_desc;
struct vkd3d_view *object;
VkImageView vk_view;
@ -3419,29 +3420,40 @@ bool vkd3d_create_texture_view(struct d3d12_device *device, const struct vkd3d_t
view_desc.subresourceRange.baseArrayLayer = desc->layer_idx;
view_desc.subresourceRange.layerCount = desc->layer_count;
if (desc->miplevel_clamp != 0.0f)
FIXME_ONCE("Cannot handle MinResourceLOD clamp of %f correctly.\n", desc->miplevel_clamp);
/* This is not correct, but it's the best we can do with existing API.
* It should at least avoid a scenario where implicit LOD fetches from invalid levels.
* TODO: We will need an extension with vkCreateImageView pNext specifying minLODClamp.
* It will be trivial to add in RADV at least ... */
if (desc->miplevel_clamp >= 1.0f)
if (!device->device_info.image_view_min_lod_features.minLod)
{
uint32_t new_base_level;
uint32_t level_offset;
uint32_t end_level;
if (desc->miplevel_clamp != 0.0f)
FIXME_ONCE("Cannot handle MinResourceLOD clamp of %f correctly.\n", desc->miplevel_clamp);
level_offset = (uint32_t)desc->miplevel_clamp;
if (view_desc.subresourceRange.levelCount != VK_REMAINING_MIP_LEVELS)
/* This is not correct, but it's the best we can do with existing API.
* It should at least avoid a scenario where implicit LOD fetches from invalid levels.
* TODO: We will need an extension with vkCreateImageView pNext specifying minLODClamp.
* It will be trivial to add in RADV at least ... */
if (desc->miplevel_clamp >= 1.0f)
{
end_level = view_desc.subresourceRange.baseMipLevel + view_desc.subresourceRange.levelCount;
new_base_level = min(end_level - 1, desc->miplevel_idx + level_offset);
view_desc.subresourceRange.levelCount = end_level - new_base_level;
view_desc.subresourceRange.baseMipLevel = new_base_level;
uint32_t new_base_level;
uint32_t level_offset;
uint32_t end_level;
level_offset = (uint32_t)desc->miplevel_clamp;
if (view_desc.subresourceRange.levelCount != VK_REMAINING_MIP_LEVELS)
{
end_level = view_desc.subresourceRange.baseMipLevel + view_desc.subresourceRange.levelCount;
new_base_level = min(end_level - 1, desc->miplevel_idx + level_offset);
view_desc.subresourceRange.levelCount = end_level - new_base_level;
view_desc.subresourceRange.baseMipLevel = new_base_level;
}
else
view_desc.subresourceRange.baseMipLevel += level_offset;
}
else
view_desc.subresourceRange.baseMipLevel += level_offset;
}
else
{
min_lod_desc.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT;
min_lod_desc.pNext = NULL;
min_lod_desc.minLod = desc->miplevel_clamp;
view_desc.pNext = &min_lod_desc;
}
if ((vr = VK_CALL(vkCreateImageView(device->vk_device, &view_desc, NULL, &vk_view))) < 0)

View File

@ -128,6 +128,7 @@ struct vkd3d_vulkan_info
bool EXT_depth_clip_enable;
bool EXT_descriptor_indexing;
bool EXT_inline_uniform_block;
bool EXT_image_view_min_lod;
bool EXT_robustness2;
bool EXT_sampler_filter_minmax;
bool EXT_shader_demote_to_helper_invocation;
@ -2519,6 +2520,7 @@ struct vkd3d_physical_device_info
VkPhysicalDeviceShaderDrawParametersFeatures shader_draw_parameters_features;
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_size_control_features;
VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR separate_depth_stencil_layout_features;
VkPhysicalDeviceImageViewMinLodFeaturesEXT image_view_min_lod_features;
VkPhysicalDeviceFeatures2 features2;

View File

@ -51863,6 +51863,219 @@ static void test_null_descriptor_mismatch_type(void)
destroy_test_context(&context);
}
static void test_view_min_lod(void)
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
D3D12_SHADER_RESOURCE_VIEW_DESC view_desc;
ID3D12GraphicsCommandList *command_list;
const D3D12_SHADER_BYTECODE *ps = NULL;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle;
ID3D12PipelineState *pso = NULL;
struct test_context_desc desc;
struct test_context context;
ID3D12DescriptorHeap *heap;
ID3D12CommandQueue *queue;
ID3D12Resource *texture;
unsigned int offset;
unsigned int i;
HRESULT hr;
static const DWORD ps_view_min_lod_load_code[] =
{
#if 0
Texture2D tex;
float testLod;
float4 main() : SV_Target
{
return tex.Load(int3(0, 0, int(testLod)));
}
#endif
0x43425844, 0xe23be9df, 0xf78327b8, 0xb2d9d572, 0xefa569ae, 0x00000001, 0x00000118, 0x00000003,
0x0000002c, 0x0000003c, 0x00000070, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000,
0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x58454853, 0x000000a0, 0x00000050, 0x00000028,
0x0100086a, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x04001858, 0x00107000, 0x00000000,
0x00005555, 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x0600001b, 0x001000c2,
0x00000000, 0x00208006, 0x00000000, 0x00000000, 0x08000036, 0x00100032, 0x00000000, 0x00004002,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8900002d, 0x800000c2, 0x00155543, 0x001020f2,
0x00000000, 0x00100e46, 0x00000000, 0x00107e46, 0x00000000, 0x0100003e,
};
static const D3D12_SHADER_BYTECODE ps_view_min_lod_load = {ps_view_min_lod_load_code, sizeof(ps_view_min_lod_load_code)};
static const DWORD ps_view_min_lod_sample_code[] =
{
#if 0
Texture2D tex;
SamplerState s;
float testLod;
float4 main() : SV_Target
{
return tex.SampleLevel(s, float2(0, 0), testLod);
}
#endif
0x43425844, 0x6447f634, 0xc09020fb, 0xdffd3b83, 0xabf31dab, 0x00000001, 0x00000104, 0x00000003,
0x0000002c, 0x0000003c, 0x00000070, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000,
0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x58454853, 0x0000008c, 0x00000050, 0x00000023,
0x0100086a, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x0300005a, 0x00106000, 0x00000000,
0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03000065, 0x001020f2, 0x00000000, 0x91000048,
0x800000c2, 0x00155543, 0x001020f2, 0x00000000, 0x00004002, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00107e46, 0x00000000, 0x00106000, 0x00000000, 0x0020800a, 0x00000000, 0x00000000,
0x0100003e,
};
static const D3D12_SHADER_BYTECODE ps_view_min_lod_sample = {ps_view_min_lod_sample_code, sizeof(ps_view_min_lod_sample_code)};
static const float red[] = {1.0f, 0.0f, 0.0f, 1.0f};
unsigned int texture_data[8 * 8 + 4 * 4 + 2 * 2 + 1 * 1];
D3D12_SUBRESOURCE_DATA resource_data[4];
static const struct
{
const D3D12_SHADER_BYTECODE *ps;
int most_detailed_mip;
float test_lod;
float min_lod;
unsigned int expected_color;
}
tests[] =
{
{&ps_view_min_lod_load, 0, -1.0f, 0.0f, 0x00000000},
{&ps_view_min_lod_load, 0, 0.0f, 0.0f, 0x0f0f0f0f},
{&ps_view_min_lod_load, 0, 1.0f, 0.0f, 0xffffffff},
{&ps_view_min_lod_load, 0, 2.0f, 0.0f, 0x0f0f0f0f},
{&ps_view_min_lod_load, 0, 3.0f, 0.0f, 0xffffffff},
{&ps_view_min_lod_load, 0, -1.0f, 1.0f, 0x00000000},
{&ps_view_min_lod_load, 0, 0.0f, 1.0f, 0x00000000},
{&ps_view_min_lod_load, 0, 1.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_load, 0, 2.0f, 1.0f, 0x0f0f0f0f},
{&ps_view_min_lod_load, 0, 3.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_load, 1, -1.0f, 1.0f, 0x00000000},
{&ps_view_min_lod_load, 1, 0.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_load, 1, 1.0f, 1.0f, 0x0f0f0f0f},
{&ps_view_min_lod_load, 1, 2.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_load, 1, 3.0f, 1.0f, 0x00000000},
{&ps_view_min_lod_load, 1, -1.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_load, 1, 0.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_load, 1, 1.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_load, 1, 2.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_load, 1, 3.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_sample, 0, -1.0f, 0.0f, 0x0f0f0f0f},
{&ps_view_min_lod_sample, 0, 0.0f, 0.0f, 0x0f0f0f0f},
{&ps_view_min_lod_sample, 0, 1.0f, 0.0f, 0xffffffff},
{&ps_view_min_lod_sample, 0, 2.0f, 0.0f, 0x0f0f0f0f},
{&ps_view_min_lod_sample, 0, 3.0f, 0.0f, 0xffffffff},
{&ps_view_min_lod_sample, 0, -1.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 0, 0.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 0, 1.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 0, 2.0f, 1.0f, 0x0f0f0f0f},
{&ps_view_min_lod_sample, 0, 3.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 1, -1.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 1, 0.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 1, 1.0f, 1.0f, 0x0f0f0f0f},
{&ps_view_min_lod_sample, 1, 2.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 1, 3.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 1, 4.0f, 1.0f, 0xffffffff},
{&ps_view_min_lod_sample, 1, -1.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_sample, 1, 0.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_sample, 1, 1.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_sample, 1, 2.0f, 9.0f, 0x00000000},
{&ps_view_min_lod_sample, 1, 3.0f, 9.0f, 0x00000000},
};
/* Alternate mip colors */
offset = 0;
for (i = 0; i < 4; i++) {
const unsigned int size = 8u >> i;
resource_data[i] = (D3D12_SUBRESOURCE_DATA) {&texture_data[offset], sizeof(unsigned int) * size};
memset(&texture_data[offset], (i % 2 == 0) ? 0x0F : 0xFF, sizeof(unsigned int) * size * size);
offset += size * size;
}
memset(&desc, 0, sizeof(desc));
desc.no_root_signature = true;
if (!init_test_context(&context, &desc))
return;
command_list = context.list;
queue = context.queue;
context.root_signature = create_texture_root_signature(context.device,
D3D12_SHADER_VISIBILITY_PIXEL, 4, 0);
init_pipeline_state_desc(&pso_desc, context.root_signature,
context.render_target_desc.Format, NULL, NULL, NULL);
heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
gpu_handle = ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(heap);
texture = create_default_texture2d(context.device,
64, 64, 1, 4, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D12_RESOURCE_STATE_COPY_DEST);
upload_texture_data(texture, resource_data, 4, queue, command_list);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, texture,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
for (i = 0; i < ARRAY_SIZE(tests); ++i)
{
vkd3d_test_set_context("Test %u", i);
if (ps != tests[i].ps)
{
if (pso)
ID3D12PipelineState_Release(pso);
ps = tests[i].ps;
pso_desc.PS = *tests[i].ps;
hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&pso);
ok(hr == S_OK, "Failed to create graphics pipeline state, hr %#x.\n", hr);
}
view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
view_desc.Texture2D.MostDetailedMip = tests[i].most_detailed_mip;
view_desc.Texture2D.MipLevels = -1;
view_desc.Texture2D.PlaneSlice = 0;
view_desc.Texture2D.ResourceMinLODClamp = tests[i].min_lod;
ID3D12Device_CreateShaderResourceView(context.device, texture, &view_desc,
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap));
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, red, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, false, NULL);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &heap);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0, gpu_handle);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &tests[i].test_lod, 0);
ID3D12GraphicsCommandList_DrawInstanced(command_list, 3, 1, 0, 0);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
check_sub_resource_uint(context.render_target, 0, queue, command_list, tests[i].expected_color, 0);
reset_command_list(command_list, context.allocator);
transition_resource_state(command_list, context.render_target,
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
}
vkd3d_test_set_context(NULL);
ID3D12Resource_Release(texture);
ID3D12DescriptorHeap_Release(heap);
destroy_test_context(&context);
}
START_TEST(d3d12)
{
pfn_D3D12CreateDevice = get_d3d12_pfn(D3D12CreateDevice);
@ -52120,4 +52333,5 @@ START_TEST(d3d12)
run_test(test_mismatching_pso_stages);
run_test(test_null_descriptor_mismatch_type);
run_test(test_vbv_stride_edge_cases);
run_test(test_view_min_lod);
}