fix(libSceAgcDriver): skip depth and stencil tests whose plane is absent
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2cf901bcff
commit
48ebf3195e
|
|
@ -86,6 +86,12 @@ bool depthSurfaceBound(const Registers& cx) {
|
|||
return (z != cx.end() && (z->second & 3u) != 0) || (stencil != cx.end() && (stencil->second & 1u) != 0);
|
||||
}
|
||||
|
||||
bool depthPlanesAbsent(const Registers& cx) {
|
||||
const auto z = find(cx, 0x010);
|
||||
const auto stencil = find(cx, 0x011);
|
||||
return z != cx.end() && stencil != cx.end() && (z->second & 3u) == 0 && (stencil->second & 1u) == 0;
|
||||
}
|
||||
|
||||
VkStencilOpState stencilFace(std::uint32_t compare, std::uint32_t ops, std::uint32_t refMask, bool readOnly) {
|
||||
VkStencilOpState face{};
|
||||
face.compareOp = static_cast<VkCompareOp>(compare);
|
||||
|
|
@ -144,8 +150,8 @@ void decodeDepth(const Registers& cx, std::uint32_t depthControl, State& result)
|
|||
const auto zFormat = read(cx, 0x010) & 3u;
|
||||
const bool stencil = (read(cx, 0x011) & 1u) != 0;
|
||||
Require(zFormat != 2, "Z_24 depth is unsupported");
|
||||
Require(zFormat != 0 || (depthControl & 2u) == 0, "depth test without a depth plane");
|
||||
Require(stencil || (depthControl & 1u) == 0, "stencil test without a stencil plane");
|
||||
if (zFormat == 0) depthControl &= ~6u;
|
||||
if (!stencil) depthControl &= ~1u;
|
||||
const auto base = [&](std::uint32_t low, std::uint32_t highOffset) {
|
||||
const auto high = find(cx, highOffset);
|
||||
return (high == cx.end() ? 0ull : static_cast<std::uint64_t>(high->second & 0xffu) << 40u) | (static_cast<std::uint64_t>(read(cx, low)) << 8u);
|
||||
|
|
@ -445,7 +451,7 @@ State DecodeState(const QueueState& queue) {
|
|||
const auto depthControl = read(cx, 0x200);
|
||||
if ((depthControl & 0xbu) != 0 && depthSurfaceBound(cx)) {
|
||||
decodeDepth(cx, depthControl, result);
|
||||
} else if (depthPassThrough(depthControl)) {
|
||||
} else if (depthPassThrough(depthControl) || ((depthControl & 3u) != 0 && depthPlanesAbsent(cx))) {
|
||||
static bool reported = false;
|
||||
if (!reported) {
|
||||
reported = true;
|
||||
|
|
@ -732,7 +738,7 @@ std::string DrawRejection(const QueueState& queue, bool indexed) {
|
|||
if (auto reason = nonzero(cx, 0x207, ~LayerExports, "clip distances, layer, viewport or auxiliary vertex exports"); !reason.empty()) return reason;
|
||||
if (value(cx, 0x200, word)) {
|
||||
const bool surface = (word & 0xbu) != 0 && depthSurfaceBound(cx);
|
||||
if (!surface && !depthPassThrough(word) && !IgnoreDepthTest() && (effectiveDepthControl(word) & DepthControlMask) != 0) return zeroMessage(0x200, word, "depth, stencil or conditional color writes");
|
||||
if (!surface && !((word & 3u) != 0 && depthPlanesAbsent(cx)) && !depthPassThrough(word) && !IgnoreDepthTest() && (effectiveDepthControl(word) & DepthControlMask) != 0) return zeroMessage(0x200, word, "depth, stencil or conditional color writes");
|
||||
if (auto reason = require((word & 8u) == 0 || surface, "depth bounds without a depth surface"); !reason.empty()) return reason;
|
||||
if (auto reason = require((word & 0xc0000000u) == 0, "depth-conditional color writes are unsupported"); !reason.empty()) return reason;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,29 @@ void stateTests() {
|
|||
queue.context[0x200] = 0x007007b6;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "depth");
|
||||
queue = makeState();
|
||||
queue.context[0x010] = 0x80000180;
|
||||
queue.context[0x011] = 0x20000180;
|
||||
queue.context[0x200] = 0x007007b3;
|
||||
queue.context[0x1b3] = 2;
|
||||
queue.context[0x1b4] = 2;
|
||||
state = AgcDriver::Graphics::DecodeState(queue);
|
||||
Require(!state.depthTest && !state.stencilTest, "tests on absent depth and stencil planes were kept");
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, false).empty(), "tests on absent depth and stencil planes were rejected");
|
||||
queue.context[0x011] = 0x20000181;
|
||||
queue.context[0x012] = 0x00001000;
|
||||
queue.context[0x013] = 0x00002000;
|
||||
queue.context[0x015] = 0x00002000;
|
||||
queue.context[0x007] = 0x003f003f;
|
||||
queue.context[0x000] = 0;
|
||||
queue.context[0x002] = 0;
|
||||
queue.context[0x00a] = 0;
|
||||
queue.context[0x00b] = 0x3f800000;
|
||||
queue.context[0x10b] = 0;
|
||||
queue.context[0x10c] = 0x01ffff00;
|
||||
queue.context[0x10d] = 0x01ffff00;
|
||||
state =AgcDriver::Graphics::DecodeState(queue);
|
||||
Require(!state.depthTest && state.stencilTest, "a depth test on an absent depth plane was kept beside a stencil plane");
|
||||
queue = makeState();
|
||||
queue.context[0x10f] = 0x7fc00000;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "non-finite");
|
||||
// The register facade: every register the decoders read is in DrawKeyRegisters (a wrong hit of
|
||||
|
|
|
|||
Loading…
Reference in New Issue