mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
graphics: allow absent programmable restart indices
Co-authored-by: Ettore Sartori <85788613+Ekt0re@users.noreply.github.com>
This commit is contained in:
@@ -863,8 +863,8 @@ static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ResolvePrimitiveRestart(const CommandBuffer& buffer, vk::PrimitiveTopology topology,
|
||||
uint32_t index_type_and_size) {
|
||||
static bool ResolvePrimitiveRestart(const CommandBuffer& buffer,
|
||||
const DrawIndexBufferSource& source) {
|
||||
const auto control = buffer.GetUserConfig().GetPrimitiveResetControl();
|
||||
EXIT_NOT_IMPLEMENTED((control & ~0x3u) != 0);
|
||||
if ((control & 0x1u) == 0) {
|
||||
@@ -876,26 +876,30 @@ static bool ResolvePrimitiveRestart(const CommandBuffer& buffer, vk::PrimitiveTo
|
||||
case Prospero::PrimitiveType::kTriStrip: break;
|
||||
default: return false;
|
||||
}
|
||||
if (topology != vk::PrimitiveTopology::eLineStrip &&
|
||||
topology != vk::PrimitiveTopology::eTriangleStrip &&
|
||||
topology != vk::PrimitiveTopology::eTriangleFan) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t index_mask = 0;
|
||||
switch (static_cast<Prospero::IndexType>(index_type_and_size)) {
|
||||
case Prospero::IndexType::kIndex8: index_mask = 0xffu; break;
|
||||
case Prospero::IndexType::kIndex16: index_mask = 0xffffu; break;
|
||||
case Prospero::IndexType::kIndex32: index_mask = 0xffffffffu; break;
|
||||
default: EXIT("unknown index_type_and_size: %u\n", index_type_and_size);
|
||||
}
|
||||
|
||||
const auto reset_index = buffer.GetRegisters().GetPrimitiveResetIndex();
|
||||
const auto element_size = source.guest_element_size;
|
||||
const auto index_mask = UINT32_MAX >> ((4 - element_size) * 8);
|
||||
const auto reset_index = buffer.GetRegisters().GetPrimitiveResetIndex();
|
||||
if ((control & 0x2u) != 0 && (reset_index & ~index_mask) != 0) {
|
||||
return false;
|
||||
}
|
||||
EXIT_NOT_IMPLEMENTED((reset_index & index_mask) != index_mask);
|
||||
return true;
|
||||
const auto restart_index = reset_index & index_mask;
|
||||
if (restart_index == index_mask) {
|
||||
// Use native restart; the 8-bit path widens its marker to 0xffff.
|
||||
return true;
|
||||
}
|
||||
|
||||
// A game can set a custom reset value without using it in the index buffer.
|
||||
// Keep restart off in that case; fail if we actually find the value.
|
||||
// Scan before preparing draw resources: readback can restart the command buffer.
|
||||
EXIT_NOT_IMPLEMENTED(source.address == 0);
|
||||
const auto* indices = reinterpret_cast<const uint8_t*>(source.address);
|
||||
for (uint64_t offset = 0; offset < source.size; offset += element_size) {
|
||||
uint32_t index = 0;
|
||||
std::memcpy(&index, indices + offset, element_size);
|
||||
EXIT_NOT_IMPLEMENTED(index == restart_index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RenderExecutor::PrepareDrawRenderState(CommandBuffer& buffer, const DrawCallInfo& draw,
|
||||
@@ -1269,51 +1273,39 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
||||
return;
|
||||
}
|
||||
|
||||
vk::IndexType index_type = vk::IndexType::eUint16;
|
||||
uint64_t index_size = 0;
|
||||
bool expand_index8_to_u16 = false;
|
||||
const bool primitive_restart =
|
||||
ResolvePrimitiveRestart(buffer, topology, args.index_type_and_size);
|
||||
|
||||
DrawIndexBufferSource index_source {};
|
||||
index_source.address = reinterpret_cast<uint64_t>(args.index_addr);
|
||||
switch (static_cast<Prospero::IndexType>(args.index_type_and_size)) {
|
||||
case Prospero::IndexType::kIndex16:
|
||||
index_type = vk::IndexType::eUint16;
|
||||
index_size = 2 * static_cast<uint64_t>(args.index_count);
|
||||
index_source.type = vk::IndexType::eUint16;
|
||||
index_source.guest_element_size = 2;
|
||||
break;
|
||||
case Prospero::IndexType::kIndex32:
|
||||
index_type = vk::IndexType::eUint32;
|
||||
index_size = 4 * static_cast<uint64_t>(args.index_count);
|
||||
index_source.type = vk::IndexType::eUint32;
|
||||
index_source.guest_element_size = 4;
|
||||
break;
|
||||
// Some games use it - need vulkan extension
|
||||
case Prospero::IndexType::kIndex8:
|
||||
index_type = vk::IndexType::eUint16;
|
||||
index_size = static_cast<uint64_t>(args.index_count);
|
||||
expand_index8_to_u16 = true;
|
||||
index_source.guest_element_size = 1;
|
||||
break;
|
||||
default: EXIT("unknown index_type_and_size: %u\n", args.index_type_and_size);
|
||||
}
|
||||
index_source.size = static_cast<uint64_t>(args.index_count) * index_source.guest_element_size;
|
||||
const bool primitive_restart = ResolvePrimitiveRestart(buffer, index_source);
|
||||
|
||||
const DrawCallInfo draw {"DrawIndex", CommandBufferDebugOp::DrawIndex, args.index_count,
|
||||
args.instance_count, args.first_instance};
|
||||
std::vector<uint16_t> expanded_indices;
|
||||
if (expand_index8_to_u16) {
|
||||
if (index_source.guest_element_size == 1) {
|
||||
EXIT_NOT_IMPLEMENTED(args.index_addr == nullptr);
|
||||
const auto* src = static_cast<const uint8_t*>(args.index_addr);
|
||||
expanded_indices.resize(args.index_count);
|
||||
for (uint32_t i = 0; i < args.index_count; i++) {
|
||||
expanded_indices[i] = primitive_restart && src[i] == 0xffu ? 0xffffu : src[i];
|
||||
}
|
||||
index_source.host_data = expanded_indices.data();
|
||||
index_source.size = expanded_indices.size() * sizeof(uint16_t);
|
||||
}
|
||||
|
||||
DrawIndexBufferSource index_source {};
|
||||
index_source.address = reinterpret_cast<uint64_t>(args.index_addr);
|
||||
index_source.host_data =
|
||||
expanded_indices.empty() ? nullptr : static_cast<const void*>(expanded_indices.data());
|
||||
index_source.size =
|
||||
expanded_indices.empty() ? index_size : expanded_indices.size() * sizeof(uint16_t);
|
||||
index_source.type = index_type;
|
||||
index_source.guest_element_size = static_cast<uint32_t>(index_size / args.index_count);
|
||||
|
||||
const DrawCallInfo draw {"DrawIndex", CommandBufferDebugOp::DrawIndex, args.index_count,
|
||||
args.instance_count, args.first_instance};
|
||||
DrawRenderState state {};
|
||||
if (!PrepareDrawRenderState(buffer, draw, args.render_target_slice_offset, true,
|
||||
state)) {
|
||||
|
||||
Reference in New Issue
Block a user