v3dv: implement VK_EXT_multi_draw

Implement the Vulkan extension VK_EXT_multi_draw. It was tested with
deqp-vk -n dEQP-VK.draw.*multi_draw*.

Signed-off-by: Maíra Canal <mcanal@igalia.com>
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26138>
This commit is contained in:
Maíra Canal 2023-08-12 12:40:43 -03:00 committed by Marge Bot
parent 794b0496e9
commit 4d95b4861e
7 changed files with 104 additions and 2 deletions

View file

@ -582,7 +582,7 @@ Khronos extensions that are not part of any Vulkan version:
VK_EXT_memory_budget DONE (anv, hasvk, lvp, radv, tu, v3dv, vn)
VK_EXT_memory_priority DONE (lvp, radv)
VK_EXT_mesh_shader DONE (anv/gfx12.5+, lvp, radv)
VK_EXT_multi_draw DONE (anv, hasvk, lvp, radv, tu, vn)
VK_EXT_multi_draw DONE (anv, hasvk, lvp, radv, tu, vn, v3dv)
VK_EXT_multisampled_render_to_single_sampled DONE (lvp)
VK_EXT_nested_command_buffer DONE (lvp)
VK_EXT_non_seamless_cube_map DONE (anv, hasvk, lvp, nvk, radv, tu, vn)

View file

@ -3359,6 +3359,10 @@ ntq_emit_intrinsic(struct v3d_compile *c, nir_intrinsic_instr *instr)
ntq_store_def(c, &instr->def, 0, vir_MOV(c, c->vid));
break;
case nir_intrinsic_load_draw_id:
ntq_store_def(c, &instr->def, 0, vir_uniform(c, QUNIFORM_DRAW_ID, 0));
break;
case nir_intrinsic_load_tlb_color_v3d:
vir_emit_tlb_color_read(c, instr);
break;

View file

@ -345,6 +345,11 @@ enum quniform_contents {
QUNIFORM_INLINE_UBO_1,
QUNIFORM_INLINE_UBO_2,
QUNIFORM_INLINE_UBO_3,
/**
* Current value of DrawIndex for Multidraw
*/
QUNIFORM_DRAW_ID,
};
static inline uint32_t v3d_unit_data_create(uint32_t unit, uint32_t value)

View file

@ -2336,6 +2336,7 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer,
const bool has_new_push_constants = dirty_uniform_state & V3DV_CMD_DIRTY_PUSH_CONSTANTS;
const bool has_new_descriptors = dirty_uniform_state & V3DV_CMD_DIRTY_DESCRIPTOR_SETS;
const bool has_new_view_index = dirty_uniform_state & V3DV_CMD_DIRTY_VIEW_INDEX;
const bool has_new_draw_id = dirty_uniform_state & V3DV_CMD_DIRTY_DRAW_ID;
/* VK_SHADER_STAGE_FRAGMENT_BIT */
const bool has_new_descriptors_fs =
@ -2403,6 +2404,7 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer,
const bool needs_vs_update = has_new_viewport ||
has_new_view_index ||
has_new_draw_id ||
has_new_pipeline ||
has_new_push_constants_vs ||
has_new_descriptors_vs;
@ -2422,6 +2424,7 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer,
}
cmd_buffer->state.dirty &= ~V3DV_CMD_DIRTY_VIEW_INDEX;
cmd_buffer->state.dirty &= ~V3DV_CMD_DIRTY_DRAW_ID;
}
/* This stores command buffer state that we might be about to stomp for
@ -2913,7 +2916,8 @@ v3dv_cmd_buffer_emit_pre_draw(struct v3dv_cmd_buffer *cmd_buffer,
V3DV_CMD_DIRTY_PUSH_CONSTANTS |
V3DV_CMD_DIRTY_DESCRIPTOR_SETS |
V3DV_CMD_DIRTY_VIEWPORT |
V3DV_CMD_DIRTY_VIEW_INDEX);
V3DV_CMD_DIRTY_VIEW_INDEX |
V3DV_CMD_DIRTY_DRAW_ID);
if (dirty_uniform_state)
update_gfx_uniform_state(cmd_buffer, dirty_uniform_state);
@ -3030,6 +3034,35 @@ v3dv_CmdDraw(VkCommandBuffer commandBuffer,
cmd_buffer_draw(cmd_buffer, &info);
}
VKAPI_ATTR void VKAPI_CALL
v3dv_CmdDrawMultiEXT(VkCommandBuffer commandBuffer,
uint32_t drawCount,
const VkMultiDrawInfoEXT *pVertexInfo,
uint32_t instanceCount,
uint32_t firstInstance,
uint32_t stride)
{
if (drawCount == 0 || instanceCount == 0)
return;
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
uint32_t i = 0;
vk_foreach_multi_draw(draw, i, pVertexInfo, drawCount, stride) {
cmd_buffer->state.draw_id = i;
cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DRAW_ID;
struct v3dv_draw_info info = {};
info.vertex_count = draw->vertexCount;
info.instance_count = instanceCount;
info.first_instance = firstInstance;
info.first_vertex = draw->firstVertex;
cmd_buffer_draw(cmd_buffer, &info);
}
}
VKAPI_ATTR void VKAPI_CALL
v3dv_CmdDrawIndexed(VkCommandBuffer commandBuffer,
uint32_t indexCount,
@ -3064,6 +3097,48 @@ v3dv_CmdDrawIndexed(VkCommandBuffer commandBuffer,
}
}
VKAPI_ATTR void VKAPI_CALL
v3dv_CmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer,
uint32_t drawCount,
const VkMultiDrawIndexedInfoEXT *pIndexInfo,
uint32_t instanceCount,
uint32_t firstInstance,
uint32_t stride,
const int32_t *pVertexOffset)
{
if (drawCount == 0 || instanceCount == 0)
return;
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
uint32_t i = 0;
vk_foreach_multi_draw_indexed(draw, i, pIndexInfo, drawCount, stride) {
uint32_t vertex_count = draw->indexCount * instanceCount;
int32_t vertexOffset = pVertexOffset ? *pVertexOffset : draw->vertexOffset;
cmd_buffer->state.draw_id = i;
cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DRAW_ID;
struct v3dv_render_pass *pass = cmd_buffer->state.pass;
if (likely(!pass->multiview_enabled)) {
v3dv_cmd_buffer_emit_pre_draw(cmd_buffer, true, false, vertex_count);
v3dv_X(cmd_buffer->device, cmd_buffer_emit_draw_indexed)
(cmd_buffer, draw->indexCount, instanceCount,
draw->firstIndex, vertexOffset, firstInstance);
continue;
}
uint32_t view_mask = pass->subpasses[cmd_buffer->state.subpass_idx].view_mask;
while (view_mask) {
cmd_buffer_set_view_index(cmd_buffer, u_bit_scan(&view_mask));
v3dv_cmd_buffer_emit_pre_draw(cmd_buffer, true, false, vertex_count);
v3dv_X(cmd_buffer->device, cmd_buffer_emit_draw_indexed)
(cmd_buffer, draw->indexCount, instanceCount,
draw->firstIndex, vertexOffset, firstInstance);
}
}
}
VKAPI_ATTR void VKAPI_CALL
v3dv_CmdDrawIndirect(VkCommandBuffer commandBuffer,
VkBuffer _buffer,

View file

@ -195,6 +195,7 @@ get_device_extensions(const struct v3dv_physical_device *device,
.EXT_index_type_uint8 = true,
.EXT_line_rasterization = true,
.EXT_memory_budget = true,
.EXT_multi_draw = true,
.EXT_physical_device_drm = true,
.EXT_pipeline_creation_cache_control = true,
.EXT_pipeline_creation_feedback = true,
@ -436,6 +437,9 @@ get_features(const struct v3dv_physical_device *physical_device,
/* VK_EXT_pipeline_robustness */
.pipelineRobustness = true,
/* VK_EXT_multi_draw */
.multiDraw = true,
};
}
@ -1736,6 +1740,12 @@ v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT: {
VkPhysicalDeviceMultiDrawPropertiesEXT *properties =
(VkPhysicalDeviceMultiDrawPropertiesEXT *)ext;
properties->maxMultiDrawCount = 2048;
break;
}
default:
v3dv_debug_ignored_stype(ext->sType);
break;

View file

@ -1091,6 +1091,7 @@ enum v3dv_cmd_dirty_bits {
V3DV_CMD_DIRTY_VIEW_INDEX = 1 << 17,
V3DV_CMD_DIRTY_COLOR_WRITE_ENABLE = 1 << 18,
V3DV_CMD_DIRTY_DEPTH_BOUNDS = 1 << 19,
V3DV_CMD_DIRTY_DRAW_ID = 1 << 20,
};
struct v3dv_dynamic_state {
@ -1530,6 +1531,9 @@ struct v3dv_cmd_buffer_state {
/* Current view index for multiview rendering */
uint32_t view_index;
/* Current draw ID for multidraw */
uint32_t draw_id;
/* Used to flag OOM conditions during command buffer recording */
bool oom;

View file

@ -657,6 +657,10 @@ v3dv_write_uniforms_wg_offsets(struct v3dv_cmd_buffer *cmd_buffer,
cl_aligned_u32(&uniforms, pipeline->spill.size_per_thread);
break;
case QUNIFORM_DRAW_ID:
cl_aligned_u32(&uniforms, job->cmd_buffer->state.draw_id);
break;
default:
unreachable("unsupported quniform_contents uniform type\n");
}