Skip to content
Merged
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
35 changes: 35 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/TessellationLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ struct Hull {
void readRing(IrValue& offset, IrValue& predicate) {
auto& loaded = builder.Emit(IrOpcode::LoadBufferU32, IrType::U32, {&ringResource(), &builder.Constant(0u), &offset, &offChip(), &predicate}, MemoryFlags{RingMemory, RingReadPc});
static_cast<void>(builder.Emit(IrOpcode::ReferenceU32, IrType::Void, {&loaded}));
}

IrValue& packed() {
return builder.BitwiseOr(builder.ShiftLeftLogical(invocation(), builder.Constant(8u)), relativePatch());
}

IrValue& merge(std::uint32_t firstMultiple, std::uint32_t secondMultiple) {
Expand Down Expand Up @@ -341,6 +345,14 @@ bool LowersUnderComplementedBallot(Conjunction conjunction) {
return LoweredAt(hull.program, address);
}

bool OwnControlPoint(const IrValue* address, std::uint32_t stride) {
if (address == nullptr || address->Opcode() != IrOpcode::IAdd32 || !address->Argument(1)->Resolve()->HasImmediate() || address->Argument(1)->Resolve()->ImmediateU32() != 0u) return false;
const IrValue* scaled = address->Argument(0)->Resolve();
if (scaled->Opcode() != IrOpcode::IMul32 || scaled->Argument(1)->Resolve()->ImmediateU32() != stride) return false;
const IrValue* invocation = scaled->Argument(0)->Resolve();
return invocation->Opcode() == IrOpcode::GetBuiltin && invocation->Argument(0)->Resolve()->ImmediateU32() == static_cast<std::uint32_t>(StageInputKind::InvocationId);
}

bool run(const char* name, const std::function<bool()>& body) {
bool passed = false;
try {
Expand Down Expand Up @@ -548,6 +560,29 @@ int main() {

passed &= run("a hull read of another control point's output at an immediate address past the last control point reads the last control point", [] {
return EmittedControlPoint(IrShaderStage::TessellationControl, TessellationAttribute::ControlOutput, InputControlPoints * 16u) == InputControlPoints - 1u;
});

passed &= run("a hull read at its control point masked out of the packed control point and relative patch reads its own input control point", [] {
Hull hull;
auto& masked = hull.builder.BitwiseAnd(hull.packed(), hull.builder.Constant(0x1f00u));
hull.read(hull.inPatch(hull.builder.ShiftRightLogical(masked, hull.builder.Constant(3u))));
const Outcome outcome = Lower(hull.program);
if (!outcome.lowered) std::fprintf(stderr, "refused: %s\n", outcome.reason.c_str());
return outcome.lowered && OwnControlPoint(outcome.emitted, LocalStride);
});

passed &= run("a mask that drops the low bit of the packed control point is refused", [] {
Hull hull;
auto& masked = hull.builder.BitwiseAnd(hull.packed(), hull.builder.Constant(0x1e00u));
hull.read(hull.inPatch(hull.builder.ShiftRightLogical(masked, hull.builder.Constant(3u))));
return RefusedBecause(hull.program, "not affine");
});

passed &= run("a mask with a gap below the packed control point is refused", [] {
Hull hull;
auto& masked = hull.builder.BitwiseAnd(hull.packed(), hull.builder.Constant(0x1f0fu));
hull.read(hull.inPatch(hull.builder.ShiftRightLogical(masked, hull.builder.Constant(3u))));
return RefusedBecause(hull.program, "not affine");
});

return passed ? 0 : 1;
Expand Down
11 changes: 11 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/execution/Tessellation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ alignas(256) constexpr std::array<std::uint32_t, 49> HullCode{
0xbf810000,
};

alignas(256) constexpr std::array<std::uint32_t, 51> HullMaskedControlPoint{
0xd7650000, 0x000100c1, 0xd7660000, 0x000200c1, 0xbf8a0000, 0x7da206f9, 0x81060000, 0xd5480014,
0x02151101, 0x362402ff, 0x000000ff, 0x160028a0, 0xd5430015, 0x040224ff, 0x00000060, 0xdbfc0000,
0x02000015, 0x362c02ff, 0x00001f00, 0x2c2c2c84, 0xd5430016, 0x045a24ff, 0x00000030, 0xbf8cc07f,
0xe0781000, 0x02020216, 0x7da82881, 0xbe94047e, 0xb06a0060, 0x162602f9, 0x0086066a, 0xd8d80008,
0x06000013, 0xd8dc1008, 0x07000013, 0xbf8cc07f, 0x7e300306, 0x7e320306, 0x7e340306, 0x7e360306,
0x34142484, 0xbefe0414, 0xe0781000, 0x0403180a, 0x4a162481, 0x16161690, 0x4c1616ff, 0x00008000,
0xe0741000, 0x0202070b, 0xbf810000,
};

alignas(256) constexpr std::array<std::uint32_t, 54> HullCompareBranch{
0xd4040016, 0x00020080, 0xbeea0416, 0xbf870001, 0xbf800000, 0xd7650000, 0x000100c1, 0xd7660000,
0x000200c1, 0xbf8a0000, 0x7da206f9, 0x81060000, 0xd5480014, 0x02151101, 0x362402ff, 0x000000ff,
Expand Down Expand Up @@ -1129,6 +1139,7 @@ int main() {
ExpectRefusal(target, ShaderStage::TessellationControl, HullDescendingRecords, "outside its control points and patch constants", {{3u, 3u, 1u, 2u, 2u, 129u}, Indices});

RequirePatches(*device, target, HullCode, "hull program");
RequirePatches(*device, target, HullMaskedControlPoint, "hull program masking its control point out of v1 for its off-chip record");
RequirePatches(*device, target, HullRestoredExecSaved, "hull program saving its restored exec");
RequirePatches(*device, target, HullNextInput, "hull program reading the next of 4 input control points of 24 bytes", NextInputTriangles, LocalCodeStride24);
RequirePatches(*device, target, HullDynamicIndex, "hull program reading a control point at a computed index");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,12 @@ class AddressEvaluator {
const auto parts = split(value, divisor);
if (!parts) return std::nullopt;
if (parts->second.Scalar()) return Affine{0, 0, parts->second.constant & bits};
return bits == divisor - 1 ? std::optional(parts->second) : std::nullopt;
if (bits == divisor - 1) return parts->second;
const auto lowest = 1ll << std::countr_zero(static_cast<std::uint64_t>(bits));
if (bits != divisor - lowest) return std::nullopt;
const auto field = split(parts->second, lowest);
if (!field) return std::nullopt;
return field->first;
}

[[nodiscard]] std::optional<Affine> disjoint(const Affine& high, const Affine& low) const {
Expand Down
Loading