Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- tests/d3d12.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+)
diff --git a/tests/d3d12.c b/tests/d3d12.c index 2b1830bd..618c2291 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -34797,6 +34797,329 @@ done: destroy_test_context(&context); }
+static void test_unbounded_resource_arrays(void) +{ + ID3D12Resource *constant_buffers[64], *input_buffers[64], *output_buffers[128]; + D3D12_ROOT_SIGNATURE_DESC root_signature_desc; + D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc; + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; + D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc; + ID3D12GraphicsCommandList *command_list; + struct resource_readback rb; + struct test_context context; + ID3D12DescriptorHeap *heap; + ID3D12CommandQueue *queue; + ID3D12Device *device; + unsigned int i; + HRESULT hr; + + static const D3D12_DESCRIPTOR_RANGE descriptor_ranges[] = + { + {D3D12_DESCRIPTOR_RANGE_TYPE_CBV, UINT_MAX, 2, 1, 0}, + {D3D12_DESCRIPTOR_RANGE_TYPE_SRV, UINT_MAX, 2, 1, 64}, + {D3D12_DESCRIPTOR_RANGE_TYPE_UAV, UINT_MAX, 1, 1, 128}, + {D3D12_DESCRIPTOR_RANGE_TYPE_UAV, UINT_MAX, 1, 2, 127}, + {D3D12_DESCRIPTOR_RANGE_TYPE_UAV, UINT_MAX, 1, 3, 192}, + }; + + static const D3D12_ROOT_PARAMETER root_parameters[] = + { + {D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, + .DescriptorTable = {ARRAY_SIZE(descriptor_ranges), descriptor_ranges}}, + }; + + static const DWORD cs_code[] = + { + /* Compiled with /res_may_alias (but it has no effect on the output from fxc 10.1). */ +#if 0 + struct cb + { + uint value; + }; + ConstantBuffer<cb> c1[] : register(b2, space1); + + Buffer<uint> t1[] : register(t2, space1); + + RWBuffer<uint> u1[] : register(u1, space1); + RWBuffer<uint> u2[] : register(u2, space2); + RWBuffer<uint> u3[] : register(u1, space3); + + [numthreads(64, 1, 1)] + void main(uint id : SV_DispatchThreadID) + { + uint i = c1[NonUniformResourceIndex(id)].value; + if (id < 64) // Workaround for an fxc bug. + { + u1[NonUniformResourceIndex(id)][0] = t1[NonUniformResourceIndex(i)][0]; + // If u2 is an alias of u1, this should copy u1. + u3[NonUniformResourceIndex(id)][0] = u2[NonUniformResourceIndex(id)][0]; + } + } +#endif + 0x43425844, 0x82871767, 0x87353509, 0x8ccc50cb, 0x5006dd54, 0x00000001, 0x00000250, 0x00000003, + 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, + 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x000001fc, 0x00050051, 0x0000007f, 0x0100086a, + 0x07000859, 0x00308e46, 0x00000000, 0x00000002, 0xffffffff, 0x00000001, 0x00000001, 0x07000858, + 0x00307e46, 0x00000000, 0x00000002, 0xffffffff, 0x00004444, 0x00000001, 0x0700089c, 0x0031ee46, + 0x00000000, 0x00000001, 0xffffffff, 0x00004444, 0x00000001, 0x0700089c, 0x0031ee46, 0x00000001, + 0x00000002, 0xffffffff, 0x00004444, 0x00000002, 0x0700089c, 0x0031ee46, 0x00000002, 0x00000001, + 0xffffffff, 0x00004444, 0x00000003, 0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, + 0x00000040, 0x00000001, 0x00000001, 0x0600004f, 0x00100012, 0x00000000, 0x0002000a, 0x00004001, + 0x00000040, 0x0304001f, 0x0010000a, 0x00000000, 0x04000036, 0x00100012, 0x00000000, 0x0002000a, + 0x0a000036, 0x00100022, 0x00000000, 0x8630800a, 0x00020001, 0x00000000, 0x00000002, 0x0010000a, + 0x00000000, 0x00000000, 0x0e00002d, 0x00100022, 0x00000000, 0x00004002, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x86207e16, 0x00020001, 0x00000000, 0x00000002, 0x0010001a, 0x00000000, + 0x0e0000a4, 0x8621e0f2, 0x00020001, 0x00000000, 0x00000001, 0x0010000a, 0x00000000, 0x00004002, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00100556, 0x00000000, 0x0e0000a3, 0x00100022, + 0x00000000, 0x00004002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8621ee16, 0x00020001, + 0x00000001, 0x00000002, 0x0010000a, 0x00000000, 0x0e0000a4, 0x8621e0f2, 0x00020001, 0x00000002, + 0x00000001, 0x0010000a, 0x00000000, 0x00004002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00100556, 0x00000000, 0x01000015, 0x0100003e, + }; + + if (!init_compute_test_context(&context)) + return; + device = context.device; + command_list = context.list; + queue = context.queue; + + memset(&root_signature_desc, 0, sizeof(root_signature_desc)); + root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters); + root_signature_desc.pParameters = root_parameters; + hr = create_root_signature(device, &root_signature_desc, &context.root_signature); + todo + ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); + if (FAILED(hr)) + goto done; + + heap = create_gpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 256); + + for (i = 0; i < ARRAY_SIZE(constant_buffers); ++i) + { + uint32_t cb_data = 63 - i; + constant_buffers[i] = create_default_buffer(device, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT, + D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST); + upload_buffer_data(constant_buffers[i], 0, sizeof(cb_data), &cb_data, queue, command_list); + reset_command_list(command_list, context.allocator); + transition_resource_state(command_list, constant_buffers[i], + D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + + cbv_desc.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(constant_buffers[i]); + cbv_desc.SizeInBytes = align(sizeof(cb_data), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); + ID3D12Device_CreateConstantBufferView(context.device, &cbv_desc, get_cpu_descriptor_handle(&context, heap, i)); + } + + for (i = 0; i < ARRAY_SIZE(input_buffers); ++i) + { + uint32_t srv_data = i ^ 0x35; + input_buffers[i] = create_default_buffer(device, sizeof(uint32_t), + D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST); + upload_buffer_data(input_buffers[i], 0, sizeof(srv_data), &srv_data, queue, command_list); + reset_command_list(command_list, context.allocator); + transition_resource_state(command_list, input_buffers[i], + D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + + memset(&srv_desc, 0, sizeof(srv_desc)); + srv_desc.Format = DXGI_FORMAT_R32_UINT; + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srv_desc.Buffer.FirstElement = 0; + srv_desc.Buffer.NumElements = 1; + ID3D12Device_CreateShaderResourceView(device, input_buffers[i], &srv_desc, + get_cpu_descriptor_handle(&context, heap, ARRAY_SIZE(constant_buffers) + i)); + } + + for (i = 0; i < ARRAY_SIZE(output_buffers); ++i) + { + output_buffers[i] = create_default_buffer(device, sizeof(uint32_t), + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + memset(&uav_desc, 0, sizeof(uav_desc)); + uav_desc.Format = DXGI_FORMAT_R32_UINT; + uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uav_desc.Buffer.FirstElement = 0; + uav_desc.Buffer.NumElements = 1; + ID3D12Device_CreateUnorderedAccessView(device, output_buffers[i], NULL, + &uav_desc, get_cpu_descriptor_handle(&context, heap, + ARRAY_SIZE(constant_buffers) + ARRAY_SIZE(input_buffers) + i)); + } + + context.pipeline_state = create_compute_pipeline_state(device, context.root_signature, + shader_bytecode(cs_code, sizeof(cs_code))); + + ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state); + ID3D12GraphicsCommandList_SetComputeRootSignature(command_list, context.root_signature); + ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, + 0, get_gpu_descriptor_handle(&context, heap, 0)); + + ID3D12GraphicsCommandList_Dispatch(command_list, 1, 1, 1); + + for (i = 0; i < ARRAY_SIZE(output_buffers); ++i) + { + vkd3d_test_set_context("buffer %u", i); + transition_sub_resource_state(command_list, output_buffers[i], 0, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); + get_buffer_readback_with_command_list(output_buffers[i], DXGI_FORMAT_R32_UINT, &rb, queue, command_list); + /* Buffers at index >= 64 are aliased. */ + check_readback_data_uint(&rb, NULL, (i < 64 ? 63 - i : 127 - i) ^ 0x35, 0); + release_resource_readback(&rb); + reset_command_list(command_list, context.allocator); + } + + for (i = 0; i < ARRAY_SIZE(output_buffers); ++i) + ID3D12Resource_Release(output_buffers[i]); + for (i = 0; i < ARRAY_SIZE(input_buffers); ++i) + ID3D12Resource_Release(input_buffers[i]); + for (i = 0; i < ARRAY_SIZE(constant_buffers); ++i) + ID3D12Resource_Release(constant_buffers[i]); + ID3D12DescriptorHeap_Release(heap); +done: + destroy_test_context(&context); +} + +static void test_unbounded_samplers(void) +{ + ID3D12DescriptorHeap *heap, *sampler_heap, *heaps[2]; + ID3D12Resource *input_texture, *output_buffer; + D3D12_ROOT_SIGNATURE_DESC root_signature_desc; + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; + ID3D12GraphicsCommandList *command_list; + D3D12_SAMPLER_DESC sampler_desc; + D3D12_SUBRESOURCE_DATA data; + struct resource_readback rb; + struct test_context context; + ID3D12CommandQueue *queue; + ID3D12Device *device; + unsigned int i; + HRESULT hr; + + static const D3D12_DESCRIPTOR_RANGE descriptor_ranges[] = + { + {D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1, 1, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND}, + {D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, UINT_MAX, 1, 1, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND}, + }; + + static const D3D12_ROOT_PARAMETER root_parameters[] = + { + {D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, .DescriptorTable = {1, &descriptor_ranges[0]}}, + {D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, .DescriptorTable = {1, &descriptor_ranges[1]}}, + {D3D12_ROOT_PARAMETER_TYPE_UAV, .Descriptor = {1, 1}}, + }; + + static const DWORD cs_code[] = + { +#if 0 + Texture2D<float> t1 : register(t1, space1); + SamplerState s1[] : register(s1, space1); + RWByteAddressBuffer u1 : register(u1, space1); + + [numthreads(64, 1, 1)] + void main(uint id : SV_DispatchThreadID) + { + // Should alternate between wrap (address 0.1), or clamp (address 1.0). + uint value = t1.SampleLevel(s1[NonUniformResourceIndex(id)], float2(1.1, 1.1), 0.0); + u1.Store(4 * id, value); + } +#endif + 0x43425844, 0x19feacce, 0xef7000f7, 0xd6411d98, 0x890a6fa4, 0x00000001, 0x00000178, 0x00000003, + 0x0000002c, 0x0000003c, 0x0000004c, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f, + 0x00000008, 0x00000000, 0x00000008, 0x58454853, 0x00000124, 0x00050051, 0x00000049, 0x0100086a, + 0x0600005a, 0x00306e46, 0x00000000, 0x00000001, 0xffffffff, 0x00000001, 0x07001858, 0x00307e46, + 0x00000000, 0x00000001, 0x00000001, 0x00005555, 0x00000001, 0x0600009d, 0x0031ee46, 0x00000000, + 0x00000001, 0x00000001, 0x00000001, 0x0200005f, 0x00020012, 0x02000068, 0x00000001, 0x0400009b, + 0x00000040, 0x00000001, 0x00000001, 0x04000036, 0x00100012, 0x00000000, 0x0002000a, 0x13000048, + 0x00100012, 0x00000000, 0x00004002, 0x3f8ccccd, 0x3f8ccccd, 0x00000000, 0x00000000, 0x00207e46, + 0x00000000, 0x00000001, 0x86206000, 0x00020001, 0x00000000, 0x00000001, 0x0010000a, 0x00000000, + 0x00004001, 0x00000000, 0x0500001c, 0x00100012, 0x00000000, 0x0010000a, 0x00000000, 0x06000029, + 0x00100022, 0x00000000, 0x0002000a, 0x00004001, 0x00000002, 0x080000a6, 0x0021e012, 0x00000000, + 0x00000001, 0x0010001a, 0x00000000, 0x0010000a, 0x00000000, 0x0100003e, + }; + + static const float texture_data[] = {10.0f, 100.0f, 100.0f, 100.0f}; + + if (!init_compute_test_context(&context)) + return; + device = context.device; + command_list = context.list; + queue = context.queue; + + root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters); + root_signature_desc.Flags = 0; + root_signature_desc.NumStaticSamplers = 0; + root_signature_desc.pStaticSamplers = NULL; + root_signature_desc.pParameters = root_parameters; + + hr = create_root_signature(device, &root_signature_desc, &context.root_signature); + todo + ok(SUCCEEDED(hr), "Failed to create root signature, hr %#x.\n", hr); + if (FAILED(hr)) + goto done; + + input_texture = create_default_texture2d(device, 2, 2, 1, 1, DXGI_FORMAT_R32_FLOAT, D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_STATE_COPY_DEST); + data.pData = texture_data; + data.RowPitch = 2 * sizeof(uint32_t); + data.SlicePitch = 2 * data.RowPitch; + upload_texture_data(input_texture, &data, 1, queue, command_list); + reset_command_list(command_list, context.allocator); + transition_resource_state(command_list, input_texture, D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + + output_buffer = create_default_buffer(device, 64 * sizeof(uint32_t), D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + context.pipeline_state = create_compute_pipeline_state(device, + context.root_signature, shader_bytecode(cs_code, sizeof(cs_code))); + + heap = create_gpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1); + sampler_heap = create_gpu_descriptor_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 64); + + srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srv_desc.Format = DXGI_FORMAT_R32_FLOAT; + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srv_desc.Texture2D.MipLevels = 1; + srv_desc.Texture2D.MostDetailedMip = 0; + srv_desc.Texture2D.PlaneSlice = 0; + srv_desc.Texture2D.ResourceMinLODClamp = 0; + ID3D12Device_CreateShaderResourceView(device, input_texture, &srv_desc, + ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap)); + + for (i = 0; i < 64; ++i) + { + memset(&sampler_desc, 0, sizeof(sampler_desc)); + sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + sampler_desc.AddressU = sampler_desc.AddressV = sampler_desc.AddressW + = (i & 1) ? D3D12_TEXTURE_ADDRESS_MODE_CLAMP : D3D12_TEXTURE_ADDRESS_MODE_WRAP; + ID3D12Device_CreateSampler(device, &sampler_desc, get_cpu_descriptor_handle(&context, sampler_heap, i)); + } + + ID3D12GraphicsCommandList_SetComputeRootSignature(command_list, context.root_signature); + ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state); + heaps[0] = heap; heaps[1] = sampler_heap; + ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 2, heaps); + ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(heap)); + ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(command_list, 1, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(sampler_heap)); + ID3D12GraphicsCommandList_SetComputeRootUnorderedAccessView(command_list, 2, ID3D12Resource_GetGPUVirtualAddress(output_buffer)); + ID3D12GraphicsCommandList_Dispatch(command_list, 1, 1, 1); + + transition_resource_state(command_list, output_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); + get_buffer_readback_with_command_list(output_buffer, DXGI_FORMAT_UNKNOWN, &rb, queue, command_list); + for (i = 0; i < 64; ++i) + { + unsigned int value = get_readback_uint(&rb, i, 0, 0); + unsigned int expected = (i & 1) ? 100 : 10; + ok(value == expected, "Got %u, expected %u at %u.\n", value, expected, i); + } + release_resource_readback(&rb); + + ID3D12Resource_Release(input_texture); + ID3D12Resource_Release(output_buffer); + ID3D12DescriptorHeap_Release(heap); + ID3D12DescriptorHeap_Release(sampler_heap); +done: + destroy_test_context(&context); +} + START_TEST(d3d12) { parse_args(argc, argv); @@ -34968,4 +35291,6 @@ START_TEST(d3d12) run_test(test_hull_shader_relative_addressing); run_test(test_hull_shader_patch_constant_inputs); run_test(test_resource_arrays); + run_test(test_unbounded_resource_arrays); + run_test(test_unbounded_samplers); }
Unbounded ranges can result in multiple descriptor sets being used.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 24 +++++++++++++----------- libs/vkd3d/vkd3d_private.h | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index bf80a9d0..3eab2ed6 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -1881,7 +1881,7 @@ static void d3d12_command_list_invalidate_root_parameters(struct d3d12_command_l if (!bindings->root_signature) return;
- bindings->descriptor_set = VK_NULL_HANDLE; + bindings->descriptor_set_count = 0; bindings->descriptor_table_dirty_mask = bindings->descriptor_table_active_mask & bindings->root_signature->descriptor_table_mask; bindings->push_descriptor_dirty_mask = bindings->push_descriptor_active_mask & bindings->root_signature->push_descriptor_mask; } @@ -2566,7 +2566,7 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point]; const struct d3d12_root_signature *root_signature = bindings->root_signature;
- if (bindings->descriptor_set && !bindings->in_use) + if (bindings->descriptor_set_count && !bindings->in_use) return;
/* We cannot modify bound descriptor sets. We need a new descriptor set if @@ -2581,8 +2581,9 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li * by an update command, or freed) between when the command is recorded * and when the command completes executing on the queue." */ - bindings->descriptor_set = d3d12_command_allocator_allocate_descriptor_set(list->allocator, + bindings->descriptor_sets[0] = d3d12_command_allocator_allocate_descriptor_set(list->allocator, root_signature->vk_set_layouts[root_signature->main_set]); + bindings->descriptor_set_count = 1; bindings->in_use = false;
bindings->descriptor_table_dirty_mask |= bindings->descriptor_table_active_mask & root_signature->descriptor_table_mask; @@ -2591,7 +2592,7 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_descriptor_write, VkDescriptorImageInfo *vk_image_info, const struct d3d12_desc *descriptor, - uint32_t descriptor_range_magic, VkDescriptorSet vk_descriptor_set, + uint32_t descriptor_range_magic, VkDescriptorSet *vk_descriptor_sets, uint32_t vk_binding, unsigned int index, bool use_array) { const struct vkd3d_view *view = descriptor->u.view; @@ -2601,7 +2602,7 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; vk_descriptor_write->pNext = NULL; - vk_descriptor_write->dstSet = vk_descriptor_set; + vk_descriptor_write->dstSet = vk_descriptor_sets[0]; vk_descriptor_write->dstBinding = use_array ? vk_binding : vk_binding + index; vk_descriptor_write->dstArrayElement = use_array ? index : 0; vk_descriptor_write->descriptorCount = 1; @@ -2708,7 +2709,7 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write, current_image_info, descriptor, range->descriptor_magic, - bindings->descriptor_set, range->binding, j, root_signature->use_descriptor_arrays)) + bindings->descriptor_sets, range->binding, j, root_signature->use_descriptor_arrays)) continue;
++descriptor_count; @@ -2816,7 +2817,7 @@ static void d3d12_command_list_update_push_descriptors(struct d3d12_command_list }
if (!vk_write_descriptor_set_from_root_descriptor(current_descriptor_write, - root_parameter, bindings->descriptor_set, vk_buffer_view, vk_buffer_info)) + root_parameter, bindings->descriptor_sets[0], vk_buffer_view, vk_buffer_info)) continue;
++descriptor_count; @@ -2913,10 +2914,11 @@ static void d3d12_command_list_update_descriptors(struct d3d12_command_list *lis
d3d12_command_list_update_push_descriptors(list, bind_point);
- if (bindings->descriptor_set) + if (bindings->descriptor_set_count) { VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point, - rs->vk_pipeline_layout, rs->main_set, 1, &bindings->descriptor_set, 0, NULL)); + rs->vk_pipeline_layout, rs->main_set, bindings->descriptor_set_count, bindings->descriptor_sets, + 0, NULL)); bindings->in_use = true; }
@@ -4231,7 +4233,7 @@ static void d3d12_command_list_set_root_cbv(struct d3d12_command_list *list, { d3d12_command_list_prepare_descriptors(list, bind_point); vk_write_descriptor_set_from_root_descriptor(&descriptor_write, - root_parameter, bindings->descriptor_set, NULL, &buffer_info); + root_parameter, bindings->descriptor_sets[0], NULL, &buffer_info); VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
assert(index < ARRAY_SIZE(bindings->push_descriptors)); @@ -4304,7 +4306,7 @@ static void d3d12_command_list_set_root_descriptor(struct d3d12_command_list *li { d3d12_command_list_prepare_descriptors(list, bind_point); vk_write_descriptor_set_from_root_descriptor(&descriptor_write, - root_parameter, bindings->descriptor_set, &vk_buffer_view, NULL); + root_parameter, bindings->descriptor_sets[0], &vk_buffer_view, NULL); VK_CALL(vkUpdateDescriptorSets(list->device->vk_device, 1, &descriptor_write, 0, NULL));
assert(index < ARRAY_SIZE(bindings->push_descriptors)); diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 7ba603fa..0b326b11 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -912,7 +912,8 @@ struct vkd3d_pipeline_bindings const struct d3d12_root_signature *root_signature;
VkPipelineBindPoint vk_bind_point; - VkDescriptorSet descriptor_set; + size_t descriptor_set_count; + VkDescriptorSet descriptor_sets[VKD3D_MAX_DESCRIPTOR_SETS - 1]; bool in_use;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_tables[D3D12_MAX_ROOT_COST];
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 3eab2ed6..c4a7bf07 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -2592,10 +2592,12 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_descriptor_write, VkDescriptorImageInfo *vk_image_info, const struct d3d12_desc *descriptor, - uint32_t descriptor_range_magic, VkDescriptorSet *vk_descriptor_sets, - uint32_t vk_binding, unsigned int index, bool use_array) + const struct d3d12_root_descriptor_table_range *range, VkDescriptorSet *vk_descriptor_sets, + unsigned int index, bool use_array) { + uint32_t descriptor_range_magic = range->descriptor_magic; const struct vkd3d_view *view = descriptor->u.view; + uint32_t vk_binding = range->binding;
if (descriptor->magic != descriptor_range_magic) return false; @@ -2707,9 +2709,8 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list } }
- if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write, - current_image_info, descriptor, range->descriptor_magic, - bindings->descriptor_sets, range->binding, j, root_signature->use_descriptor_arrays)) + if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write, current_image_info, + descriptor, range, bindings->descriptor_sets, j, root_signature->use_descriptor_arrays)) continue;
++descriptor_count;
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/state.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index f9efeeec..58463e59 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -664,6 +664,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo for (i = 0; i < desc->NumParameters; ++i) { const D3D12_ROOT_PARAMETER *p = &desc->pParameters[i]; + enum vkd3d_shader_visibility shader_visibility; unsigned int offset = 0;
if (p->ParameterType != D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE) @@ -673,6 +674,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
table = &root_signature->parameters[i].u.descriptor_table; range_count = p->u.DescriptorTable.NumDescriptorRanges; + shader_visibility = vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility);
root_signature->parameters[i].parameter_type = p->ParameterType; table->range_count = range_count; @@ -723,7 +725,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo
vk_binding = d3d12_root_signature_assign_vk_bindings(root_signature, range->type, range->register_space, range->base_register_idx, range->descriptor_count, false, true, - vkd3d_shader_visibility_from_d3d12(p->ShaderVisibility), context); + shader_visibility, context);
/* Unroll descriptor range. */ for (k = 0; k < range->descriptor_count; ++k)
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 130 ++++++++++++++++++++++++----- libs/vkd3d/device.c | 71 ++++++++++++++++ libs/vkd3d/resource.c | 14 ++++ libs/vkd3d/state.c | 166 +++++++++++++++++++++++++++++++++---- libs/vkd3d/vkd3d_private.h | 18 +++- tests/d3d12.c | 4 +- 6 files changed, 362 insertions(+), 41 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index c4a7bf07..afa68e0e 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -1,6 +1,7 @@ /* * Copyright 2016 Józef Kucia for CodeWeavers * Copyright 2016 Henri Verbeet for CodeWeavers + * Copyright 2021 Conor McCarthy for Codeweavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1363,10 +1364,12 @@ static VkDescriptorPool d3d12_command_allocator_allocate_descriptor_pool( }
static VkDescriptorSet d3d12_command_allocator_allocate_descriptor_set( - struct d3d12_command_allocator *allocator, VkDescriptorSetLayout vk_set_layout) + struct d3d12_command_allocator *allocator, VkDescriptorSetLayout vk_set_layout, + uint32_t variable_binding_size, bool unbounded) { struct d3d12_device *device = allocator->device; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VkDescriptorSetVariableDescriptorCountAllocateInfoEXT set_size; struct VkDescriptorSetAllocateInfo set_desc; VkDevice vk_device = device->vk_device; VkDescriptorSet vk_descriptor_set; @@ -1382,6 +1385,14 @@ static VkDescriptorSet d3d12_command_allocator_allocate_descriptor_set( set_desc.descriptorPool = allocator->vk_descriptor_pool; set_desc.descriptorSetCount = 1; set_desc.pSetLayouts = &vk_set_layout; + if (unbounded) + { + set_desc.pNext = &set_size; + set_size.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT; + set_size.pNext = NULL; + set_size.descriptorSetCount = 1; + set_size.pDescriptorCounts = &variable_binding_size; + } if ((vr = VK_CALL(vkAllocateDescriptorSets(vk_device, &set_desc, &vk_descriptor_set))) >= 0) return vk_descriptor_set;
@@ -2565,6 +2576,8 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li { struct vkd3d_pipeline_bindings *bindings = &list->pipeline_bindings[bind_point]; const struct d3d12_root_signature *root_signature = bindings->root_signature; + struct d3d12_device *device = list->device; + unsigned int i;
if (bindings->descriptor_set_count && !bindings->in_use) return; @@ -2581,9 +2594,44 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li * by an update command, or freed) between when the command is recorded * and when the command completes executing on the queue." */ - bindings->descriptor_sets[0] = d3d12_command_allocator_allocate_descriptor_set(list->allocator, - root_signature->vk_set_layouts[root_signature->main_set]); - bindings->descriptor_set_count = 1; + bindings->descriptor_set_count = 0; + for (i = root_signature->main_set; i < root_signature->vk_set_count; ++i) + { + unsigned int unbounded_range_offset = root_signature->vk_set_layout_unbounded_offsets[i]; + unsigned int unbounded_table = root_signature->vk_set_layout_table_indices[i]; + unsigned int variable_binding_size = 0; + + if (unbounded_range_offset != UINT_MAX) + { + const struct d3d12_desc *base_descriptor + = d3d12_desc_from_gpu_handle(bindings->descriptor_tables[unbounded_table]); + /* Descriptors may not be set, eg. WoW. */ + if (base_descriptor) + { + unsigned int heap_size; + int rc; + + rc = pthread_mutex_lock(&device->mutex); + if (rc) + ERR("Failed to lock mutex, error %d.\n", rc); + heap_size = d3d12_device_descriptor_heap_size_from_descriptor(device, base_descriptor); + if (!rc) + pthread_mutex_unlock(&device->mutex); + + if (heap_size >= unbounded_range_offset) + variable_binding_size = heap_size - unbounded_range_offset; + else + WARN("Descriptor heap size %u is less than the offset %u of an unbounded range in table %u, " + "vk set %u.\n", heap_size, unbounded_range_offset, unbounded_table, i); + } + } + + bindings->descriptor_sets[bindings->descriptor_set_count] = + d3d12_command_allocator_allocate_descriptor_set(list->allocator, + root_signature->vk_set_layouts[i], variable_binding_size, unbounded_range_offset != UINT_MAX); + ++bindings->descriptor_set_count; + } + bindings->in_use = false;
bindings->descriptor_table_dirty_mask |= bindings->descriptor_table_active_mask & root_signature->descriptor_table_mask; @@ -2598,13 +2646,14 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des uint32_t descriptor_range_magic = range->descriptor_magic; const struct vkd3d_view *view = descriptor->u.view; uint32_t vk_binding = range->binding; + uint32_t set = range->set;
if (descriptor->magic != descriptor_range_magic) return false;
vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; vk_descriptor_write->pNext = NULL; - vk_descriptor_write->dstSet = vk_descriptor_sets[0]; + vk_descriptor_write->dstSet = vk_descriptor_sets[set]; vk_descriptor_write->dstBinding = use_array ? vk_binding : vk_binding + index; vk_descriptor_write->dstArrayElement = use_array ? index : 0; vk_descriptor_write->descriptorCount = 1; @@ -2622,12 +2671,25 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des case VKD3D_DESCRIPTOR_MAGIC_SRV: case VKD3D_DESCRIPTOR_MAGIC_UAV: /* We use separate bindings for buffer and texture SRVs/UAVs. - * See d3d12_root_signature_init(). */ - if (!use_array) - vk_descriptor_write->dstBinding = vk_binding + 2 * index; - if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER - && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) - ++vk_descriptor_write->dstBinding; + * See d3d12_root_signature_init(). For unbounded ranges the descriptors exist + * in two consecutive sets, otherwise they occur in pairs in one set. */ + if (range->descriptor_count == UINT_MAX) + { + if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER + && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + { + vk_descriptor_write->dstSet = vk_descriptor_sets[set + 1]; + vk_descriptor_write->dstBinding = 0; + } + } + else + { + if (!use_array) + vk_descriptor_write->dstBinding = vk_binding + 2 * index; + if (descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER + && descriptor->vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + ++vk_descriptor_write->dstBinding; + }
if (descriptor->vk_descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || descriptor->vk_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) @@ -2675,10 +2737,10 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list VkDevice vk_device = list->device->vk_device; unsigned int i, j, k, descriptor_count; struct d3d12_desc *descriptor; + unsigned int write_count = 0;
descriptor_table = root_signature_get_descriptor_table(root_signature, index);
- descriptor_count = 0; current_descriptor_write = descriptor_writes; current_image_info = image_infos; for (i = 0; i < descriptor_table->range_count; ++i) @@ -2687,7 +2749,31 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
descriptor = base_descriptor + range->offset;
- for (j = 0; j < range->descriptor_count; ++j, ++descriptor) + descriptor_count = range->descriptor_count; + if (descriptor_count == UINT_MAX) + { + int rc; + + /* The first unbounded range of each type is written until the heap end is reached. Do not repeat. */ + if (i && range[-1].descriptor_magic == range->descriptor_magic && range[-1].descriptor_count == UINT_MAX) + continue; + + rc = pthread_mutex_lock(&list->device->mutex); + if (rc) + ERR("Failed to lock mutex, error %d.\n", rc); + descriptor_count = d3d12_device_descriptor_heap_size_from_descriptor(list->device, descriptor); + if (!rc) + pthread_mutex_unlock(&list->device->mutex); + + if (descriptor_count > range->vk_binding_count) + { + ERR("Heap descriptor count %u exceeds maximum Vulkan count %u. Reducing to the Vulkan maximum.\n", + descriptor_count, range->vk_binding_count); + descriptor_count = range->vk_binding_count; + } + } + + for (j = 0; j < descriptor_count; ++j, ++descriptor) { unsigned int register_idx = range->base_register_idx + j;
@@ -2709,25 +2795,29 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list } }
+ /* Not all descriptors are necessarily populated if the range is unbounded. */ + if (!descriptor->magic) + continue; + if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write, current_image_info, descriptor, range, bindings->descriptor_sets, j, root_signature->use_descriptor_arrays)) continue;
- ++descriptor_count; + ++write_count; ++current_descriptor_write; ++current_image_info;
- if (descriptor_count == ARRAY_SIZE(descriptor_writes)) + if (write_count == ARRAY_SIZE(descriptor_writes)) { - VK_CALL(vkUpdateDescriptorSets(vk_device, descriptor_count, descriptor_writes, 0, NULL)); - descriptor_count = 0; + VK_CALL(vkUpdateDescriptorSets(vk_device, write_count, descriptor_writes, 0, NULL)); + write_count = 0; current_descriptor_write = descriptor_writes; current_image_info = image_infos; } } }
- VK_CALL(vkUpdateDescriptorSets(vk_device, descriptor_count, descriptor_writes, 0, NULL)); + VK_CALL(vkUpdateDescriptorSets(vk_device, write_count, descriptor_writes, 0, NULL)); }
static bool vk_write_descriptor_set_from_root_descriptor(VkWriteDescriptorSet *vk_descriptor_write, @@ -2853,7 +2943,7 @@ static void d3d12_command_list_update_uav_counter_descriptors(struct d3d12_comma if (!(vk_descriptor_writes = vkd3d_calloc(uav_counter_count, sizeof(*vk_descriptor_writes)))) return; if (!(vk_descriptor_set = d3d12_command_allocator_allocate_descriptor_set(list->allocator, - state->uav_counters.vk_set_layout))) + state->uav_counters.vk_set_layout, 0, false))) goto done;
for (i = 0; i < uav_counter_count; ++i) @@ -4954,7 +5044,7 @@ static void d3d12_command_list_clear_uav(struct d3d12_command_list *list, }
if (!(write_set.dstSet = d3d12_command_allocator_allocate_descriptor_set( - list->allocator, pipeline.vk_set_layout))) + list->allocator, pipeline.vk_set_layout, 0, false))) { ERR("Failed to allocate descriptor set.\n"); return; diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 0fadb521..795ff899 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -2231,6 +2231,7 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface) vkd3d_fence_worker_stop(&device->fence_worker, device); d3d12_device_destroy_pipeline_cache(device); d3d12_device_destroy_vkd3d_queues(device); + vkd3d_free(device->descriptor_heaps); for (i = 0; i < ARRAY_SIZE(device->desc_mutex); ++i) pthread_mutex_destroy(&device->desc_mutex[i]); VK_CALL(vkDestroyDevice(device->vk_device, NULL)); @@ -3737,6 +3738,10 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, if ((device->parent = create_info->parent)) IUnknown_AddRef(device->parent);
+ device->descriptor_heap_capacity = 0; + device->descriptor_heap_count = 0; + device->descriptor_heaps = NULL; + return S_OK;
out_destroy_null_resources: @@ -3792,6 +3797,72 @@ void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason, device->removed_reason = reason; }
+void d3d12_device_track_descriptor_heap(struct d3d12_device *device, + const struct d3d12_descriptor_heap *heap) +{ + if (!device->vk_info.EXT_descriptor_indexing) + return; + + if (!vkd3d_array_reserve((void **)&device->descriptor_heaps, &device->descriptor_heap_capacity, + device->descriptor_heap_count + 1, sizeof(*device->descriptor_heaps))) + { + ERR("Out of memory. Cannot track descriptor heap for unbounded arrays.\n"); + return; + } + + device->descriptor_heaps[device->descriptor_heap_count++] = heap; + /* Do not increment the heap reference count. This reference is deleted on heap destruction. */ +} + +void d3d12_device_untrack_descriptor_heap(struct d3d12_device *device, + const struct d3d12_descriptor_heap *heap) +{ + size_t i; + + if (!device->vk_info.EXT_descriptor_indexing) + return; + + for (i = 0; i < device->descriptor_heap_count; ++i) + { + if (device->descriptor_heaps[i] != heap) + continue; + + memmove(&device->descriptor_heaps[i], &device->descriptor_heaps[i + 1], + (device->descriptor_heap_count - i - 1) * sizeof(*device->descriptor_heaps)); + --device->descriptor_heap_count; + + return; + } + + ERR("Attempted to untrack an already untracked heap.\n"); +} + +/* Return the available size from the specified descriptor to the heap end. */ +uint32_t d3d12_device_descriptor_heap_size_from_descriptor(struct d3d12_device *device, + const struct d3d12_desc *desc) +{ + size_t i; + + for (i = 0; i < device->descriptor_heap_count; ++i) + { + unsigned int size; + size_t offset; + + if (device->descriptor_heaps[i]->descriptors > (const BYTE*)desc) + continue; + + size = d3d12_device_get_descriptor_handle_increment_size(device, device->descriptor_heaps[i]->desc.Type); + offset = ((const BYTE*)desc - device->descriptor_heaps[i]->descriptors) / size; + if (device->descriptor_heaps[i]->desc.NumDescriptors <= offset) + continue; + + return device->descriptor_heaps[i]->desc.NumDescriptors - (uint32_t)offset; + } + + ERR("Failed to find descriptor heap size from descriptor pointer.\n"); + return 0; +} + HRESULT vkd3d_create_thread(struct vkd3d_instance *instance, PFN_vkd3d_thread thread_main, void *data, union vkd3d_thread_handle *thread) { diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 1ca23a90..5d768b30 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -3337,6 +3337,7 @@ static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHea { struct d3d12_device *device = heap->device; unsigned int i; + int rc;
vkd3d_private_store_destroy(&heap->private_store);
@@ -3382,6 +3383,12 @@ static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHea
vkd3d_free(heap);
+ if ((rc = pthread_mutex_lock(&device->mutex))) + ERR("Failed to lock mutex, error %d.\n", rc); + d3d12_device_untrack_descriptor_heap(device, heap); + if (!rc) + pthread_mutex_unlock(&device->mutex); + d3d12_device_release(device); }
@@ -3514,6 +3521,7 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device, size_t max_descriptor_count, descriptor_size; struct d3d12_descriptor_heap *object; HRESULT hr; + int rc;
if (!(descriptor_size = d3d12_device_get_descriptor_handle_increment_size(device, desc->Type))) { @@ -3547,6 +3555,12 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
memset(object->descriptors, 0, descriptor_size * desc->NumDescriptors);
+ if ((rc = pthread_mutex_lock(&device->mutex))) + ERR("Failed to lock mutex, error %d.\n", rc); + d3d12_device_track_descriptor_heap(device, object); + if (!rc) + pthread_mutex_unlock(&device->mutex); + TRACE("Created descriptor heap %p.\n", object);
*descriptor_heap = object; diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 58463e59..38948bf9 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -1,6 +1,7 @@ /* * Copyright 2016 Józef Kucia for CodeWeavers * Copyright 2016 Henri Verbeet for CodeWeavers + * Copyright 2021 Conor McCarthy for Codeweavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -325,6 +326,7 @@ struct d3d12_root_signature_info static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_signature_info *info, const D3D12_ROOT_DESCRIPTOR_TABLE *table, bool use_array) { + bool unbounded = false; unsigned int i;
for (i = 0; i < table->NumDescriptorRanges; ++i) @@ -332,14 +334,33 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig const D3D12_DESCRIPTOR_RANGE *range = &table->pDescriptorRanges[i]; unsigned int binding_count;
- if (range->NumDescriptors == 0xffffffff) - { - FIXME("Unhandled unbound descriptor range.\n"); - return E_NOTIMPL; + if (unbounded) + { + if (range->NumDescriptors != UINT_MAX) + { + ERR("Static range occurs after unbounded range.\n"); + return E_INVALIDARG; + } + if (range->OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + { + ERR("Unbounded range with offset D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND occurs after " + "another unbounded range.\n"); + return E_INVALIDARG; + } }
binding_count = use_array ? 1 : range->NumDescriptors;
+ if (range->NumDescriptors == UINT_MAX) + { + if (!use_array) + { + FIXME("The device does not support unbounded descriptor ranges.\n"); + return E_NOTIMPL; + } + unbounded = true; + } + switch (range->RangeType) { case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: @@ -515,6 +536,8 @@ struct vkd3d_descriptor_set_context { VkDescriptorSetLayoutBinding *current_binding; VkDescriptorSetLayoutBinding *first_binding; + unsigned int table_index; + unsigned int unbounded_offset; unsigned int descriptor_index; uint32_t descriptor_binding; }; @@ -533,7 +556,7 @@ static bool vkd3d_validate_descriptor_set_count(struct d3d12_device *device, uns }
static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, - VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, + VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, bool unbounded, const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout);
static HRESULT d3d12_root_signature_append_descriptor_set_layout(struct d3d12_root_signature *root_signature, @@ -548,9 +571,11 @@ static HRESULT d3d12_root_signature_append_descriptor_set_layout(struct d3d12_ro return E_INVALIDARG;
if (FAILED(hr = vkd3d_create_descriptor_set_layout(root_signature->device, - flags, context->descriptor_binding, context->first_binding, + flags, context->descriptor_binding, context->unbounded_offset != UINT_MAX, context->first_binding, &root_signature->vk_set_layouts[root_signature->vk_set_count]))) return hr; + root_signature->vk_set_layout_table_indices[root_signature->vk_set_count] = context->table_index; + root_signature->vk_set_layout_unbounded_offsets[root_signature->vk_set_count] = context->unbounded_offset; ++root_signature->vk_set_count;
context->current_binding = context->first_binding; @@ -575,6 +600,9 @@ static void d3d12_root_signature_append_vk_binding(struct d3d12_root_signature * mapping->binding.set = root_signature->vk_set_count; mapping->binding.binding = context->descriptor_binding++; mapping->binding.count = descriptor_count; + + if (context->unbounded_offset != UINT_MAX) + d3d12_root_signature_append_descriptor_set_layout(root_signature, context, 0); }
static uint32_t d3d12_root_signature_assign_vk_bindings(struct d3d12_root_signature *root_signature, @@ -621,6 +649,15 @@ static uint32_t vkd3d_descriptor_magic_from_d3d12(D3D12_DESCRIPTOR_RANGE_TYPE ty } }
+static unsigned int vk_binding_count_from_descriptor_range(const struct d3d12_root_descriptor_table_range *range) +{ + if (range->descriptor_count != UINT_MAX) + return range->descriptor_count; + + /* TODO: Calculate an upper bound from unbounded set counts and Vulkan device limits. */ + return 1024; +} + static HRESULT d3d12_root_signature_init_descriptor_array_binding(struct d3d12_root_signature *root_signature, const struct d3d12_root_descriptor_table_range *range, D3D12_SHADER_VISIBILITY visibility, struct vkd3d_descriptor_set_context *context) @@ -629,28 +666,81 @@ static HRESULT d3d12_root_signature_init_descriptor_array_binding(struct d3d12_r bool is_buffer = range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV; enum vkd3d_shader_descriptor_type descriptor_type = range->type;
+ if (range->descriptor_count == UINT_MAX) + context->unbounded_offset = range->offset; + if (descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV || descriptor_type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) { if (!vk_binding_from_d3d12_descriptor_range(context->current_binding, - descriptor_type, visibility, true, context->descriptor_binding, range->descriptor_count)) + descriptor_type, visibility, true, context->descriptor_binding, range->vk_binding_count)) return E_NOTIMPL; ++context->current_binding;
d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->register_space, - range->base_register_idx, true, shader_visibility, range->descriptor_count, context); + range->base_register_idx, true, shader_visibility, range->vk_binding_count, context); }
if (!vk_binding_from_d3d12_descriptor_range(context->current_binding, - descriptor_type, visibility, is_buffer, context->descriptor_binding, range->descriptor_count)) + descriptor_type, visibility, is_buffer, context->descriptor_binding, range->vk_binding_count)) return E_NOTIMPL; ++context->current_binding;
d3d12_root_signature_append_vk_binding(root_signature, descriptor_type, range->register_space, - range->base_register_idx, is_buffer, shader_visibility, range->descriptor_count, context); + range->base_register_idx, is_buffer, shader_visibility, range->vk_binding_count, context); + + context->unbounded_offset = UINT_MAX;
return S_OK; }
+static void d3d12_root_signature_map_vk_unbounded_binding(struct d3d12_root_signature *root_signature, + const struct d3d12_root_descriptor_table_range *range, unsigned int binding_offset, bool buffer_descriptor, + enum vkd3d_shader_visibility shader_visibility, struct vkd3d_descriptor_set_context *context) +{ + struct vkd3d_shader_resource_binding *mapping + = &root_signature->descriptor_mapping[context->descriptor_index++]; + + mapping->type = range->type; + mapping->register_space = range->register_space; + mapping->register_index = range->base_register_idx; + mapping->shader_visibility = shader_visibility; + mapping->flags = buffer_descriptor ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE; + mapping->binding.set = root_signature->main_set + range->set + ((range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV + || range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) && !buffer_descriptor); + mapping->binding.binding = range->binding; + mapping->binding.count = range->vk_binding_count; +} + +static void d3d12_root_signature_map_descriptor_unbounded_binding(struct d3d12_root_signature *root_signature, + const struct d3d12_root_descriptor_table_range *range, unsigned int binding_offset, + enum vkd3d_shader_visibility shader_visibility, struct vkd3d_descriptor_set_context *context) +{ + bool is_buffer = range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_CBV; + + if (range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SRV || range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) + d3d12_root_signature_map_vk_unbounded_binding(root_signature, range, + binding_offset, true, shader_visibility, context); + + d3d12_root_signature_map_vk_unbounded_binding(root_signature, range, + binding_offset, is_buffer, shader_visibility, context); +} + +static int compare_range(const void *a, const void *b) +{ + const struct d3d12_root_descriptor_table_range *range_a = a, *range_b = b; + int unbounded_a, unbounded_b; + + if (range_a->descriptor_magic != range_b->descriptor_magic) + return range_a->descriptor_magic - range_b->descriptor_magic; + + unbounded_a = range_a->descriptor_count == UINT_MAX; + unbounded_b = range_b->descriptor_count == UINT_MAX; + if (unbounded_a != unbounded_b) + return unbounded_a - unbounded_b; + + return range_a->offset - range_b->offset; +} + static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_root_signature *root_signature, const D3D12_ROOT_SIGNATURE_DESC *desc, struct vkd3d_descriptor_set_context *context) { @@ -681,6 +771,8 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo if (!(table->ranges = vkd3d_calloc(table->range_count, sizeof(*table->ranges)))) return E_OUTOFMEMORY;
+ context->table_index = i; + for (j = 0; j < range_count; ++j) { const D3D12_DESCRIPTOR_RANGE *range = &p->u.DescriptorTable.pDescriptorRanges[j]; @@ -688,7 +780,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo if (range->OffsetInDescriptorsFromTableStart != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) offset = range->OffsetInDescriptorsFromTableStart;
- if (!vkd3d_bound_range(offset, range->NumDescriptors, UINT_MAX)) + if (range->NumDescriptors != UINT_MAX && !vkd3d_bound_range(offset, range->NumDescriptors, UINT_MAX)) return E_INVALIDARG;
table->ranges[j].offset = offset; @@ -701,18 +793,48 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo TRACE("Descriptor table %u, range %u, offset %u, type %#x, count %u.\n", i, j, offset, range->RangeType, range->NumDescriptors);
+ /* If NumDescriptors == UINT_MAX, validation during counting ensures this offset is not used. */ offset += range->NumDescriptors; }
+ qsort(table->ranges, range_count, sizeof(*table->ranges), compare_range); + for (j = 0; j < range_count; ++j) { struct d3d12_root_descriptor_table_range *range; VkDescriptorSetLayoutBinding *cur_binding; + unsigned int offset; + range = &table->ranges[j];
+ range->set = root_signature->vk_set_count - root_signature->main_set; + if (root_signature->use_descriptor_arrays) { + if (j && range->descriptor_magic == range[-1].descriptor_magic && range->descriptor_count == UINT_MAX + && range[-1].descriptor_count == UINT_MAX) + { + unsigned int rel_offset = range->offset - range[-1].offset; + + if (rel_offset >= range[-1].vk_binding_count) + { + ERR("Available binding size of %u is insufficient for an offset of %u.\n", + range[-1].vk_binding_count, rel_offset); + continue; + } + + range->set = range[-1].set; + range->binding = range[-1].binding; + range->vk_binding_count = range[-1].vk_binding_count - rel_offset; + d3d12_root_signature_map_descriptor_unbounded_binding(root_signature, range, + range->offset - offset, shader_visibility, context); + continue; + } + + offset = range->offset; + range->binding = context->descriptor_binding; + range->vk_binding_count = vk_binding_count_from_descriptor_range(range);
if (FAILED(hr = d3d12_root_signature_init_descriptor_array_binding(root_signature, range, p->ShaderVisibility, context))) @@ -752,6 +874,7 @@ static HRESULT d3d12_root_signature_init_root_descriptor_tables(struct d3d12_roo ++cur_binding; }
+ table->ranges[j].vk_binding_count = table->ranges[j].descriptor_count; table->ranges[j].binding = vk_binding;
context->current_binding = cur_binding; @@ -849,7 +972,7 @@ static bool vk_binding_uses_partial_binding(const VkDescriptorSetLayoutBinding * }
static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, - VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, + VkDescriptorSetLayoutCreateFlags flags, unsigned int binding_count, bool unbounded, const VkDescriptorSetLayoutBinding *bindings, VkDescriptorSetLayout *set_layout) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; @@ -868,7 +991,7 @@ static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, unsigned int i;
for (i = 0; i < binding_count; ++i) - if (vk_binding_uses_partial_binding(&bindings[i])) + if (unbounded || vk_binding_uses_partial_binding(&bindings[i])) break;
if (i < binding_count) @@ -880,6 +1003,10 @@ static HRESULT vkd3d_create_descriptor_set_layout(struct d3d12_device *device, set_flags[i] = vk_binding_uses_partial_binding(&bindings[i]) ? VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT : 0;
+ if (unbounded) + set_flags[binding_count - 1] = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT + | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; + flags_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; flags_info.pNext = NULL; flags_info.bindingCount = binding_count; @@ -909,6 +1036,9 @@ static HRESULT vkd3d_create_pipeline_layout(struct d3d12_device *device, struct VkPipelineLayoutCreateInfo pipeline_layout_info; VkResult vr;
+ if (!vkd3d_validate_descriptor_set_count(device, set_layout_count)) + return E_INVALIDARG; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_info.pNext = NULL; pipeline_layout_info.flags = 0; @@ -936,6 +1066,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa HRESULT hr;
memset(&context, 0, sizeof(context)); + context.unbounded_offset = UINT_MAX; binding_desc = NULL;
root_signature->ID3D12RootSignature_iface.lpVtbl = &d3d12_root_signature_vtbl; @@ -999,6 +1130,8 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa goto fail; }
+ root_signature->main_set = root_signature->vk_set_count; + if (FAILED(hr = d3d12_root_signature_init_push_constants(root_signature, desc, root_signature->push_constant_ranges, &root_signature->push_constant_range_count))) goto fail; @@ -1007,8 +1140,6 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa if (FAILED(hr = d3d12_root_signature_init_root_descriptor_tables(root_signature, desc, &context))) goto fail;
- root_signature->main_set = root_signature->vk_set_count; - if (FAILED(hr = d3d12_root_signature_append_descriptor_set_layout(root_signature, &context, 0))) goto fail;
@@ -1652,7 +1783,7 @@ static HRESULT d3d12_pipeline_state_init_uav_counters(struct d3d12_pipeline_stat
/* Create a descriptor set layout for UAV counters. */ hr = vkd3d_create_descriptor_set_layout(device, - 0, descriptor_binding, binding_desc, &state->uav_counters.vk_set_layout); + 0, descriptor_binding, false, binding_desc, &state->uav_counters.vk_set_layout); vkd3d_free(binding_desc); if (FAILED(hr)) { @@ -3122,7 +3253,8 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d { set_binding.descriptorType = set_layouts[i].descriptor_type;
- if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0, 1, &set_binding, set_layouts[i].set_layout))) + if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0, 1, false, + &set_binding, set_layouts[i].set_layout))) { ERR("Failed to create descriptor set layout %u, hr %#x.\n", i, hr); goto fail; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 0b326b11..d39893bb 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -54,7 +54,7 @@ #define VKD3D_MAX_SHADER_EXTENSIONS 2u #define VKD3D_MAX_SHADER_STAGES 5u #define VKD3D_MAX_VK_SYNC_OBJECTS 4u -#define VKD3D_MAX_DESCRIPTOR_SETS 2u +#define VKD3D_MAX_DESCRIPTOR_SETS 64u
struct d3d12_command_list; struct d3d12_device; @@ -647,6 +647,8 @@ struct d3d12_root_descriptor_table_range { unsigned int offset; unsigned int descriptor_count; + unsigned int vk_binding_count; + uint32_t set; uint32_t binding;
enum vkd3d_shader_descriptor_type type; @@ -692,6 +694,8 @@ struct d3d12_root_signature VkPipelineLayout vk_pipeline_layout; uint32_t vk_set_count; VkDescriptorSetLayout vk_set_layouts[VKD3D_MAX_DESCRIPTOR_SETS]; + unsigned int vk_set_layout_unbounded_offsets[VKD3D_MAX_DESCRIPTOR_SETS]; + unsigned int vk_set_layout_table_indices[VKD3D_MAX_DESCRIPTOR_SETS]; bool use_descriptor_arrays;
struct d3d12_root_parameter *parameters; @@ -912,8 +916,9 @@ struct vkd3d_pipeline_bindings const struct d3d12_root_signature *root_signature;
VkPipelineBindPoint vk_bind_point; + /* All descriptor sets at index > 1 are for unbounded D3D12 ranges. Set 0 or 1 may be unbounded too. */ size_t descriptor_set_count; - VkDescriptorSet descriptor_sets[VKD3D_MAX_DESCRIPTOR_SETS - 1]; + VkDescriptorSet descriptor_sets[VKD3D_MAX_DESCRIPTOR_SETS]; bool in_use;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_tables[D3D12_MAX_ROOT_COST]; @@ -1165,6 +1170,10 @@ struct d3d12_device const struct vkd3d_format_compatibility_list *format_compatibility_lists; struct vkd3d_null_resources null_resources; struct vkd3d_uav_clear_state uav_clear_state; + + size_t descriptor_heap_capacity; + size_t descriptor_heap_count; + const struct d3d12_descriptor_heap **descriptor_heaps; };
HRESULT d3d12_device_create(struct vkd3d_instance *instance, @@ -1175,6 +1184,11 @@ void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason, const char *message, ...) VKD3D_PRINTF_FUNC(3, 4); struct d3d12_device *unsafe_impl_from_ID3D12Device(ID3D12Device *iface);
+void d3d12_device_track_descriptor_heap(struct d3d12_device *device, const struct d3d12_descriptor_heap *heap); +void d3d12_device_untrack_descriptor_heap(struct d3d12_device *device, const struct d3d12_descriptor_heap *heap); +uint32_t d3d12_device_descriptor_heap_size_from_descriptor(struct d3d12_device *device, + const struct d3d12_desc *desc); + static inline HRESULT d3d12_device_query_interface(struct d3d12_device *device, REFIID iid, void **object) { return ID3D12Device_QueryInterface(&device->ID3D12Device_iface, iid, object); diff --git a/tests/d3d12.c b/tests/d3d12.c index 618c2291..bd3ef624 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -34887,7 +34887,6 @@ static void test_unbounded_resource_arrays(void) root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters); root_signature_desc.pParameters = root_parameters; hr = create_root_signature(device, &root_signature_desc, &context.root_signature); - todo ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr); if (FAILED(hr)) goto done; @@ -34961,6 +34960,7 @@ static void test_unbounded_resource_arrays(void) D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); get_buffer_readback_with_command_list(output_buffers[i], DXGI_FORMAT_R32_UINT, &rb, queue, command_list); /* Buffers at index >= 64 are aliased. */ + todo_if(i != 10 && i != 74) check_readback_data_uint(&rb, NULL, (i < 64 ? 63 - i : 127 - i) ^ 0x35, 0); release_resource_readback(&rb); reset_command_list(command_list, context.allocator); @@ -35050,7 +35050,6 @@ static void test_unbounded_samplers(void) root_signature_desc.pParameters = root_parameters;
hr = create_root_signature(device, &root_signature_desc, &context.root_signature); - todo ok(SUCCEEDED(hr), "Failed to create root signature, hr %#x.\n", hr); if (FAILED(hr)) goto done; @@ -35108,6 +35107,7 @@ static void test_unbounded_samplers(void) { unsigned int value = get_readback_uint(&rb, i, 0, 0); unsigned int expected = (i & 1) ? 100 : 10; + todo_if(i & 1) ok(value == expected, "Got %u, expected %u at %u.\n", value, expected, i); } release_resource_readback(&rb);
On Fri, 13 Aug 2021 at 16:57, Conor McCarthy cmccarthy@codeweavers.com wrote:
@@ -2581,9 +2594,44 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li * by an update command, or freed) between when the command is recorded * and when the command completes executing on the queue." */
- bindings->descriptor_sets[0] = d3d12_command_allocator_allocate_descriptor_set(list->allocator,
root_signature->vk_set_layouts[root_signature->main_set]);
- bindings->descriptor_set_count = 1;
- bindings->descriptor_set_count = 0;
- for (i = root_signature->main_set; i < root_signature->vk_set_count; ++i)
- {
unsigned int unbounded_range_offset = root_signature->vk_set_layout_unbounded_offsets[i];
unsigned int unbounded_table = root_signature->vk_set_layout_table_indices[i];
unsigned int variable_binding_size = 0;
if (unbounded_range_offset != UINT_MAX)
{
const struct d3d12_desc *base_descriptor
= d3d12_desc_from_gpu_handle(bindings->descriptor_tables[unbounded_table]);
/* Descriptors may not be set, eg. WoW. */
if (base_descriptor)
{
unsigned int heap_size;
int rc;
rc = pthread_mutex_lock(&device->mutex);
if (rc)
ERR("Failed to lock mutex, error %d.\n", rc);
heap_size = d3d12_device_descriptor_heap_size_from_descriptor(device, base_descriptor);
if (!rc)
pthread_mutex_unlock(&device->mutex);
Would it make sense to do the locking for d3d12_device_descriptor_heap_size_from_descriptor() inside that function? Doing it outside the function is perhaps a little more flexible, but it doesn't seem to gain us much here.
@@ -2687,7 +2749,31 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list
descriptor = base_descriptor + range->offset;
for (j = 0; j < range->descriptor_count; ++j, ++descriptor)
descriptor_count = range->descriptor_count;
if (descriptor_count == UINT_MAX)
{
int rc;
/* The first unbounded range of each type is written until the heap end is reached. Do not repeat. */
if (i && range[-1].descriptor_magic == range->descriptor_magic && range[-1].descriptor_count == UINT_MAX)
continue;
I get that "range[-1]" is convenient, but I don't like it much. There are a few more instances of this in this patch.
+void d3d12_device_track_descriptor_heap(struct d3d12_device *device,
const struct d3d12_descriptor_heap *heap)
+{
- if (!device->vk_info.EXT_descriptor_indexing)
return;
- if (!vkd3d_array_reserve((void **)&device->descriptor_heaps, &device->descriptor_heap_capacity,
device->descriptor_heap_count + 1, sizeof(*device->descriptor_heaps)))
- {
ERR("Out of memory. Cannot track descriptor heap for unbounded arrays.\n");
return;
- }
- device->descriptor_heaps[device->descriptor_heap_count++] = heap;
- /* Do not increment the heap reference count. This reference is deleted on heap destruction. */
+}
It seems like it would make sense to group the "descriptor_heaps", "descriptor_heap_capacity", and "descriptor_heap_count" fields together in their own structure, similar to how that's done for e.g. struct vkd3d_render_pass_cache.
+void d3d12_device_untrack_descriptor_heap(struct d3d12_device *device,
const struct d3d12_descriptor_heap *heap)
+{
- size_t i;
- if (!device->vk_info.EXT_descriptor_indexing)
return;
- for (i = 0; i < device->descriptor_heap_count; ++i)
- {
if (device->descriptor_heaps[i] != heap)
continue;
memmove(&device->descriptor_heaps[i], &device->descriptor_heaps[i + 1],
(device->descriptor_heap_count - i - 1) * sizeof(*device->descriptor_heaps));
--device->descriptor_heap_count;
return;
- }
- ERR("Attempted to untrack an already untracked heap.\n");
+}
If we don't need to maintain the order in which heaps were inserted, we don't really need to use memmove() here; we'd only need to move the last element to the index of the element that's to be removed.
+/* Return the available size from the specified descriptor to the heap end. */ +uint32_t d3d12_device_descriptor_heap_size_from_descriptor(struct d3d12_device *device,
const struct d3d12_desc *desc)
+{
- size_t i;
- for (i = 0; i < device->descriptor_heap_count; ++i)
- {
unsigned int size;
size_t offset;
if (device->descriptor_heaps[i]->descriptors > (const BYTE*)desc)
continue;
size = d3d12_device_get_descriptor_handle_increment_size(device, device->descriptor_heaps[i]->desc.Type);
offset = ((const BYTE*)desc - device->descriptor_heaps[i]->descriptors) / size;
if (device->descriptor_heaps[i]->desc.NumDescriptors <= offset)
continue;
return device->descriptor_heaps[i]->desc.NumDescriptors - (uint32_t)offset;
- }
- ERR("Failed to find descriptor heap size from descriptor pointer.\n");
- return 0;
+}
Presumably we could just skip checking heaps that don't have the correct type, and then "size" would always be "sizeof(*desc)".
@@ -3547,6 +3555,12 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
memset(object->descriptors, 0, descriptor_size * desc->NumDescriptors);
- if ((rc = pthread_mutex_lock(&device->mutex)))
ERR("Failed to lock mutex, error %d.\n", rc);
- d3d12_device_track_descriptor_heap(device, object);
- if (!rc)
pthread_mutex_unlock(&device->mutex);
Do we need to track RTV and DSV heaps?
@@ -332,14 +334,33 @@ static HRESULT d3d12_root_signature_info_count_descriptors(struct d3d12_root_sig const D3D12_DESCRIPTOR_RANGE *range = &table->pDescriptorRanges[i]; unsigned int binding_count;
if (range->NumDescriptors == 0xffffffff)
{
FIXME("Unhandled unbound descriptor range.\n");
return E_NOTIMPL;
if (unbounded)
{
Some stray whitespace above.
if (range->NumDescriptors != UINT_MAX)
{
ERR("Static range occurs after unbounded range.\n");
return E_INVALIDARG;
}
if (range->OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
{
ERR("Unbounded range with offset D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND occurs after "
"another unbounded range.\n");
return E_INVALIDARG;
} } binding_count = use_array ? 1 : range->NumDescriptors;
if (range->NumDescriptors == UINT_MAX)
{
if (!use_array)
{
FIXME("The device does not support unbounded descriptor ranges.\n");
return E_NOTIMPL;
}
unbounded = true;
}
The validation changes above could perhaps be in a separate patch.
@@ -692,6 +694,8 @@ struct d3d12_root_signature VkPipelineLayout vk_pipeline_layout; uint32_t vk_set_count; VkDescriptorSetLayout vk_set_layouts[VKD3D_MAX_DESCRIPTOR_SETS];
- unsigned int vk_set_layout_unbounded_offsets[VKD3D_MAX_DESCRIPTOR_SETS];
- unsigned int vk_set_layout_table_indices[VKD3D_MAX_DESCRIPTOR_SETS]; bool use_descriptor_arrays;
Like the descriptor heap tracking fields mentioned earlier, it seems like it would make sense to group the "vk_set_layouts", "vk_set_layout_unbounded_offsets", and "vk_set_layout_table_indices" together in their own structure.
Prevents an unhandled flag from causing all flags to be skipped. Based in part on a vkd3d-proton patch by Philip Rebohle.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d-shader/dxbc.c | 13 ++++++++----- libs/vkd3d-shader/sm4.h | 8 ++++---- 2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index fab19046..412b9267 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -1133,8 +1133,9 @@ static bool shader_sm4_read_param(struct vkd3d_sm4_data *priv, const DWORD **ptr return false; } m = *(*ptr)++; + m = (m & VKD3D_SM4_REGISTER_MODIFIER_MASK) >> VKD3D_SM4_REGISTER_MODIFIER_SHIFT;
- switch (m) + switch (m & (VKD3D_SM4_REGISTER_MODIFIER_ABS | VKD3D_SM4_REGISTER_MODIFIER_NEGATE)) { case VKD3D_SM4_REGISTER_MODIFIER_NEGATE: *modifier = VKD3DSPSM_NEG; @@ -1144,17 +1145,19 @@ static bool shader_sm4_read_param(struct vkd3d_sm4_data *priv, const DWORD **ptr *modifier = VKD3DSPSM_ABS; break;
- case VKD3D_SM4_REGISTER_MODIFIER_ABS_NEGATE: + case VKD3D_SM4_REGISTER_MODIFIER_ABS | VKD3D_SM4_REGISTER_MODIFIER_NEGATE: *modifier = VKD3DSPSM_ABSNEG; break;
default: - FIXME("Skipping modifier 0x%08x.\n", m); - /* fall-through */ - case VKD3D_SM4_REGISTER_MODIFIER_NONE: *modifier = VKD3DSPSM_NONE; break; } + m &= ~(VKD3D_SM4_REGISTER_MODIFIER_ABS | VKD3D_SM4_REGISTER_MODIFIER_NEGATE); + + if (m) + FIXME("Skipping modifier flags 0x%08x.\n", m); + } else { diff --git a/libs/vkd3d-shader/sm4.h b/libs/vkd3d-shader/sm4.h index 335f0161..e8dbeb4b 100644 --- a/libs/vkd3d-shader/sm4.h +++ b/libs/vkd3d-shader/sm4.h @@ -94,6 +94,8 @@ #define VKD3D_SM4_OPCODE_MASK 0xff
#define VKD3D_SM4_REGISTER_MODIFIER (0x1u << 31) +#define VKD3D_SM4_REGISTER_MODIFIER_SHIFT 1 +#define VKD3D_SM4_REGISTER_MODIFIER_MASK (0x7FFFFFFF << VKD3D_SM4_REGISTER_MODIFIER_SHIFT)
#define VKD3D_SM4_ADDRESSING_SHIFT2 28 #define VKD3D_SM4_ADDRESSING_MASK2 (0x3u << VKD3D_SM4_ADDRESSING_SHIFT2) @@ -383,10 +385,8 @@ enum vkd3d_sm4_register_type
enum vkd3d_sm4_register_modifier { - VKD3D_SM4_REGISTER_MODIFIER_NONE = 0x01, - VKD3D_SM4_REGISTER_MODIFIER_NEGATE = 0x41, - VKD3D_SM4_REGISTER_MODIFIER_ABS = 0x81, - VKD3D_SM4_REGISTER_MODIFIER_ABS_NEGATE = 0xc1, + VKD3D_SM4_REGISTER_MODIFIER_NEGATE = 0x20, + VKD3D_SM4_REGISTER_MODIFIER_ABS = 0x40, };
enum vkd3d_sm4_output_primitive_type
On 8/13/21 9:55 AM, Conor McCarthy wrote:
Prevents an unhandled flag from causing all flags to be skipped. Based in part on a vkd3d-proton patch by Philip Rebohle.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com
libs/vkd3d-shader/dxbc.c | 13 ++++++++----- libs/vkd3d-shader/sm4.h | 8 ++++---- 2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index fab19046..412b9267 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -1133,8 +1133,9 @@ static bool shader_sm4_read_param(struct vkd3d_sm4_data *priv, const DWORD **ptr return false; } m = *(*ptr)++;
m = (m & VKD3D_SM4_REGISTER_MODIFIER_MASK) >> VKD3D_SM4_REGISTER_MODIFIER_SHIFT;
switch (m)
switch (m & (VKD3D_SM4_REGISTER_MODIFIER_ABS | VKD3D_SM4_REGISTER_MODIFIER_NEGATE)) { case VKD3D_SM4_REGISTER_MODIFIER_NEGATE: *modifier = VKD3DSPSM_NEG;
@@ -1144,17 +1145,19 @@ static bool shader_sm4_read_param(struct vkd3d_sm4_data *priv, const DWORD **ptr *modifier = VKD3DSPSM_ABS; break;
case VKD3D_SM4_REGISTER_MODIFIER_ABS_NEGATE:
case VKD3D_SM4_REGISTER_MODIFIER_ABS | VKD3D_SM4_REGISTER_MODIFIER_NEGATE: *modifier = VKD3DSPSM_ABSNEG; break; default:
FIXME("Skipping modifier 0x%08x.\n", m);
/* fall-through */
case VKD3D_SM4_REGISTER_MODIFIER_NONE: *modifier = VKD3DSPSM_NONE; break; }
m &= ~(VKD3D_SM4_REGISTER_MODIFIER_ABS | VKD3D_SM4_REGISTER_MODIFIER_NEGATE);
if (m)
FIXME("Skipping modifier flags 0x%08x.\n", m);
} else {
diff --git a/libs/vkd3d-shader/sm4.h b/libs/vkd3d-shader/sm4.h index 335f0161..e8dbeb4b 100644 --- a/libs/vkd3d-shader/sm4.h +++ b/libs/vkd3d-shader/sm4.h @@ -94,6 +94,8 @@ #define VKD3D_SM4_OPCODE_MASK 0xff
#define VKD3D_SM4_REGISTER_MODIFIER (0x1u << 31) +#define VKD3D_SM4_REGISTER_MODIFIER_SHIFT 1 +#define VKD3D_SM4_REGISTER_MODIFIER_MASK (0x7FFFFFFF << VKD3D_SM4_REGISTER_MODIFIER_SHIFT)
#define VKD3D_SM4_ADDRESSING_SHIFT2 28 #define VKD3D_SM4_ADDRESSING_MASK2 (0x3u << VKD3D_SM4_ADDRESSING_SHIFT2) @@ -383,10 +385,8 @@ enum vkd3d_sm4_register_type
enum vkd3d_sm4_register_modifier {
- VKD3D_SM4_REGISTER_MODIFIER_NONE = 0x01,
- VKD3D_SM4_REGISTER_MODIFIER_NEGATE = 0x41,
- VKD3D_SM4_REGISTER_MODIFIER_ABS = 0x81,
- VKD3D_SM4_REGISTER_MODIFIER_ABS_NEGATE = 0xc1,
VKD3D_SM4_REGISTER_MODIFIER_NEGATE = 0x20,
VKD3D_SM4_REGISTER_MODIFIER_ABS = 0x40, };
enum vkd3d_sm4_output_primitive_type
For what it's worth, according to Microsoft ([1] s.v. D3D10_SB_OPERAND_MODIFIER) the shift and mask here is different. Not that we necessarily have to follow that, though.
[1] https://github.com/microsoft/DirectXShaderCompiler/blob/cb485263b75495015e2a...
Based on vkd3d-proton patches by Philip Rebohle and Hans-Kristian Arntzen.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d-shader/dxbc.c | 7 ++++ libs/vkd3d-shader/sm4.h | 1 + libs/vkd3d-shader/spirv.c | 42 ++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 7 ++++ tests/d3d12.c | 3 +- 5 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 412b9267..9371e262 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -1121,6 +1121,7 @@ static bool shader_sm4_read_param(struct vkd3d_sm4_data *priv, const DWORD **ptr { param->type = register_type_table[register_type]; } + param->modifier = VKD3DSPRM_NONE; param->data_type = data_type;
if (token & VKD3D_SM4_REGISTER_MODIFIER) @@ -1155,6 +1156,12 @@ static bool shader_sm4_read_param(struct vkd3d_sm4_data *priv, const DWORD **ptr } m &= ~(VKD3D_SM4_REGISTER_MODIFIER_ABS | VKD3D_SM4_REGISTER_MODIFIER_NEGATE);
+ if (m & VKD3D_SM4_REGISTER_MODIFIER_NONUNIFORM) + { + param->modifier = VKD3DSPRM_NONUNIFORM; + m &= ~VKD3D_SM4_REGISTER_MODIFIER_NONUNIFORM; + } + if (m) FIXME("Skipping modifier flags 0x%08x.\n", m);
diff --git a/libs/vkd3d-shader/sm4.h b/libs/vkd3d-shader/sm4.h index e8dbeb4b..8dbbeb3d 100644 --- a/libs/vkd3d-shader/sm4.h +++ b/libs/vkd3d-shader/sm4.h @@ -387,6 +387,7 @@ enum vkd3d_sm4_register_modifier { VKD3D_SM4_REGISTER_MODIFIER_NEGATE = 0x20, VKD3D_SM4_REGISTER_MODIFIER_ABS = 0x40, + VKD3D_SM4_REGISTER_MODIFIER_NONUNIFORM = 0x10000, };
enum vkd3d_sm4_output_primitive_type diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 4e67af49..a0c60972 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1842,7 +1842,8 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder, || vkd3d_spirv_capability_is_enabled(builder, SpvCapabilitySampledImageArrayDynamicIndexing) || vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityStorageBufferArrayDynamicIndexing) || vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT) - || vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityStorageImageArrayDynamicIndexing)) + || vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityStorageImageArrayDynamicIndexing) + || vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityShaderNonUniformEXT)) vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_descriptor_indexing");
if (builder->ext_instr_set_glsl_450) @@ -2675,6 +2676,15 @@ static void vkd3d_dxbc_compiler_emit_descriptor_binding_for_reg(struct vkd3d_dxb vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, variable_id, &binding); }
+static void vkd3d_dxbc_compiler_decorate_nonuniform(struct vkd3d_dxbc_compiler *compiler, + uint32_t expression_id) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + + vkd3d_spirv_enable_capability(builder, SpvCapabilityShaderNonUniformEXT); + vkd3d_spirv_build_op_decorate(builder, expression_id, SpvDecorationNonUniformEXT, NULL, 0); +} + static const struct vkd3d_symbol *vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_symbol *symbol) { @@ -3242,6 +3252,9 @@ static uint32_t vkd3d_dxbc_compiler_get_descriptor_index(struct vkd3d_dxbc_compi
index.offset -= binding_base_idx; index_id = vkd3d_dxbc_compiler_emit_register_addressing(compiler, &index); + /* AMD drivers rely on the index being marked as nonuniform */ + if (reg->modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, index_id);
return index_id; } @@ -3319,6 +3332,8 @@ static void vkd3d_dxbc_compiler_emit_dereference_register(struct vkd3d_dxbc_comp ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, register_info->storage_class, type_id); register_info->id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, register_info->id, indexes, index_count); + if (reg->modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, register_info->id); } }
@@ -7992,8 +8007,16 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil return; }
- image->image_id = load ? vkd3d_spirv_build_op_load(builder, - image->image_type_id, image->id, SpvMemoryAccessMaskNone) : 0; + if (load) + { + image->image_id = vkd3d_spirv_build_op_load(builder, image->image_type_id, image->id, SpvMemoryAccessMaskNone); + if (resource_reg->modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, image->image_id); + } + else + { + image->image_id = 0; + }
image->image_type_id = vkd3d_dxbc_compiler_get_image_type_id(compiler, resource_reg, &symbol->info.resource.range, image->resource_type_info, @@ -8022,9 +8045,14 @@ static void vkd3d_dxbc_compiler_prepare_image(struct vkd3d_dxbc_compiler *compil
sampler_id = vkd3d_spirv_build_op_load(builder, vkd3d_spirv_get_op_type_sampler(builder), sampler_var_id, SpvMemoryAccessMaskNone); + if (sampler_reg->modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, sampler_id); + sampled_image_type_id = vkd3d_spirv_get_op_type_sampled_image(builder, image->image_type_id); image->sampled_image_id = vkd3d_spirv_build_op_sampled_image(builder, sampled_image_type_id, image->image_id, sampler_id); + if (resource_reg->modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, image->sampled_image_id); } else { @@ -8375,6 +8403,8 @@ static void vkd3d_dxbc_compiler_emit_ld_raw_structured_srv_uav(struct vkd3d_dxbc indices[1] = coordinate_id;
ptr_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, resource_symbol->id, indices, 2); + if (resource->reg.modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, ptr_id); constituents[j++] = vkd3d_spirv_build_op_load(builder, texel_type_id, ptr_id, SpvMemoryAccessMaskNone); } } @@ -8517,6 +8547,8 @@ static void vkd3d_dxbc_compiler_emit_store_uav_raw_structured(struct vkd3d_dxbc_ indices[1] = coordinate_id;
ptr_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id, resource_symbol->id, indices, 2); + if (dst->reg.modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, ptr_id); vkd3d_spirv_build_op_store(builder, ptr_id, data_id, SpvMemoryAccessMaskNone); } } @@ -8894,6 +8926,8 @@ static void vkd3d_dxbc_compiler_emit_atomic_instruction(struct vkd3d_dxbc_compil pointer_id = vkd3d_spirv_build_op_image_texel_pointer(builder, ptr_type_id, image.id, coordinate_id, sample_id); } + if (resource->reg.modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, pointer_id); }
val_id = vkd3d_dxbc_compiler_emit_load_src_with_type(compiler, &src[1], VKD3DSP_WRITEMASK_0, component_type); @@ -8942,6 +8976,8 @@ static void vkd3d_dxbc_compiler_emit_bufinfo(struct vkd3d_dxbc_compiler *compile
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); val_id = vkd3d_spirv_build_op_image_query_size(builder, type_id, image.image_id); + if (src->reg.modifier == VKD3DSPRM_NONUNIFORM) + vkd3d_dxbc_compiler_decorate_nonuniform(compiler, image.id); write_mask = VKD3DSP_WRITEMASK_0; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 9948045e..a70cab59 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -455,6 +455,12 @@ enum vkd3d_immconst_type VKD3D_IMMCONST_VEC4, };
+enum vkd3d_shader_register_modifier +{ + VKD3DSPRM_NONE = 0, + VKD3DSPRM_NONUNIFORM = 1, +}; + enum vkd3d_shader_src_modifier { VKD3DSPSM_NONE = 0, @@ -612,6 +618,7 @@ struct vkd3d_shader_register_index struct vkd3d_shader_register { enum vkd3d_shader_register_type type; + enum vkd3d_shader_register_modifier modifier; enum vkd3d_data_type data_type; struct vkd3d_shader_register_index idx[3]; enum vkd3d_immconst_type immconst_type; diff --git a/tests/d3d12.c b/tests/d3d12.c index bd3ef624..ecda1272 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -34960,7 +34960,7 @@ static void test_unbounded_resource_arrays(void) D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); get_buffer_readback_with_command_list(output_buffers[i], DXGI_FORMAT_R32_UINT, &rb, queue, command_list); /* Buffers at index >= 64 are aliased. */ - todo_if(i != 10 && i != 74) + todo_if(i != 74) check_readback_data_uint(&rb, NULL, (i < 64 ? 63 - i : 127 - i) ^ 0x35, 0); release_resource_readback(&rb); reset_command_list(command_list, context.allocator); @@ -35107,7 +35107,6 @@ static void test_unbounded_samplers(void) { unsigned int value = get_readback_uint(&rb, i, 0, 0); unsigned int expected = (i & 1) ? 100 : 10; - todo_if(i & 1) ok(value == expected, "Got %u, expected %u at %u.\n", value, expected, i); } release_resource_readback(&rb);
On Fri, 13 Aug 2021 at 16:56, Conor McCarthy cmccarthy@codeweavers.com wrote:
tests/d3d12.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+)
I think it makes sense to split this into two patches, one for each test, as a matter of principle.
- static const DWORD cs_code[] =
- {
/* Compiled with /res_may_alias (but it has no effect on the output from fxc 10.1). */
+#if 0
struct cb
{
uint value;
};
ConstantBuffer<cb> c1[] : register(b2, space1);
Buffer<uint> t1[] : register(t2, space1);
RWBuffer<uint> u1[] : register(u1, space1);
RWBuffer<uint> u2[] : register(u2, space2);
RWBuffer<uint> u3[] : register(u1, space3);
[numthreads(64, 1, 1)]
void main(uint id : SV_DispatchThreadID)
{
uint i = c1[NonUniformResourceIndex(id)].value;
if (id < 64) // Workaround for an fxc bug.
{
So what is the bug? :) Incidentally, I don't think C99 comments are any better in HLSL either.