Merge pull request #1139 from alfalfa-star/fix/agc-inert-pixel-stage
fix(agc): run draws whose pixel stage cannot run without its program
This commit is contained in:
commit
e705d430d6
|
|
@ -15,8 +15,9 @@ std::shared_ptr<DrawDecode> Driver::decodeDraw(const QueueState& queue, const Su
|
|||
require((high & ~0xffu) == 0, "reserved graphics program address bits are set");
|
||||
return (static_cast<std::uint64_t>(readRegister(queue.shader, base)) << 8u) | (static_cast<std::uint64_t>(high) << 40u);
|
||||
};
|
||||
const bool pixelSkipped = Graphics::PixelProgramSkipped(queue);
|
||||
const auto prepare = [&](std::uint64_t address, std::uint8_t type, Stage stage, std::uint32_t rsrc2, std::uint32_t userDataBase) {
|
||||
const bool nullPixel = address == 0 && stage == Stage::Fragment;
|
||||
const bool nullPixel = stage == Stage::Fragment && (address == 0 || pixelSkipped);
|
||||
if (nullPixel) address = NullPixelProgramAddress();
|
||||
auto it = submission.shaders->upper_bound(address);
|
||||
require(it != submission.shaders->begin(), "graphics program does not belong to a registered shader");
|
||||
|
|
@ -89,7 +90,7 @@ std::shared_ptr<DrawDecode> Driver::decodeDraw(const QueueState& queue, const Su
|
|||
} else {
|
||||
append(0xc8, 2, Stage::Vertex, 0x8b, 0x8c, Role::Main);
|
||||
}
|
||||
const bool nullPixel = Graphics::PixelProgramUnset(queue);
|
||||
const bool nullPixel = pixelSkipped;
|
||||
if (nullPixel) {
|
||||
const auto rejection = Graphics::NullPixelProgramRejection(queue);
|
||||
require(rejection.empty(), rejection.c_str());
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ std::optional<ColorMetadataPass> DecodeColorMetadataPass(const QueueState& queue
|
|||
// this precheck covers, evaluated without exceptions before the draw is decoded; empty when they
|
||||
// pass (DecodeState still checks everything). A register a rule needs that is absent is no verdict.
|
||||
std::string DrawRejection(const QueueState& queue, bool indexed);
|
||||
bool PixelProgramUnset(const QueueState& queue);
|
||||
bool PixelProgramSkipped(const QueueState& queue);
|
||||
std::string NullPixelProgramRejection(const QueueState& queue);
|
||||
|
||||
// The recording facade of the draw decoders (design_cpu_final M8, step 8a): every register read
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ constexpr std::uint32_t DepthControlMask = ~0x007007f0u;
|
|||
// EXEC_ON_HIER_FAIL / EXEC_ON_NOOP / EXEC_IF_OVERLAPPED (bits 9, 10, 17) only force the pixel shader
|
||||
// to run, which it always does here.
|
||||
constexpr std::uint32_t ShaderControlMask = ~(0x0000f870u | 0x00020600u);
|
||||
constexpr std::uint32_t PixelStageRunsMask = 0x00020747u;
|
||||
constexpr std::uint32_t AlphaToCoverageMask = ~0x0001ff00u;
|
||||
constexpr std::uint32_t ScanModeMask = ~2u;
|
||||
constexpr std::uint32_t ScanControlMask = ~0x06023fffu;
|
||||
|
|
@ -806,7 +807,7 @@ std::string DrawRejection(const QueueState& queue, bool indexed) {
|
|||
std::uint32_t targetMask = 0, shaderMask = 0;
|
||||
if (value(cx, 0x8e, targetMask) && value(cx, 0x8f, shaderMask) && value(cx, 0x202, word) && !colorControlSupported(word, (targetMask & shaderMask) != 0)) return colorControlMessage(word);
|
||||
if (auto reason = nonzero(cx, 0x1c4, zFormatSupported(zFormat) ? 0u : ~0u, "depth or sample-mask export"); !reason.empty()) return reason;
|
||||
if (PixelProgramUnset(queue)) return NullPixelProgramRejection(queue);
|
||||
if (PixelProgramSkipped(queue)) return NullPixelProgramRejection(queue);
|
||||
for (const auto offset : {0x1b3u, 0x1b4u, 0x1c5u}) {
|
||||
if (find(cx, offset) != cx.end()) continue;
|
||||
char text[64];
|
||||
|
|
@ -816,10 +817,17 @@ std::string DrawRejection(const QueueState& queue, bool indexed) {
|
|||
return {};
|
||||
}
|
||||
|
||||
bool PixelProgramUnset(const QueueState& queue) {
|
||||
bool PixelProgramSkipped(const QueueState& queue) {
|
||||
const auto low = find(queue.shader, 0x008, RegisterBank::Shader);
|
||||
const auto high = find(queue.shader, 0x009, RegisterBank::Shader);
|
||||
return low != queue.shader.end() && high != queue.shader.end() && low->second == 0 && high->second == 0;
|
||||
if (low != queue.shader.end() && high != queue.shader.end() && low->second == 0 && high->second == 0) return true;
|
||||
const auto& cx = queue.context;
|
||||
const auto targetMask = find(cx, 0x8e);
|
||||
const auto shaderMask = find(cx, 0x8f);
|
||||
const auto zFormat = find(cx, 0x1c4);
|
||||
const auto shaderControl = find(cx, 0x203);
|
||||
if (targetMask == cx.end() || shaderMask == cx.end() || zFormat == cx.end() || shaderControl == cx.end()) return false;
|
||||
return (targetMask->second & shaderMask->second) == 0 && zFormat->second == 0 && (shaderControl->second & PixelStageRunsMask) == 0;
|
||||
}
|
||||
|
||||
std::string NullPixelProgramRejection(const QueueState& queue) {
|
||||
|
|
|
|||
|
|
@ -207,11 +207,11 @@ void stateTests() {
|
|||
queue.context.erase(0x1c5);
|
||||
queue.shader[0x008] = 0x100;
|
||||
queue.shader[0x009] = 0;
|
||||
Require(!AgcDriver::Graphics::PixelProgramUnset(queue), "a pixel program address was read as unset");
|
||||
Require(!AgcDriver::Graphics::PixelProgramSkipped(queue), "a pixel program address was read as unset");
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, true).find("missing register at DWORD 0x1b3") != std::string::npos, "a real pixel program without SPI_PS_INPUT_ENA was accepted");
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodePixelStageInfo(queue.context, std::array<std::uint8_t, 8>{0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u, 0xe4u}); }, "missing register");
|
||||
queue.shader[0x008] = 0;
|
||||
Require(AgcDriver::Graphics::PixelProgramUnset(queue), "a zero pixel program address was not read as unset");
|
||||
Require(AgcDriver::Graphics::PixelProgramSkipped(queue), "a zero pixel program address was not read as unset");
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, true).find("writes color") != std::string::npos, "a draw without a pixel program that writes color was accepted");
|
||||
queue.context[0x8e] = 0;
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, true).empty(), "a depth-only draw without a pixel program was rejected");
|
||||
|
|
@ -220,6 +220,24 @@ void stateTests() {
|
|||
const auto unset = AgcDriver::Graphics::DecodePixelStageInfo(queue.context, AgcDriver::Graphics::ExportMappings(state), true);
|
||||
Require(unset.inputAddr == ShaderRecompiler::PixelInputBit(ShaderRecompiler::PixelInput::PerspectiveCenter), "unset pixel inputs of the null program did not read as PERSP_CENTER_ENA");
|
||||
for (const auto mode : unset.targetOutputMode) Require(mode == 0, "an unset SPI_SHADER_COL_FORMAT exported a color");
|
||||
queue.shader[0x008] = 0x100;
|
||||
queue.context[0x1c4] = 0;
|
||||
queue.context[0x203] = 0;
|
||||
Require(AgcDriver::Graphics::PixelProgramSkipped(queue), "a pixel program that writes nothing and cannot run was not skipped");
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, true).empty(), "a depth-only draw whose pixel program cannot run was rejected");
|
||||
for (const auto [control, what] : {std::pair{0x400u, "EXEC_ON_NOOP"}, std::pair{0x40u, "KILL_ENABLE"}}) {
|
||||
queue.context[0x203] = control;
|
||||
Require(!AgcDriver::Graphics::PixelProgramSkipped(queue), std::string("a pixel program with ") + what + " was skipped");
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, true).find("missing register at DWORD 0x1b3") != std::string::npos, std::string("a pixel program with ") + what + " ran without SPI_PS_INPUT_ENA");
|
||||
}
|
||||
queue.context[0x203] = 1;
|
||||
Require(!AgcDriver::Graphics::PixelProgramSkipped(queue), "a pixel program with Z_EXPORT_ENABLE was skipped");
|
||||
queue.context[0x203] = 0;
|
||||
queue.context[0x1c4] = 1;
|
||||
Require(!AgcDriver::Graphics::PixelProgramSkipped(queue), "a pixel program exporting depth was skipped");
|
||||
queue.context[0x1c4] = 0;
|
||||
queue.context[0x8e] = 0xf;
|
||||
Require(!AgcDriver::Graphics::PixelProgramSkipped(queue), "a pixel program writing color was skipped");
|
||||
}
|
||||
|
||||
VkFormatFeatureFlags srgb8Features = 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue