mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
graphics: share indirect draw handling and honor indexed sources
This commit is contained in:
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user