From e018311b3559896cc6176a50efcd9b9a06020e84 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 7 Apr 2022 06:49:00 -0700 Subject: [PATCH] dzn: Add KHR_draw_indirect_count support Unfortunately it's not as simple as passing the indirect draw count buffer to ExecuteIndirect. The compute job that populate the execute buffer also needs to know the number of entries that need to be patched. Instead of transitioning the indirect count buffer from GENERIC_READ to INDIRECT_ARGUMENT we just keep at as a read-only resource and copy the draw_count value to the exec buffer in the compute job. Acked-by: Jesse Natalie Part-of: --- src/microsoft/ci/warp-fails.txt | 8 ++ src/microsoft/vulkan/dzn_cmd_buffer.c | 131 ++++++++++++++++++++------ src/microsoft/vulkan/dzn_device.c | 1 + src/microsoft/vulkan/dzn_meta.c | 24 ++++- src/microsoft/vulkan/dzn_nir.c | 43 ++++++++- src/microsoft/vulkan/dzn_nir.h | 4 + 6 files changed, 177 insertions(+), 34 deletions(-) diff --git a/src/microsoft/ci/warp-fails.txt b/src/microsoft/ci/warp-fails.txt index 6922d1f7fc8..2517cd58a79 100644 --- a/src/microsoft/ci/warp-fails.txt +++ b/src/microsoft/ci/warp-fails.txt @@ -874,6 +874,14 @@ dEQP-VK.api.copy_and_blit.dedicated_allocation.blit_image.all_formats.depth_sten dEQP-VK.api.copy_and_blit.dedicated_allocation.blit_image.all_formats.depth_stencil.2d.d32_sfloat_s8_uint_d32_sfloat_s8_uint_separate_layouts.general_optimal_nearest,Fail dEQP-VK.api.copy_and_blit.dedicated_allocation.blit_image.all_formats.depth_stencil.2d.d32_sfloat_s8_uint_d32_sfloat_s8_uint_separate_layouts.optimal_general_nearest,Fail dEQP-VK.api.copy_and_blit.dedicated_allocation.blit_image.all_formats.depth_stencil.2d.d32_sfloat_s8_uint_d32_sfloat_s8_uint_separate_layouts.optimal_optimal_nearest,Fail +dEQP-VK.draw.dynamic_rendering.basic_draw.draw_indexed_indirect.triangle_fan.45_multi_command,Fail +dEQP-VK.draw.dynamic_rendering.basic_draw.draw_indirect.triangle_fan.45_multi_command,Fail +dEQP-VK.draw.renderpass.basic_draw.draw_indexed_indirect.triangle_fan.17_multi_command,Fail +dEQP-VK.draw.renderpass.basic_draw.draw_indexed_indirect.triangle_fan.3_multi_command,Fail +dEQP-VK.draw.renderpass.basic_draw.draw_indexed_indirect.triangle_fan.45_multi_command,Fail +dEQP-VK.draw.renderpass.basic_draw.draw_indirect.triangle_fan.17_multi_command,Fail +dEQP-VK.draw.renderpass.basic_draw.draw_indirect.triangle_fan.3_multi_command,Fail +dEQP-VK.draw.renderpass.basic_draw.draw_indirect.triangle_fan.45_multi_command,Fail dEQP-VK.draw.renderpass.multiple_interpolation.separate.no_sample_decoration.4_samples,Fail dEQP-VK.draw.renderpass.multiple_interpolation.separate.with_sample_decoration.4_samples,Fail dEQP-VK.draw.renderpass.multiple_interpolation.structured.no_sample_decoration.4_samples,Fail diff --git a/src/microsoft/vulkan/dzn_cmd_buffer.c b/src/microsoft/vulkan/dzn_cmd_buffer.c index 9bd9bb37f40..902b0546349 100644 --- a/src/microsoft/vulkan/dzn_cmd_buffer.c +++ b/src/microsoft/vulkan/dzn_cmd_buffer.c @@ -2547,7 +2547,9 @@ static void dzn_cmd_buffer_indirect_draw(struct dzn_cmd_buffer *cmdbuf, struct dzn_buffer *draw_buf, size_t draw_buf_offset, - uint32_t draw_count, + struct dzn_buffer *count_buf, + size_t count_buf_offset, + uint32_t max_draw_count, uint32_t draw_buf_stride, bool indexed) { @@ -2574,9 +2576,19 @@ dzn_cmd_buffer_indirect_draw(struct dzn_cmd_buffer *cmdbuf, sizeof(struct dzn_indirect_draw_exec_params); uint32_t triangle_fan_exec_buf_stride = sizeof(struct dzn_indirect_triangle_fan_rewrite_index_exec_params); + uint32_t exec_buf_size = max_draw_count * exec_buf_stride; + uint32_t exec_buf_draw_offset = 0; + + // We reserve the first slot for the draw_count value when indirect count is + // involved. + if (count_buf != NULL) { + exec_buf_size += exec_buf_stride; + exec_buf_draw_offset = exec_buf_stride; + } + ID3D12Resource *exec_buf; VkResult result = - dzn_cmd_buffer_alloc_internal_buf(cmdbuf, draw_count * exec_buf_stride, + dzn_cmd_buffer_alloc_internal_buf(cmdbuf, exec_buf_size, D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, &exec_buf); @@ -2591,7 +2603,7 @@ dzn_cmd_buffer_indirect_draw(struct dzn_cmd_buffer *cmdbuf, if (triangle_fan_index_buf_stride) { result = dzn_cmd_buffer_alloc_internal_buf(cmdbuf, - draw_count * triangle_fan_index_buf_stride, + max_draw_count * triangle_fan_index_buf_stride, D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, &triangle_fan_index_buf); @@ -2600,7 +2612,7 @@ dzn_cmd_buffer_indirect_draw(struct dzn_cmd_buffer *cmdbuf, result = dzn_cmd_buffer_alloc_internal_buf(cmdbuf, - draw_count * triangle_fan_exec_buf_stride, + max_draw_count * triangle_fan_exec_buf_stride, D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, &triangle_fan_exec_buf); @@ -2622,29 +2634,50 @@ dzn_cmd_buffer_indirect_draw(struct dzn_cmd_buffer *cmdbuf, enum dzn_indirect_draw_type draw_type; - if (indexed && triangle_fan_index_buf_stride > 0) - draw_type = DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN; - else if (!indexed && triangle_fan_index_buf_stride > 0) - draw_type = DZN_INDIRECT_DRAW_TRIANGLE_FAN; - else if (indexed) - draw_type = DZN_INDIRECT_INDEXED_DRAW; - else - draw_type = DZN_INDIRECT_DRAW; + if (indexed && triangle_fan_index_buf_stride > 0) { + draw_type = count_buf ? + DZN_INDIRECT_INDEXED_DRAW_COUNT_TRIANGLE_FAN : + DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN; + } else if (!indexed && triangle_fan_index_buf_stride > 0) { + draw_type = count_buf ? + DZN_INDIRECT_DRAW_COUNT_TRIANGLE_FAN : + DZN_INDIRECT_DRAW_TRIANGLE_FAN; + } else if (indexed) { + draw_type = count_buf ? + DZN_INDIRECT_INDEXED_DRAW_COUNT : + DZN_INDIRECT_INDEXED_DRAW; + } else { + draw_type = count_buf ? DZN_INDIRECT_DRAW_COUNT : DZN_INDIRECT_DRAW; + } struct dzn_meta_indirect_draw *indirect_draw = &device->indirect_draws[draw_type]; const struct dzn_pipeline *compute_pipeline = cmdbuf->state.bindpoint[VK_PIPELINE_BIND_POINT_COMPUTE].pipeline; + uint32_t root_param_idx = 0; ID3D12GraphicsCommandList1_SetComputeRootSignature(cmdbuf->cmdlist, indirect_draw->root_sig); ID3D12GraphicsCommandList1_SetPipelineState(cmdbuf->cmdlist, indirect_draw->pipeline_state); - ID3D12GraphicsCommandList1_SetComputeRoot32BitConstants(cmdbuf->cmdlist, 0, params_size / 4, ¶ms, 0); - ID3D12GraphicsCommandList1_SetComputeRootShaderResourceView(cmdbuf->cmdlist, 1, draw_buf_gpu); - ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(cmdbuf->cmdlist, 2, ID3D12Resource_GetGPUVirtualAddress(exec_buf)); - if (triangle_fan_exec_buf) - ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(cmdbuf->cmdlist, 3, ID3D12Resource_GetGPUVirtualAddress(triangle_fan_exec_buf)); + ID3D12GraphicsCommandList1_SetComputeRoot32BitConstants(cmdbuf->cmdlist, root_param_idx++, + params_size / 4, (const void *)¶ms, 0); + ID3D12GraphicsCommandList1_SetComputeRootShaderResourceView(cmdbuf->cmdlist, root_param_idx++, + draw_buf_gpu); + ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(cmdbuf->cmdlist, root_param_idx++, + ID3D12Resource_GetGPUVirtualAddress(exec_buf)); + if (count_buf) { + ID3D12GraphicsCommandList1_SetComputeRootShaderResourceView(cmdbuf->cmdlist, + root_param_idx++, + ID3D12Resource_GetGPUVirtualAddress(count_buf->res) + + count_buf_offset); + } - ID3D12GraphicsCommandList1_Dispatch(cmdbuf->cmdlist, draw_count, 1, 1); + if (triangle_fan_exec_buf) { + ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(cmdbuf->cmdlist, + root_param_idx++, + ID3D12Resource_GetGPUVirtualAddress(triangle_fan_exec_buf)); + } + + ID3D12GraphicsCommandList1_Dispatch(cmdbuf->cmdlist, max_draw_count, 1, 1); D3D12_RESOURCE_BARRIER post_barriers[] = { { @@ -2697,16 +2730,22 @@ dzn_cmd_buffer_indirect_draw(struct dzn_cmd_buffer *cmdbuf, ID3D12GraphicsCommandList1_SetComputeRootSignature(cmdbuf->cmdlist, rewrite_index->root_sig); ID3D12GraphicsCommandList1_SetPipelineState(cmdbuf->cmdlist, rewrite_index->pipeline_state); - ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(cmdbuf->cmdlist, 0, ID3D12Resource_GetGPUVirtualAddress(triangle_fan_index_buf)); - ID3D12GraphicsCommandList1_SetComputeRoot32BitConstants(cmdbuf->cmdlist, 1, sizeof(rewrite_index_params) / 4, + root_param_idx = 0; + ID3D12GraphicsCommandList1_SetComputeRootUnorderedAccessView(cmdbuf->cmdlist, root_param_idx++, + ID3D12Resource_GetGPUVirtualAddress(triangle_fan_index_buf)); + ID3D12GraphicsCommandList1_SetComputeRoot32BitConstants(cmdbuf->cmdlist, root_param_idx++, + sizeof(rewrite_index_params) / 4, (const void *)&rewrite_index_params, 0); - if (indexed) - ID3D12GraphicsCommandList1_SetComputeRootShaderResourceView(cmdbuf->cmdlist, 2, cmdbuf->state.ib.view.BufferLocation); + if (indexed) { + ID3D12GraphicsCommandList1_SetComputeRootShaderResourceView(cmdbuf->cmdlist, + root_param_idx++, + cmdbuf->state.ib.view.BufferLocation); + } ID3D12GraphicsCommandList1_ExecuteIndirect(cmdbuf->cmdlist, rewrite_index->cmd_sig, - draw_count, triangle_fan_exec_buf, - 0, NULL, 0); + max_draw_count, triangle_fan_exec_buf, 0, + count_buf ? exec_buf : NULL, 0); D3D12_RESOURCE_BARRIER index_buf_barriers[] = { { @@ -2771,7 +2810,9 @@ dzn_cmd_buffer_indirect_draw(struct dzn_cmd_buffer *cmdbuf, } ID3D12GraphicsCommandList1_ExecuteIndirect(cmdbuf->cmdlist, cmdsig, - draw_count, exec_buf, 0, NULL, 0); + max_draw_count, + exec_buf, exec_buf_draw_offset, + count_buf ? exec_buf : NULL, 0); } static void @@ -3729,7 +3770,7 @@ dzn_CmdDrawIndirect(VkCommandBuffer commandBuffer, VK_FROM_HANDLE(dzn_cmd_buffer, cmdbuf, commandBuffer); VK_FROM_HANDLE(dzn_buffer, buf, buffer); - dzn_cmd_buffer_indirect_draw(cmdbuf, buf, offset, drawCount, stride, false); + dzn_cmd_buffer_indirect_draw(cmdbuf, buf, offset, NULL, 0, drawCount, stride, false); } VKAPI_ATTR void VKAPI_CALL @@ -3742,7 +3783,43 @@ dzn_CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VK_FROM_HANDLE(dzn_cmd_buffer, cmdbuf, commandBuffer); VK_FROM_HANDLE(dzn_buffer, buf, buffer); - dzn_cmd_buffer_indirect_draw(cmdbuf, buf, offset, drawCount, stride, true); + dzn_cmd_buffer_indirect_draw(cmdbuf, buf, offset, NULL, 0, drawCount, stride, true); +} + +VKAPI_ATTR void VKAPI_CALL +dzn_CmdDrawIndirectCount(VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride) +{ + VK_FROM_HANDLE(dzn_cmd_buffer, cmdbuf, commandBuffer); + VK_FROM_HANDLE(dzn_buffer, buf, buffer); + VK_FROM_HANDLE(dzn_buffer, count_buf, countBuffer); + + dzn_cmd_buffer_indirect_draw(cmdbuf, buf, offset, + count_buf, countBufferOffset, + maxDrawCount, stride, false); +} + +VKAPI_ATTR void VKAPI_CALL +dzn_CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, + VkBuffer buffer, + VkDeviceSize offset, + VkBuffer countBuffer, + VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, + uint32_t stride) +{ + VK_FROM_HANDLE(dzn_cmd_buffer, cmdbuf, commandBuffer); + VK_FROM_HANDLE(dzn_buffer, buf, buffer); + VK_FROM_HANDLE(dzn_buffer, count_buf, countBuffer); + + dzn_cmd_buffer_indirect_draw(cmdbuf, buf, offset, + count_buf, countBufferOffset, + maxDrawCount, stride, true); } VKAPI_ATTR void VKAPI_CALL diff --git a/src/microsoft/vulkan/dzn_device.c b/src/microsoft/vulkan/dzn_device.c index 69dd7d221ff..989919aab3e 100644 --- a/src/microsoft/vulkan/dzn_device.c +++ b/src/microsoft/vulkan/dzn_device.c @@ -78,6 +78,7 @@ dzn_physical_device_get_extensions(struct dzn_physical_device *pdev) { pdev->vk.supported_extensions = (struct vk_device_extension_table) { .KHR_descriptor_update_template = true, + .KHR_draw_indirect_count = true, .KHR_dynamic_rendering = true, .KHR_shader_draw_parameters = true, #ifdef DZN_USE_WSI_PLATFORM diff --git a/src/microsoft/vulkan/dzn_meta.c b/src/microsoft/vulkan/dzn_meta.c index 9ecc4fbefa0..d0e88dbab9b 100644 --- a/src/microsoft/vulkan/dzn_meta.c +++ b/src/microsoft/vulkan/dzn_meta.c @@ -87,7 +87,7 @@ dzn_meta_compile_shader(struct dzn_device *device, nir_shader *nir, slot->BytecodeLength = size; } -#define DZN_META_INDIRECT_DRAW_MAX_PARAM_COUNT 4 +#define DZN_META_INDIRECT_DRAW_MAX_PARAM_COUNT 5 static void dzn_meta_indirect_draw_finish(struct dzn_device *device, enum dzn_indirect_draw_type type) @@ -114,7 +114,13 @@ dzn_meta_indirect_draw_init(struct dzn_device *device, nir_shader *nir = dzn_nir_indirect_draw_shader(type); bool triangle_fan = type == DZN_INDIRECT_DRAW_TRIANGLE_FAN || - type == DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN; + type == DZN_INDIRECT_DRAW_COUNT_TRIANGLE_FAN || + type == DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN || + type == DZN_INDIRECT_INDEXED_DRAW_COUNT_TRIANGLE_FAN; + bool indirect_count = type == DZN_INDIRECT_DRAW_COUNT || + type == DZN_INDIRECT_INDEXED_DRAW_COUNT || + type == DZN_INDIRECT_DRAW_COUNT_TRIANGLE_FAN || + type == DZN_INDIRECT_INDEXED_DRAW_COUNT_TRIANGLE_FAN; uint32_t shader_params_size = triangle_fan ? sizeof(struct dzn_indirect_draw_triangle_fan_rewrite_params) : @@ -153,12 +159,24 @@ dzn_meta_indirect_draw_init(struct dzn_device *device, .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL, }; + if (indirect_count) { + root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) { + .ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV, + .Descriptor = { + .ShaderRegister = 3, + .RegisterSpace = 0, + .Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE, + }, + .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL, + }; + } + if (triangle_fan) { root_params[root_param_count++] = (D3D12_ROOT_PARAMETER1) { .ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV, .Descriptor = { - .ShaderRegister = 3, + .ShaderRegister = 4, .RegisterSpace = 0, .Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE, }, diff --git a/src/microsoft/vulkan/dzn_nir.c b/src/microsoft/vulkan/dzn_nir.c index 146322756a1..fcae26f45b7 100644 --- a/src/microsoft/vulkan/dzn_nir.c +++ b/src/microsoft/vulkan/dzn_nir.c @@ -86,17 +86,29 @@ dzn_nir_indirect_draw_shader(enum dzn_indirect_draw_type type) { const char *type_str[] = { "draw", + "draw_count", "indexed_draw", + "indexed_draw_count", "draw_triangle_fan", + "draw_count_triangle_fan", "indexed_draw_triangle_fan", + "indexed_draw_count_triangle_fan", }; assert(type < ARRAY_SIZE(type_str)); bool indexed = type == DZN_INDIRECT_INDEXED_DRAW || - type == DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN; + type == DZN_INDIRECT_INDEXED_DRAW_COUNT || + type == DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN || + type == DZN_INDIRECT_INDEXED_DRAW_COUNT_TRIANGLE_FAN; bool triangle_fan = type == DZN_INDIRECT_DRAW_TRIANGLE_FAN || - type == DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN; + type == DZN_INDIRECT_DRAW_COUNT_TRIANGLE_FAN || + type == DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN || + type == DZN_INDIRECT_INDEXED_DRAW_COUNT_TRIANGLE_FAN; + bool indirect_count = type == DZN_INDIRECT_DRAW_COUNT || + type == DZN_INDIRECT_INDEXED_DRAW_COUNT || + type == DZN_INDIRECT_DRAW_COUNT_TRIANGLE_FAN || + type == DZN_INDIRECT_INDEXED_DRAW_COUNT_TRIANGLE_FAN; nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, dxil_get_nir_compiler_options(), @@ -136,8 +148,29 @@ dzn_nir_indirect_draw_shader(enum dzn_indirect_draw_type type) nir_ssa_def *index = nir_channel(&b, nir_load_global_invocation_id(&b, 32), 0); + if (indirect_count) { + nir_ssa_def *count_buf_desc = + dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 3, "count_buf", ACCESS_NON_WRITEABLE); + + nir_ssa_def *draw_count = + nir_load_ssbo(&b, 1, 32, count_buf_desc, nir_imm_int(&b, 0), .align_mul = 4); + + nir_push_if(&b, nir_ieq(&b, index, nir_imm_int(&b, 0))); + nir_store_ssbo(&b, draw_count, exec_buf_desc, nir_imm_int(&b, 0), + .write_mask = 0x1, .access = ACCESS_NON_READABLE, + .align_mul = 16); + nir_pop_if(&b, NULL); + + nir_push_if(&b, nir_ult(&b, index, draw_count)); + } + nir_ssa_def *draw_offset = nir_imul(&b, draw_stride, index); - nir_ssa_def *exec_offset = nir_imul(&b, exec_stride, index); + + /* The first entry contains the indirect count */ + nir_ssa_def *exec_offset = + indirect_count ? + nir_imul(&b, exec_stride, nir_iadd_imm(&b, index, 1)) : + nir_imul(&b, exec_stride, index); nir_ssa_def *draw_info1 = nir_load_ssbo(&b, 4, 32, draw_buf_desc, draw_offset, .align_mul = 4); @@ -168,7 +201,7 @@ dzn_nir_indirect_draw_shader(enum dzn_indirect_draw_type type) exec_vals[7] = base_instance; nir_ssa_def *triangle_fan_exec_buf_desc = - dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 3, + dzn_nir_create_bo_desc(&b, nir_var_mem_ssbo, 0, 4, "triangle_fan_exec_buf", ACCESS_NON_READABLE); nir_ssa_def *triangle_fan_index_buf_stride = nir_channel(&b, params, 1); @@ -232,6 +265,8 @@ dzn_nir_indirect_draw_shader(enum dzn_indirect_draw_type type) exec_buf_desc, nir_iadd_imm(&b, exec_offset, 16), .write_mask = 0xf, .access = ACCESS_NON_READABLE, .align_mul = 16); + if (indirect_count) + nir_pop_if(&b, NULL); return b.shader; } diff --git a/src/microsoft/vulkan/dzn_nir.h b/src/microsoft/vulkan/dzn_nir.h index d05f1ba5030..8e095ddb040 100644 --- a/src/microsoft/vulkan/dzn_nir.h +++ b/src/microsoft/vulkan/dzn_nir.h @@ -94,9 +94,13 @@ struct dzn_indirect_triangle_fan_rewrite_index_exec_params { enum dzn_indirect_draw_type { DZN_INDIRECT_DRAW, + DZN_INDIRECT_DRAW_COUNT, DZN_INDIRECT_INDEXED_DRAW, + DZN_INDIRECT_INDEXED_DRAW_COUNT, DZN_INDIRECT_DRAW_TRIANGLE_FAN, + DZN_INDIRECT_DRAW_COUNT_TRIANGLE_FAN, DZN_INDIRECT_INDEXED_DRAW_TRIANGLE_FAN, + DZN_INDIRECT_INDEXED_DRAW_COUNT_TRIANGLE_FAN, DZN_NUM_INDIRECT_DRAW_TYPES, };