graphics: write the subdraw index of multi-draw indirect packets

Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
This commit is contained in:
nmzikandAli Almohaya committed 2026-10-26 05:32:02 +01:00
1 parent 72d7da7266
commit b4209dde1b
4 files changed
+19 -7

No files matched your search

@@ -27,6 +27,7 @@ struct IndirectDrawRegisters {
uint32_t vertex_offset; uint32_t vertex_offset;
uint32_t instance_offset; uint32_t instance_offset;
uint32_t index_offset; uint32_t index_offset;
uint32_t draw_index;
}; };
class Pm4Execution { class Pm4Execution {
@@ -1582,7 +1582,7 @@ KYTY_CP_OP_PARSER(CpOpDrawIndirect) {
// The native indexed packet enables the high-half first-index destination in word 3. // The native indexed packet enables the high-half first-index destination in word 3.
const IndirectDrawRegisters registers { const IndirectDrawRegisters registers {
buffer[1] & 0xffffu, buffer[2] & 0xffffu, buffer[1] & 0xffffu, buffer[2] & 0xffffu,
indexed && (buffer[2] & (1u << 28u)) != 0 ? buffer[1] >> 16u : Pm4::SH_NOP}; indexed && (buffer[2] & (1u << 28u)) != 0 ? buffer[1] >> 16u : Pm4::SH_NOP, Pm4::SH_NOP};
cp.DrawIndirect(data_offset, registers, draw_initiator, indexed); cp.DrawIndirect(data_offset, registers, draw_initiator, indexed);
@@ -1602,10 +1602,12 @@ KYTY_CP_OP_PARSER(CpOpDrawIndirectMulti) {
const auto stride_in_bytes = buffer[7]; const auto stride_in_bytes = buffer[7];
const auto draw_initiator = buffer[8]; const auto draw_initiator = buffer[8];
const bool indexed = (cmd_id == 0xc0083800); const bool indexed = (cmd_id == 0xc0083800);
// Multi-draw moves the first-index enable to word 4; the destinations stay in 2/3. // Multi-draw moves the first-index enable to word 4; the destinations stay in 2/3. Word 4
// bit 31 enables the subdraw index, written to the register in its low half.
const IndirectDrawRegisters registers { const IndirectDrawRegisters registers {
buffer[1] & 0xffffu, buffer[2] & 0xffffu, buffer[1] & 0xffffu, buffer[2] & 0xffffu,
indexed && (buffer[3] & (1u << 28u)) != 0 ? buffer[1] >> 16u : Pm4::SH_NOP}; indexed && (buffer[3] & (1u << 28u)) != 0 ? buffer[1] >> 16u : Pm4::SH_NOP,
(buffer[3] >> 31u) != 0 ? buffer[3] & 0xffffu : Pm4::SH_NOP};
if (count_indirect == 0) { if (count_indirect == 0) {
count_addr = nullptr; count_addr = nullptr;
+6 -4
View File
@@ -789,7 +789,7 @@ void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_cou
static void PatchIndirectDrawOffsets(CommandProcessor& cp, IndirectDrawRegisters registers, static void PatchIndirectDrawOffsets(CommandProcessor& cp, IndirectDrawRegisters registers,
uint32_t vertex_offset, uint32_t instance_offset, uint32_t vertex_offset, uint32_t instance_offset,
uint32_t first_index) { uint32_t first_index, uint32_t draw_index) {
const auto write = [&](uint32_t location, uint32_t value) { const auto write = [&](uint32_t location, uint32_t value) {
if (location == Pm4::SH_NOP) { if (location == Pm4::SH_NOP) {
return; return;
@@ -801,6 +801,7 @@ static void PatchIndirectDrawOffsets(CommandProcessor& cp, IndirectDrawRegisters
write(registers.vertex_offset, vertex_offset); write(registers.vertex_offset, vertex_offset);
write(registers.instance_offset, instance_offset); write(registers.instance_offset, instance_offset);
write(registers.index_offset, first_index); write(registers.index_offset, first_index);
write(registers.draw_index, draw_index);
} }
void CommandProcessor::DrawIndirect(uint32_t data_offset, IndirectDrawRegisters registers, void CommandProcessor::DrawIndirect(uint32_t data_offset, IndirectDrawRegisters registers,
@@ -839,7 +840,8 @@ void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_coun
// while they are zero. // while they are zero.
const DrawIndirectArgs records {args_addr, draw_count, stride_in_bytes}; const DrawIndirectArgs records {args_addr, draw_count, stride_in_bytes};
if (registers.vertex_offset == Pm4::SH_NOP && registers.instance_offset == Pm4::SH_NOP && if (registers.vertex_offset == Pm4::SH_NOP && registers.instance_offset == Pm4::SH_NOP &&
registers.index_offset == Pm4::SH_NOP && (!indexed || m_index_buffer_size != 0) && registers.index_offset == Pm4::SH_NOP && registers.draw_index == Pm4::SH_NOP &&
(!indexed || m_index_buffer_size != 0) &&
(indexed ? executor.DrawIndex(m_submit_id, CurrentBuffer(), (indexed ? executor.DrawIndex(m_submit_id, CurrentBuffer(),
{.index_count = m_index_buffer_size, {.index_count = m_index_buffer_size,
.index_addr = IndexAddress(0), .index_addr = IndexAddress(0),
@@ -854,7 +856,7 @@ void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_coun
const auto addr = args_addr + static_cast<uint64_t>(i) * stride_in_bytes; const auto addr = args_addr + static_cast<uint64_t>(i) * stride_in_bytes;
if (!indexed) { if (!indexed) {
const auto& args = *reinterpret_cast<const vk::DrawIndirectCommand*>(addr); const auto& args = *reinterpret_cast<const vk::DrawIndirectCommand*>(addr);
PatchIndirectDrawOffsets(*this, registers, args.firstVertex, args.firstInstance, 0); PatchIndirectDrawOffsets(*this, registers, args.firstVertex, args.firstInstance, 0, i);
executor.DrawAuto(m_submit_id, CurrentBuffer(), executor.DrawAuto(m_submit_id, CurrentBuffer(),
{.vertex_count = args.vertexCount, {.vertex_count = args.vertexCount,
.instance_count = args.instanceCount, .instance_count = args.instanceCount,
@@ -866,7 +868,7 @@ void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_coun
const auto& args = *reinterpret_cast<const vk::DrawIndexedIndirectCommand*>(addr); const auto& args = *reinterpret_cast<const vk::DrawIndexedIndirectCommand*>(addr);
PatchIndirectDrawOffsets(*this, registers, static_cast<uint32_t>(args.vertexOffset), PatchIndirectDrawOffsets(*this, registers, static_cast<uint32_t>(args.vertexOffset),
args.firstInstance, args.firstIndex); args.firstInstance, args.firstIndex, i);
executor.DrawIndex(m_submit_id, CurrentBuffer(), executor.DrawIndex(m_submit_id, CurrentBuffer(),
{.index_count = std::min(args.indexCount, max_indices), {.index_count = std::min(args.indexCount, max_indices),
.index_addr = IndexAddress(args.firstIndex), .index_addr = IndexAddress(args.firstIndex),
+7
View File
@@ -49964,6 +49964,13 @@ void CheckPm4DrawIndirectMultiPacket(RenderContext &renderer) {
KYTY_PM4(10, Pm4::IT_DRAW_INDIRECT_MULTI, 0), 0, KYTY_PM4(10, Pm4::IT_DRAW_INDIRECT_MULTI, 0), 0,
auto_packet[2], auto_packet[3], Pm4::SH_NOP, 2, 0, 0, 16, 2}; auto_packet[2], auto_packet[3], Pm4::SH_NOP, 2, 0, 0, 16, 2};
check_offsets(auto_multi_packet, hs, {53, 15}, "non-indexed multi-draw offsets"); check_offsets(auto_multi_packet, hs, {53, 15}, "non-indexed multi-draw offsets");
// Word 4 bit 31 has the CP write each subdraw's index, even with no offsets to patch.
shaders.SetHsUserSgpr(11, 77);
auto_multi_packet[2] = auto_multi_packet[3] = Pm4::SH_NOP;
auto_multi_packet[4] = (1u << 31u) | (Pm4::SPI_SHADER_USER_DATA_HS_0 + 11);
Require("Pm4DrawIndirectMulti", "multi-draw index",
execute(auto_multi_packet.data(), auto_multi_packet.size()) && hs[11] == 1,
"multi-draw did not write the last subdraw index");
arguments = {0, 1, 99, 101}; arguments = {0, 1, 99, 101};
auto_packet[2] = Pm4::SH_NOP; auto_packet[2] = Pm4::SH_NOP;
check_offsets(auto_packet, hs, {53, 101}, "independent destinations"); check_offsets(auto_packet, hs, {53, 101}, "independent destinations");