graphics: share indirect draw handling and honor indexed sources

This commit is contained in:
nmzik
2026-10-05 23:15:20 +04:00
parent e5dcfdb87b
commit cdb64bfd4f
3 changed files with 78 additions and 57 deletions
+3 -52
View File
@@ -876,64 +876,15 @@ void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_cou
}
void CommandProcessor::DrawIndirect(uint32_t data_offset, uint32_t draw_initiator, bool indexed) {
EXIT_NOT_IMPLEMENTED((draw_initiator & ~0x20u) != 2u);
EXIT_NOT_IMPLEMENTED(m_draw_indirect_args_base_addr == 0);
const auto* args_addr =
reinterpret_cast<const void*>(m_draw_indirect_args_base_addr + data_offset);
if (!indexed) {
DrawIndirectArgs args {};
std::memcpy(&args, args_addr, sizeof(args));
m_num_instances = args.instance_count;
DrawIndexAuto({.vertex_count = args.vertex_count_per_instance,
.instance_count = args.instance_count,
.first_vertex = args.start_vertex_location,
.first_instance = args.start_instance_location,
.offset_source = DrawOffsetSource::IndirectArgs});
return;
}
DrawIndexedIndirectArgs args {};
std::memcpy(&args, args_addr, sizeof(args));
uint64_t index_size = 0;
switch (m_index_type_and_size) {
case 0: index_size = 2; break;
case 1: index_size = 4; break;
case 2: index_size = 1; break;
default: EXIT("unknown index_type_and_size: %u\n", m_index_type_and_size);
}
auto* index_addr = reinterpret_cast<const void*>(
m_index_base_addr + static_cast<uint64_t>(args.start_index_location) * index_size);
const uint32_t index_count =
(m_index_buffer_size != 0 ? std::min(args.index_count_per_instance, m_index_buffer_size)
: args.index_count_per_instance);
if (GraphicsRunDebugDumpEnabled() && index_count != args.index_count_per_instance) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 64) {
LOGF("\t DrawIndexIndirect: clamped index_count from %" PRIu32 " to %" PRIu32
" using INDEX_BUFFER_SIZE\n",
args.index_count_per_instance, index_count);
}
}
m_num_instances = args.instance_count;
DrawIndex({.index_count = index_count,
.index_addr = index_addr,
.instance_count = args.instance_count,
.base_vertex = static_cast<int32_t>(args.base_vertex_location),
.first_instance = args.start_instance_location,
.offset_source = DrawOffsetSource::IndirectArgs});
const auto args_size = indexed ? sizeof(DrawIndexedIndirectArgs) : sizeof(DrawIndirectArgs);
DrawIndirectMulti(data_offset, 1, nullptr, args_size, draw_initiator, indexed);
}
void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_count_or_count,
const volatile uint32_t* count_addr,
uint32_t stride_in_bytes, uint32_t draw_initiator,
bool indexed) {
EXIT_NOT_IMPLEMENTED((draw_initiator & ~0x20u) != 2u);
EXIT_NOT_IMPLEMENTED((draw_initiator & ~0x20u) != (indexed ? 0u : 2u));
EXIT_NOT_IMPLEMENTED(m_draw_indirect_args_base_addr == 0);
uint32_t draw_count = max_count_or_count;
+17 -5
View File
@@ -2529,7 +2529,6 @@ static uint64_t decode_indirect_modifier_patch_offsets(uint64_t modifier, bool i
if (indexed && (low & 0x2u) != 0) {
base_vtx_loc |= static_cast<uint64_t>(sgpr_base + extract_modifier_bits(low, 14u, 5u))
<< 16u;
base_vtx_loc |= 1ull << 59u;
}
return base_vtx_loc | (start_inst_loc << 32u);
@@ -2787,13 +2786,15 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndexIndirect(CommandBuffer* buf, uint32_t dat
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
const auto patch_offsets = decode_indirect_modifier_patch_offsets(modifier, true);
// Single indexed draws store the index-offset enable in word 3, bit 28.
const auto patch_offsets = decode_indirect_modifier_patch_offsets(modifier, true) |
((modifier & 0x2ull) << 59u);
cmd[0] = KYTY_PM4(5, Pm4::IT_DRAW_INDEX_INDIRECT, 0u);
cmd[1] = data_offset_in_bytes;
cmd[2] = static_cast<uint32_t>(patch_offsets);
cmd[3] = static_cast<uint32_t>(patch_offsets >> 32u);
cmd[4] = decode_indirect_draw_initiator(modifier);
cmd[4] = decode_draw_index_initiator(modifier);
return cmd;
}
@@ -2914,19 +2915,30 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndexIndirectMulti(CommandBuffer* buf,
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
const auto low = static_cast<uint32_t>(modifier);
const auto sgpr_base = indirect_modifier_sgpr_base(low);
const auto patch_offsets = decode_indirect_modifier_patch_offsets(modifier, true);
const auto count_vaddr = reinterpret_cast<uint64_t>(count_addr);
uint32_t draw_index_location = 0x280u;
if ((low & 0x8u) != 0) {
draw_index_location = sgpr_base + extract_modifier_bits(low, 24u, 5u);
}
// Multi indexed draws store the index-offset enable in word 4, bit 28.
const auto draw_control = draw_index_location | ((low & 0x10u) << 23u) |
((low & 0x2u) << 27u) | ((count_indirect & 0x1u) << 30u) |
((low & 0x8u) << 28u);
cmd[0] = KYTY_PM4(10, Pm4::IT_DRAW_INDEX_INDIRECT_MULTI, 0u);
cmd[1] = data_offset_in_bytes;
cmd[2] = static_cast<uint32_t>(patch_offsets);
cmd[3] = static_cast<uint32_t>(patch_offsets >> 32u);
cmd[4] = (count_indirect & 1u) << 30u;
cmd[4] = draw_control;
cmd[5] = max_count_or_count;
cmd[6] = static_cast<uint32_t>(count_vaddr) & ~0x3u;
cmd[7] = static_cast<uint32_t>(count_vaddr >> 32u);
cmd[8] = stride_in_bytes;
cmd[9] = decode_indirect_draw_initiator(modifier);
cmd[9] = decode_draw_index_initiator(modifier);
return cmd;
}
+58
View File
@@ -39947,6 +39947,64 @@ void CheckPm4DrawIndirectMultiPacket(RenderContext &renderer) {
packet_mismatch &&
!Gen5::AgcIsInternalDataPacket(0xc0017904u, invalid_payload),
"indirect multi-draw packet differs from the expected stream");
constexpr uint32_t data_offset = 0x5c08;
constexpr uint32_t stride = 32;
std::array<uint32_t, data_offset / 4 + stride / 4 + 5> arguments{};
const std::array<uint32_t, 5> first{0, 1, 3, 0xfffffffeu, 9};
const std::array<uint32_t, 5> second{0, 2, 5, 7, 11};
std::copy(first.begin(), first.end(), arguments.begin() + data_offset / 4);
std::copy(second.begin(), second.end(), arguments.begin() + (data_offset + stride) / 4);
std::array<uint32_t, 8> indices{};
processor.BufferInit();
processor.SetDrawIndirectArgsBaseAddress(reinterpret_cast<uint64_t>(arguments.data()));
processor.SetIndexBaseAddress(reinterpret_cast<uint64_t>(indices.data()));
processor.SetIndexType(0);
std::array<uint32_t, 5> captured{0xc0032500u, data_offset, 0x94, 0x95, 0};
Require("Pm4DrawIndirectMulti", "captured indexed single execution",
execute(captured.data(), captured.size()),
"indexed indirect draw rejected native source-select zero");
// Zero primitive counts still traverse CP argument decoding and renderer entry,
// while avoiding unrelated shader and attachment requirements.
for (const bool indexed : {false, true}) {
for (const bool multi : {false, true}) {
for (const uint64_t draw_modifier : {0ull, 0x100ull, 1ull << 32u, (1ull << 32u) | 0x100ull}) {
packet.fill(0);
dcb.cursor_up = packet.data();
auto *buffer = reinterpret_cast<Gen5::CommandBuffer *>(&dcb);
alignas(4) uint32_t draw_count = 3;
if (multi) {
emitted = indexed ? Gen5::AgcDcbDrawIndexIndirectMulti(buffer, data_offset, 1, 2,
&draw_count, stride, draw_modifier)
: Gen5::AgcDcbDrawIndirectMulti(buffer, data_offset, 1, 2,
&draw_count, stride, draw_modifier);
} else {
emitted = indexed ? Gen5::AgcDcbDrawIndexIndirect(buffer, data_offset, draw_modifier)
: Gen5::AgcDcbDrawIndirect(buffer, data_offset, draw_modifier);
}
const uint32_t begin = multi && !indexed ? 3 : 0;
const uint32_t words = multi ? (indexed ? 10 : 16) : 5;
const uint32_t opcode = multi ? (indexed ? 0xc0083800u : 0xc0082c00u)
: (indexed ? 0xc0032500u : 0xc0032400u);
const uint32_t initiator = (indexed ? 0 : 2) |
(draw_modifier == 0x100 ? 0x20 : 0);
Require("Pm4DrawIndirectMulti", "indexed/auto initiator emission",
emitted == packet.data() && dcb.cursor_up == packet.data() + words &&
packet[begin] == opcode && packet[begin + 1] == data_offset &&
packet[begin + (multi ? 9 : 4)] == initiator,
"indirect opcode, source select, or modifier bits differ from the native packet");
Require("Pm4DrawIndirectMulti", "single/multi argument execution",
execute(packet.data(), words),
"indirect draw failed shared argument decoding or padded/count-limited traversal");
if (multi) {
draw_count = 0;
Require("Pm4DrawIndirectMulti", "zero indirect count execution",
execute(packet.data(), words), "zero indirect draw count did not complete");
}
}
}
}
renderer.GetCommandScheduler().Finish();
std::printf("[host] %-32s ok\n", "Pm4DrawIndirectMulti");
}