Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,16 @@ if(BUILD_TESTING)
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endforeach()
add_test(NAME agc_driver_sparse_indirect_indices_unreadable COMMAND agc_driver_sparse_indirect_indices_tests --unreadable)
add_test(NAME agc_driver_sparse_indirect_indices_no_size COMMAND agc_driver_sparse_indirect_indices_tests --no-size)
add_test(NAME agc_driver_sparse_indirect_indices_no_size_unreadable COMMAND agc_driver_sparse_indirect_indices_tests --no-size-unreadable)
add_test(NAME agc_driver_sparse_indirect_indices_no_size_unreadable_record COMMAND agc_driver_sparse_indirect_indices_tests --no-size-unreadable-record)
set_tests_properties(agc_driver_sparse_indirect_indices agc_driver_sparse_indirect_indices_unreadable agc_driver_sparse_indirect_indices_no_size agc_driver_sparse_indirect_indices_no_size_unreadable agc_driver_sparse_indirect_indices_no_size_unreadable_record PROPERTIES
ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" SKIP_RETURN_CODE 77 TIMEOUT 30 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
if(WIN32)
set_tests_properties(agc_driver_sparse_indirect_indices_unreadable agc_driver_sparse_indirect_indices_no_size agc_driver_sparse_indirect_indices_no_size_unreadable agc_driver_sparse_indirect_indices_no_size_unreadable_record PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test(NAME agc_driver_partially_resident_pending_stores COMMAND agc_driver_partially_resident_snapshot_tests --pending-stores)
set_tests_properties(agc_driver_partially_resident_pending_stores PROPERTIES ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" TIMEOUT 30)
if(WIN32)
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/Execution/include/Pm4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct DrawParameters {
std::uint32_t drawIndexLocation;
bool drawIndexEnabled;
std::uint32_t indxOffset;
bool indexLimitKnown = true;
enum class Rule : std::uint8_t { InPlace, Constant };
Rule vertexRule = Rule::Constant;
Rule instanceRule = Rule::Constant;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ struct QueueState {
std::uint64_t indexBase = 0;
std::uint64_t drawIndirectBase = 0;
std::uint64_t dispatchIndirectBase = 0;
std::uint32_t indexBufferSize = 0;
std::optional<std::uint32_t> indexBufferSize;
std::uint32_t indexType = 0;
std::uint32_t instanceCount = 1;
std::vector<std::string> markers;
Expand Down
12 changes: 9 additions & 3 deletions core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/Draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,10 +532,16 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
}
Pm4::DrawParameters direct{0, arguments.count, 0, arguments.instances, drawParameters.flags, drawParameters.indexed, 0, 0};
if (drawParameters.indexed) {

if (arguments.firstVertexOrIndex >= drawParameters.indexCount) continue;
if (indirect.indexLimitKnown) {
if (arguments.firstVertexOrIndex >= drawParameters.indexCount) continue;
direct.indexCount = std::min(arguments.count, drawParameters.indexCount - arguments.firstVertexOrIndex);
} else {
const auto end = static_cast<std::uint64_t>(arguments.firstVertexOrIndex) + arguments.count;
require(end <= std::numeric_limits<std::uint32_t>::max(), "indirect draw index range overflow");
require(end * drawParameters.indexSize <= std::numeric_limits<std::uint64_t>::max() - drawParameters.indexAddress, "indirect draw index range address overflow");
direct.indexCount = arguments.count;
}
direct.indexAddress = drawParameters.indexAddress + static_cast<std::uint64_t>(arguments.firstVertexOrIndex) * drawParameters.indexSize;
direct.indexCount = std::min(arguments.count, drawParameters.indexCount - arguments.firstVertexOrIndex);
direct.indexSize = drawParameters.indexSize;
} else {
direct.firstVertex = indirect.indxOffset;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "prx/libSceAgcDriver/Execution/include/Pm4.hpp"
#include <cstdlib>

Expand Down Expand Up @@ -28,6 +29,8 @@ std::optional<Graphics::IndirectDrawPath> Driver::ClassifyIndirectDraw(const Sha
using Path = Graphics::IndirectDrawPath;
const auto support = localDevice->DrawIndirectSupport();
const auto fail = [&](Path reason) { if (!indirectCpu) indirectCpu = reason; };
if (drawParameters.indexed && !indirect.indexLimitKnown) fail(Path::IndexLimitUnknown);
else if (drawParameters.indexed && !GuestMemory::Accessible(reinterpret_cast<const void*>(drawParameters.indexAddress), static_cast<std::size_t>(drawParameters.indexCount) * drawParameters.indexSize)) fail(Path::IndexRange);
constexpr std::uint32_t NoLocation = 0x280u;
const bool meshPath = graphics.stages.mesh.has_value() && !graphics.stages.tessellation && !graphics.rectList;
const bool meshGpuSide = meshPath && drawParameters.indexed && indirect.count == 1 && !indirect.countIndirect && indirect.baseVertexLocation == NoLocation && indirect.startInstanceLocation == NoLocation && (!indirect.drawIndexEnabled || indirect.drawIndexLocation == NoLocation);
Expand Down
16 changes: 9 additions & 7 deletions core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,16 +851,18 @@ DrawParameters resolveIndirectDraw(std::span<const std::uint32_t> packet, const
draw.firstVertex = offset->second;
indirect.indxOffset = offset->second;
} else {
// The CP clamps firstIndex + indexCount to INDEX_BUFFER_SIZE: the declared range is the
// hardware's view of the index buffer, so that is what gets bound.
const auto indexSize = indexSizeOf(queue);
require(queue.indexBufferSize != 0, "INDEX_BUFFER_SIZE has not been set");
const auto bytes = static_cast<std::uint64_t>(queue.indexBufferSize) * indexSize;
require(bytes <= std::numeric_limits<std::size_t>::max() && bytes <= std::numeric_limits<std::uint64_t>::max() - queue.indexBase, "index range size overflow");
GuestMemory::CheckRange(reinterpret_cast<const void*>(queue.indexBase), static_cast<std::size_t>(bytes), indexSize);
draw.indexAddress = queue.indexBase;
draw.indexCount = queue.indexBufferSize;
draw.indexSize = indexSize;
if (queue.indexBufferSize) {
require(*queue.indexBufferSize != 0, "INDEX_BUFFER_SIZE is zero");
const auto bytes = static_cast<std::uint64_t>(*queue.indexBufferSize) * indexSize;
require(bytes <= std::numeric_limits<std::size_t>::max() && bytes <= std::numeric_limits<std::uint64_t>::max() - queue.indexBase, "index range size overflow");
draw.indexCount = *queue.indexBufferSize;
} else {
draw.indexCount = 0;
indirect.indexLimitKnown = false;
}
}
draw.indirect = indirect;
return draw;
Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ bool DrawRecipes();
// draw index, the vertex ranges, the device features, APS5_NO_GPU_INDIRECT_DRAW) or under the device
// lock in Draw (the memory state of the records). `readMs` is the CPU read's time (its sync);
// `rewritten` counts a GPU-side draw whose records were copied and patched with a constant.
enum class IndirectDrawPath : std::uint8_t { Gpu, NotFolded, FetchUnknown, NonVertexPath, IndxOffset, DrawIndex, VertexRange, FeatureGap, PendingImage, PendingLabelOrCopy, NotImported, Disabled, Count };
enum class IndirectDrawPath : std::uint8_t { Gpu, NotFolded, FetchUnknown, NonVertexPath, IndxOffset, DrawIndex, VertexRange, FeatureGap, PendingImage, PendingLabelOrCopy, NotImported, Disabled, IndexRange, IndexLimitUnknown, Count };
void CountIndirectDraw(IndirectDrawPath path, double readMs, bool rewritten = false);
std::array<std::uint64_t, static_cast<std::size_t>(IndirectDrawPath::Count)> IndirectDrawCounts();

Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ constexpr std::array<const char*, PhaseCount> DrawPhaseNames{"validate", "vertex
enum SyncReason : std::size_t { SyncNone, SyncNotResident, SyncNoRecorder, SyncDisabled, SyncCopiedWrites, SyncLease, SyncCount };
constexpr std::array<const char*, SyncCount> SyncReasonNames{"none", "non-resident target", "no recorder", "disabled", "copied writes", "lease"};
constexpr std::size_t IndirectPathCount = static_cast<std::size_t>(IndirectDrawPath::Count);
constexpr std::array<const char*, IndirectPathCount> IndirectDrawPathNames{"gpu-side", "patched SGPR not folded", "fetch offset unknown", "non-vertex path", "GE_INDX_OFFSET", "draw index", "vertex range too large", "feature gap", "pending image results", "pending label or copied write", "not imported", "disabled"};
constexpr std::array<const char*, IndirectPathCount> IndirectDrawPathNames{"gpu-side", "patched SGPR not folded", "fetch offset unknown", "non-vertex path", "GE_INDX_OFFSET", "draw index", "vertex range too large", "feature gap", "pending image results", "pending label or copied write", "not imported", "disabled", "index range not fully readable", "index limit unknown"};

// What became of one draw, for the totals.
struct DrawOutcome {
Expand Down
17 changes: 16 additions & 1 deletion core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,17 @@ void testIndirectDraw() {
alignas(4) std::array<std::uint16_t, 8> indices{};
state.indexBase = reinterpret_cast<std::uintptr_t>(indices.data());
state.indexType = 0;
state.indexBufferSize.reset();
const auto unlimited = AgcDriver::Pm4::ResolveDraw(makePacket(0x25, {0, 0x8c, 0x280, 0}), state);
check(unlimited.indexed && unlimited.indirect && !unlimited.indirect->indexLimitKnown && unlimited.indexCount == 0 && unlimited.indexAddress == state.indexBase && unlimited.indexSize == 2 && unlimited.indirect->recordBytes == 20, "an indexed indirect draw without INDEX_BUFFER_SIZE did not resolve with an unknown limit");
const auto unlimitedMulti = AgcDriver::Pm4::ResolveDraw(makePacket(0x38, {0, 0x8c, 0x280, 0x280, 3, 0, 0, 20, 0}), state);
check(unlimitedMulti.indirect && !unlimitedMulti.indirect->indexLimitKnown && unlimitedMulti.indirect->count == 3 && unlimitedMulti.indirect->stride == 20, "a multi indexed indirect draw without INDEX_BUFFER_SIZE did not resolve with an unknown limit");
execute(state, makePacket(0x13, {0}));
check(state.indexBufferSize.has_value() && *state.indexBufferSize == 0, "INDEX_BUFFER_SIZE of zero was not recorded as written");
expectFailure([&] { AgcDriver::Pm4::ResolveDraw(makePacket(0x25, {0, 0x8c, 0x280, 0}), state); }, "INDEX_BUFFER_SIZE");
expectFailure([&] { AgcDriver::Pm4::ResolveDraw(makePacket(0x38, {0, 0x8c, 0x280, 0x280, 3, 0, 0, 20, 0}), state); }, "INDEX_BUFFER_SIZE");
state.indexBufferSize = 8;
check(AgcDriver::Pm4::ResolveDraw(makePacket(0x25, {0, 0x8c, 0x280, 0}), state).indirect->indexLimitKnown, "a written INDEX_BUFFER_SIZE resolved with an unknown limit");
const auto indexed = AgcDriver::Pm4::ResolveDraw(makePacket(0x25, {0, 0x8c, 0x280, 0}), state);
check(indexed.indexed && indexed.indexAddress == state.indexBase && indexed.indexCount == 8 && indexed.indexSize == 2 && indexed.indirect->recordBytes == 20 && indexed.indirect->stride == 20 && indexed.firstVertex == 0 && indexed.indirect->indxOffset == 0, "indexed indirect draw mismatch");
check(indexed.indirect->VertexDwordOffset() == 12 && indexed.indirect->InstanceDwordOffset() == 16, "indexed record geometry mismatch");
Expand Down Expand Up @@ -414,7 +423,13 @@ void testIndexAttributesIndirect() {
check(sameDraw(indirectFromRecord, AgcDriver::Pm4::ResolveDraw(indirectDraw, direct)) && indirectFromRecord.indexAddress == indexAddress && indirectFromRecord.indexCount == 12 && indirectFromRecord.indexSize == 4, "an indexed indirect draw after INDEX_ATTRIBUTES_INDIRECT differs from the same draw after the direct packets");
records[6] = 0x7fffffffu;
execute(loaded, packet);
expectFailure([&] { AgcDriver::Pm4::ResolveDraw(indirectDraw, loaded); }, "guest");
const auto largeIndirect = AgcDriver::Pm4::ResolveDraw(indirectDraw, loaded);
check(largeIndirect.indexAddress == indexAddress && largeIndirect.indexCount == records[6] && largeIndirect.indexSize == 4, "an indirect draw did not preserve its declared index limit for record resolution");
loaded.indexBase = std::numeric_limits<std::uint64_t>::max() - 3u;
expectFailure([&] { AgcDriver::Pm4::ResolveDraw(indirectDraw, loaded); }, "index range size overflow");
loaded.indexBase = indexAddress + 1u;
expectFailure([&] { AgcDriver::Pm4::ResolveDraw(indirectDraw, loaded); }, "misaligned index base");
loaded.indexBase = indexAddress;
records[6] = 12;

static std::size_t flushed = 0;
Expand Down
Loading
Loading