mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-07 13:39:55 +00:00
fix(shader): lower hulls that write one output control point per patch
A hull with one output control point writes its control point at the
patch record offset alone, so the write has no control-point term and
was taken for a patch constant with no control stride ('the hull shader
writes off-chip memory outside its control points and patch constants').
Take the control stride from the patch term of such writes when the
write fits in one record (its offset is at least 0 and its end within
the patch term), the rule domain programs already apply to control-point
reads; patch-constant records lie outside that, below the top of the
off-chip block or above every control point. With one invocation per
patch, per-patch outputs also need no control-point-0 guard. Resident
Evil Village's quad patches have one output control point.
This commit is contained in:
1 parent
e25d561b7c
commit
1243f067b1
2 files changed
+18
-1
No files matched your search
@@ -73,6 +73,16 @@ alignas(256) constexpr std::array<std::uint32_t, 49> HullSingleInput{
|
||||
0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 49> HullSingleOutput{
|
||||
0xd7650000, 0x000100c1, 0xd7660000, 0x000200c1, 0xbf8a0000, 0x7da206f9, 0x81060000, 0xd5480014,
|
||||
0x02151101, 0x362402ff, 0x000000ff, 0x160028a0, 0xd5430015, 0x022224ff, 0x00000020, 0xdbfc0000,
|
||||
0x02000015, 0x7e2c0280, 0xd5430016, 0x045a24ff, 0x00000010, 0xbf8cc07f, 0xe0781000, 0x02020216,
|
||||
0xbf800000, 0xbe94047e, 0xb06a0020, 0x162602f9, 0x0086066a, 0xd8d80008, 0x06000013, 0xd8dc0201,
|
||||
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, 51> HullRestoredExecSaved{
|
||||
0xd7650000, 0x000100c1, 0xd7660000, 0x000200c1, 0xbf8a0000, 0x7da206f9, 0x81060000, 0xd5480014,
|
||||
0x02151101, 0x362402ff, 0x000000ff, 0x160028a0, 0xd5430015, 0x040224ff, 0x00000060, 0xdbfc0000,
|
||||
@@ -742,6 +752,7 @@ ShaderRecompiler::RecompileResult CompileHull(const ShaderRecompiler::SpirvTarge
|
||||
|
||||
void RequireSingleControlPointHulls(const ShaderRecompiler::SpirvTarget& target) {
|
||||
Require(!CompileHull(target, HullSingleInput, {1u, 3u, 1u, 2u, 2u}).spirv.empty(), "a hull that reads only the one input control point of its patch was not compiled");
|
||||
Require(!CompileHull(target, HullSingleOutput, {1u, 1u, 1u, 2u, 2u}).spirv.empty(), "a hull with one output control point and unguarded patch outputs was not compiled");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -656,11 +656,16 @@ private:
|
||||
void derive() {
|
||||
const auto inputs = static_cast<std::int64_t>(tessellation.inputControlPoints);
|
||||
const auto outputs = static_cast<std::int64_t>(tessellation.outputControlPoints);
|
||||
const auto soleControlPoint = [&](const Access& access) {
|
||||
const auto end = access.address.constant + 4 * static_cast<std::int64_t>(access.components);
|
||||
return outputs == 1 && access.address.vertex == 0 && access.address.relative > 0 && access.address.constant >= 0 && end <= access.address.relative;
|
||||
};
|
||||
for (auto& access : accesses) {
|
||||
if (access.kind == TessellationAttribute::LocalOutput) agree(localStride, access.address.relative, access.pc);
|
||||
if (access.kind == TessellationAttribute::ControlInput && access.address.vertex != 0) agree(localStride, access.address.vertex, access.pc);
|
||||
if (access.kind == TessellationAttribute::ControlInput && (access.address.dynamic || access.address.vertex == 0) && access.address.relative > 0 && access.address.relative % inputs == 0) agree(localStride, access.address.relative / inputs, access.pc);
|
||||
if (access.kind == TessellationAttribute::ControlOutput && access.address.vertex != 0) agree(controlStride, access.address.vertex, access.pc);
|
||||
if (access.kind == TessellationAttribute::ControlOutput && soleControlPoint(access)) agree(controlStride, access.address.relative, access.pc);
|
||||
if (access.kind == TessellationAttribute::EvaluationInput) {
|
||||
const auto end = access.address.constant + 4 * static_cast<std::int64_t>(access.components);
|
||||
if (access.address.relative > 0 && access.address.relative % outputs == 0 && access.address.constant >= 0 && end <= access.address.relative) {
|
||||
@@ -692,7 +697,7 @@ private:
|
||||
if (address.dynamic && (address.dynamicScale == 0 || address.dynamicScale % localStride != 0)) Fail("the hull shader reads LDS at a computed offset that is not a whole number of control points", access.pc);
|
||||
break;
|
||||
case TessellationAttribute::ControlOutput:
|
||||
if (address.vertex == 0) {
|
||||
if (address.vertex == 0 && !soleControlPoint(access)) {
|
||||
if (controlStride == 0u || evaluator.Lowest(address) < static_cast<std::int64_t>(tessellation.patchesPerGroup) * outputs * controlStride) Fail("the hull shader writes off-chip memory outside its control points and patch constants", access.pc);
|
||||
record(access, end);
|
||||
access.kind = TessellationAttribute::PatchOutput;
|
||||
@@ -817,6 +822,7 @@ private:
|
||||
}
|
||||
|
||||
void requireFirstInvocation(const Access& access) {
|
||||
if (tessellation.outputControlPoints == 1u) return;
|
||||
std::unordered_set<IrValue*> path;
|
||||
if (!FirstInvocationOnly(access.predicate, evaluator, path)) Fail("per-patch tessellation output is not written by control point 0 alone", access.pc);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user