mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ResolvePrimitiveRestart(const CommandBuffer& buffer, vk::PrimitiveTopology topology,
|
static bool ResolvePrimitiveRestart(const CommandBuffer& buffer,
|
||||||
uint32_t index_type_and_size) {
|
const DrawIndexBufferSource& source) {
|
||||||
const auto control = buffer.GetUserConfig().GetPrimitiveResetControl();
|
const auto control = buffer.GetUserConfig().GetPrimitiveResetControl();
|
||||||
EXIT_NOT_IMPLEMENTED((control & ~0x3u) != 0);
|
EXIT_NOT_IMPLEMENTED((control & ~0x3u) != 0);
|
||||||
if ((control & 0x1u) == 0) {
|
if ((control & 0x1u) == 0) {
|
||||||
@@ -876,26 +876,30 @@ static bool ResolvePrimitiveRestart(const CommandBuffer& buffer, vk::PrimitiveTo
|
|||||||
case Prospero::PrimitiveType::kTriStrip: break;
|
case Prospero::PrimitiveType::kTriStrip: break;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
if (topology != vk::PrimitiveTopology::eLineStrip &&
|
|
||||||
topology != vk::PrimitiveTopology::eTriangleStrip &&
|
|
||||||
topology != vk::PrimitiveTopology::eTriangleFan) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t index_mask = 0;
|
const auto element_size = source.guest_element_size;
|
||||||
switch (static_cast<Prospero::IndexType>(index_type_and_size)) {
|
const auto index_mask = UINT32_MAX >> ((4 - element_size) * 8);
|
||||||
case Prospero::IndexType::kIndex8: index_mask = 0xffu; break;
|
const auto reset_index = buffer.GetRegisters().GetPrimitiveResetIndex();
|
||||||
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();
|
|
||||||
if ((control & 0x2u) != 0 && (reset_index & ~index_mask) != 0) {
|
if ((control & 0x2u) != 0 && (reset_index & ~index_mask) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EXIT_NOT_IMPLEMENTED((reset_index & index_mask) != index_mask);
|
const auto restart_index = reset_index & index_mask;
|
||||||
return true;
|
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,
|
bool RenderExecutor::PrepareDrawRenderState(CommandBuffer& buffer, const DrawCallInfo& draw,
|
||||||
@@ -1269,51 +1273,39 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::IndexType index_type = vk::IndexType::eUint16;
|
DrawIndexBufferSource index_source {};
|
||||||
uint64_t index_size = 0;
|
index_source.address = reinterpret_cast<uint64_t>(args.index_addr);
|
||||||
bool expand_index8_to_u16 = false;
|
|
||||||
const bool primitive_restart =
|
|
||||||
ResolvePrimitiveRestart(buffer, topology, args.index_type_and_size);
|
|
||||||
|
|
||||||
switch (static_cast<Prospero::IndexType>(args.index_type_and_size)) {
|
switch (static_cast<Prospero::IndexType>(args.index_type_and_size)) {
|
||||||
case Prospero::IndexType::kIndex16:
|
case Prospero::IndexType::kIndex16:
|
||||||
index_type = vk::IndexType::eUint16;
|
index_source.type = vk::IndexType::eUint16;
|
||||||
index_size = 2 * static_cast<uint64_t>(args.index_count);
|
index_source.guest_element_size = 2;
|
||||||
break;
|
break;
|
||||||
case Prospero::IndexType::kIndex32:
|
case Prospero::IndexType::kIndex32:
|
||||||
index_type = vk::IndexType::eUint32;
|
index_source.type = vk::IndexType::eUint32;
|
||||||
index_size = 4 * static_cast<uint64_t>(args.index_count);
|
index_source.guest_element_size = 4;
|
||||||
break;
|
break;
|
||||||
// Some games use it - need vulkan extension
|
|
||||||
case Prospero::IndexType::kIndex8:
|
case Prospero::IndexType::kIndex8:
|
||||||
index_type = vk::IndexType::eUint16;
|
index_source.guest_element_size = 1;
|
||||||
index_size = static_cast<uint64_t>(args.index_count);
|
|
||||||
expand_index8_to_u16 = true;
|
|
||||||
break;
|
break;
|
||||||
default: EXIT("unknown index_type_and_size: %u\n", args.index_type_and_size);
|
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;
|
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);
|
EXIT_NOT_IMPLEMENTED(args.index_addr == nullptr);
|
||||||
const auto* src = static_cast<const uint8_t*>(args.index_addr);
|
const auto* src = static_cast<const uint8_t*>(args.index_addr);
|
||||||
expanded_indices.resize(args.index_count);
|
expanded_indices.resize(args.index_count);
|
||||||
for (uint32_t i = 0; i < args.index_count; i++) {
|
for (uint32_t i = 0; i < args.index_count; i++) {
|
||||||
expanded_indices[i] = primitive_restart && src[i] == 0xffu ? 0xffffu : src[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 {};
|
const DrawCallInfo draw {"DrawIndex", CommandBufferDebugOp::DrawIndex, args.index_count,
|
||||||
index_source.address = reinterpret_cast<uint64_t>(args.index_addr);
|
args.instance_count, args.first_instance};
|
||||||
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);
|
|
||||||
|
|
||||||
DrawRenderState state {};
|
DrawRenderState state {};
|
||||||
if (!PrepareDrawRenderState(buffer, draw, args.render_target_slice_offset, true,
|
if (!PrepareDrawRenderState(buffer, draw, args.render_target_slice_offset, true,
|
||||||
state)) {
|
state)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user