feat(agc): implement primitive-ordered pixel shaders with fragment shader interlock

DecodeState and the draw precheck rejected DB_SHADER_CONTROL bit 16,
PRIMITIVE_ORDERED_PIXEL_SHADER (POPS), which runs the ordered section
of overlapping pixels' shaders in primitive order. The bit now reaches
the recompiler as a pixel stage field, and such a pixel shader declares
PixelInterlockOrderedEXT and runs its whole body between
OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT; an
invocation that a BDA read fault kills ends the interlock first. The
POPS collision SGPRs read 0, so a title skips its POPS wait and runs
its per-collision loop once. An image_load still reads a sampled
binding, which misses an earlier overlapping primitive's image_store in
the same draw. The device enables VK_EXT_fragment_shader_interlock when
it has fragmentShaderPixelInterlock; without it the recompile throws,
as does a nonzero POPS_OVERLAP_NUM_SAMPLES. The field is part of the
recompile cache key, the draw key and the serialized request (version 10).
This commit is contained in:
Celegans12 authored and Adrià Franch committed 2026-10-08 11:18:46 +02:00
1 parent 3e32797cca
commit e1d4e699be
21 files changed
+462 -11

No files matched your search

@@ -305,6 +305,7 @@ void writePixelInfo(Writer& writer, const ShaderPixelStageInfo& info) {
writer.WriteBool(info.earlyZ);
writer.WriteBool(info.executeOnNoop);
writer.WriteU8(static_cast<std::uint8_t>(info.conservativeZExport));
writer.WriteBool(info.orderedPixelShader);
for (const std::uint8_t value : info.targetOutputMode) {
writer.WriteU8(value);
}
@@ -341,6 +342,7 @@ ShaderPixelStageInfo readPixelInfo(Reader& reader, std::uint32_t version) {
info.earlyZ = reader.ReadBool();
info.executeOnNoop = reader.ReadBool();
if (version >= 7u) info.conservativeZExport = readConservativeZExport(reader);
if (version >= 11u) info.orderedPixelShader = reader.ReadBool();
for (std::uint8_t& value : info.targetOutputMode) {
value = reader.ReadU8();
}
@@ -697,7 +699,7 @@ std::string RequestSerializer::Serialize(const RecompileRequest& request) const
std::string buffer;
Writer writer(buffer);
writer.WriteU32(0x41505335u);
writer.WriteU32(10u);
writer.WriteU32(11u);
writeShaderBinary(writer, request.shader);
writeGuestContext(writer, request.context);
writeSpirvTarget(writer, request.target);
@@ -723,7 +725,7 @@ DeserializedRequest RequestSerializer::Deserialize(std::string_view text) const
Reader reader(decoded);
if (reader.ReadU32() != 0x41505335u) throw std::runtime_error("invalid recompile request signature");
const auto version = reader.ReadU32();
if (version < 1u || version > 10u) throw std::runtime_error("unsupported recompile request serialization version");
if (version < 1u || version > 11u) throw std::runtime_error("unsupported recompile request serialization version");
DeserializedRequest result{};
result.request.shader = readShaderBinary(reader, result.shaderCode, result.shaderHeader);
result.request.context = readGuestContext(reader, result, version);