mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge pull request #7880 from klosixgaming-arch/fix/shader-indirect-column-phi-pointer
fix(shader): resolve table column pointers through Phi nodes
This commit is contained in:
2 files changed
+120
-1
No files matched your search
@@ -3455,6 +3455,18 @@ void verifyPointerImageTable() {
|
||||
require(!TableTouched(narrowTable.regions, root + (Palette + 32u) / 4u, 32u) && !TableTouched(narrowTable.regions, root + Committed / 4u, Reserved - Committed), "pointer image table: a record outside the key domain was read");
|
||||
const std::vector<std::pair<std::uint64_t, std::uint64_t>> narrowReads{{base + Palette, 32u}, {base + Palette + 2u * 32u, 32u}, {base + Palette + 255u * 32u, 32u}, {base + Palette + 0x102u * 32u, 32u}};
|
||||
require(narrowSnapshot.readRanges == narrowReads && narrowTable.result->imageTableReadRanges.size() == 1u && narrowTable.result->imageTableReadRanges[0] == narrowReads, "pointer image table: consumed ranges include skipped keys or the key-domain buffer");
|
||||
|
||||
auto phiCode = maskedCode;
|
||||
phiCode.erase(phiCode.begin() + 8, phiCode.begin() + 10);
|
||||
phiCode.insert(phiCode.begin() + 8, {
|
||||
0xbf068010u, 0xbf850003u, 0xf4200444u, 0x20000000u, 0xbf820002u, 0xf4200444u, 0x20000000u
|
||||
});
|
||||
const auto phiRequest = request(phiCode, 0x36000u);
|
||||
const auto phiPlan = GetResourcePlan(phiRequest);
|
||||
require(phiPlan->info.images.size() == 1u && phiPlan->info.images[0].table == 0u, "pointer image table: a pointer read through a phi was not planned as a table");
|
||||
const auto phiTable = CompileTable(phiRequest);
|
||||
require(phiTable.capture->snapshot.tables.tables.at(0).codes == snapshot.codes, "pointer image table: a pointer read through a phi captured different records");
|
||||
|
||||
keys = {};
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
@@ -3858,6 +3870,45 @@ void verifyPointerChainImageTable() {
|
||||
static_cast<void>(ValidateAndOptimizeSpirv(compiled.result->spirv, request.target.vulkanVersion, request.target.spirvVersion));
|
||||
#endif
|
||||
store(links[1].data() + 4u, address(descriptors[1].data()));
|
||||
|
||||
auto phiCode = code;
|
||||
phiCode.erase(phiCode.begin() + 15, phiCode.begin() + 17);
|
||||
phiCode.insert(phiCode.begin() + 15, {
|
||||
0xbf068010u, 0xbf850003u, 0xf4240b02u, 0x24000008u, 0xbf820002u, 0xf4240b02u, 0x24000008u
|
||||
});
|
||||
auto phiRequest = TableRequest(phiCode, userData);
|
||||
phiRequest.shader.codeAddress = 0x38000u;
|
||||
const auto phiPlan = GetResourcePlan(phiRequest);
|
||||
require(phiPlan->info.images.size() == 1u && phiPlan->info.images[0].table == 0u, "pointer chain image table: a pointer read through a phi was not planned as a table");
|
||||
const auto phiTable = CompileTable(phiRequest);
|
||||
require(phiTable.capture->snapshot.tables.tables.at(0).codes == snapshot.codes, "pointer chain image table: a pointer read through a phi captured different records");
|
||||
|
||||
auto divergentCode = code;
|
||||
divergentCode.erase(divergentCode.begin() + 15, divergentCode.begin() + 17);
|
||||
divergentCode.insert(divergentCode.begin() + 15, {
|
||||
0xbf068010u, 0xbf850003u, 0xf4240b02u, 0x24000008u, 0xbf820002u, 0xf4240b02u, 0x24000018u
|
||||
});
|
||||
auto divergentRequest = TableRequest(divergentCode, userData);
|
||||
divergentRequest.shader.codeAddress = 0x39000u;
|
||||
expectFailure([&] { static_cast<void>(GetResourcePlan(divergentRequest)); }, "GetImageResource dword 0 is not a valid runtime value", "pointer chain image table: a phi reading different table offsets was planned as a table");
|
||||
|
||||
auto nonTableCode = code;
|
||||
nonTableCode.erase(nonTableCode.begin() + 15, nonTableCode.begin() + 17);
|
||||
nonTableCode.insert(nonTableCode.begin() + 15, {
|
||||
0xbf068010u, 0xbf850003u, 0xf4240b02u, 0x24000008u, 0xbf820002u, 0xbe960380u, 0xbe970380u
|
||||
});
|
||||
auto nonTableRequest = TableRequest(nonTableCode, userData);
|
||||
nonTableRequest.shader.codeAddress = 0x3a000u;
|
||||
expectFailure([&] { static_cast<void>(GetResourcePlan(nonTableRequest)); }, "GetImageResource dword 0 is not a valid runtime value", "pointer chain image table: a phi with a non-table branch was planned as a table");
|
||||
|
||||
auto armOffsetCode = code;
|
||||
armOffsetCode.erase(armOffsetCode.begin() + 14, armOffsetCode.begin() + 17);
|
||||
armOffsetCode.insert(armOffsetCode.begin() + 14, {
|
||||
0xbf068010u, 0xbf850004u, 0x8f128411u, 0xf4240b02u, 0x24000008u, 0xbf820003u, 0x8f128411u, 0xf4240b02u, 0x24000008u
|
||||
});
|
||||
auto armOffsetRequest = TableRequest(armOffsetCode, userData);
|
||||
armOffsetRequest.shader.codeAddress = 0x3b000u;
|
||||
expectFailure([&] { static_cast<void>(GetResourcePlan(armOffsetRequest)); }, "GetImageResource dword 0 is not a valid runtime value", "pointer chain image table: a phi whose arms compute their own table offset was planned as a table");
|
||||
}
|
||||
|
||||
void verifyWaterfallImageTable() {
|
||||
|
||||
@@ -751,6 +751,68 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
IrValue* UnwrapTableRead(IrValue* value) const {
|
||||
if (value == nullptr) return nullptr;
|
||||
value = value->Resolve();
|
||||
if (!value->IsPhi()) return value;
|
||||
IrValue* candidate = nullptr;
|
||||
std::vector<IrValue*> pending{value};
|
||||
std::unordered_set<const IrValue*> visited;
|
||||
while (!pending.empty()) {
|
||||
auto* current = pending.back()->Resolve();
|
||||
pending.pop_back();
|
||||
if (!visited.insert(current).second) continue;
|
||||
if (current->IsPhi()) {
|
||||
for (std::size_t i = 0; i < current->ArgumentCount(); i++) {
|
||||
pending.push_back(current->Argument(i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
std::uint32_t memoryIndex = 0;
|
||||
IrValue* key = nullptr;
|
||||
std::uint32_t stride = 0;
|
||||
std::uint32_t addend = 0;
|
||||
if (ScalarReadMemory(*current, memoryIndex) == nullptr || !MemoryIndexBelongsTo(memoryIndex, *current) ||
|
||||
!MatchAffineOffset(current->Argument(1), key, stride, addend)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (candidate == nullptr) {
|
||||
candidate = current;
|
||||
} else if (!EquivalentValue(m_program.Resources(), candidate, current)) {
|
||||
std::uint32_t candidateIndex = 0;
|
||||
const auto* candMem = ScalarReadMemory(*candidate, candidateIndex);
|
||||
const auto* curMem = ScalarReadMemory(*current, memoryIndex);
|
||||
if (candMem == nullptr || curMem == nullptr || candMem->offset != curMem->offset ||
|
||||
!EquivalentValue(m_program.Resources(), candidate->Argument(0), current->Argument(0)) ||
|
||||
!EquivalentValue(m_program.Resources(), candidate->Argument(1), current->Argument(1))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
bool BlockDominates(const IrBlock* dominator, const IrBlock* block) const {
|
||||
if (dominator == block) return true;
|
||||
std::vector<const IrBlock*> pending{block};
|
||||
std::unordered_set<const IrBlock*> visited{block};
|
||||
while (!pending.empty()) {
|
||||
const IrBlock* current = pending.back();
|
||||
pending.pop_back();
|
||||
if (current->Predecessors().empty()) return false;
|
||||
for (const IrBlock* predecessor : current->Predecessors()) {
|
||||
if (predecessor != dominator && visited.insert(predecessor).second) pending.push_back(predecessor);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AvailableAt(IrValue* value, const IrBlock* block) const {
|
||||
value = value->Resolve();
|
||||
if (value->HasImmediate() || value->Parent() == nullptr) return true;
|
||||
return BlockDominates(value->Parent(), block);
|
||||
}
|
||||
|
||||
bool TryMakeIndirectColumn(IrValue& handle, IrValue& descriptorPointer, bool sampler, std::uint32_t words, std::uint32_t descriptorOffset, std::uint32_t descriptorImmediate, TableColumnPlan& plan) {
|
||||
std::vector<PointerHop> hops;
|
||||
IrValue* pointer = &descriptorPointer;
|
||||
@@ -788,7 +850,10 @@ private:
|
||||
IrValue* offset = nullptr;
|
||||
std::uint32_t first = 0;
|
||||
for (std::uint32_t dword = 0; dword < 2u; dword++) {
|
||||
IrValue* read = pointer->Argument(dword)->Resolve();
|
||||
IrValue* read = UnwrapTableRead(pointer->Argument(dword));
|
||||
if (read == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::uint32_t memoryIndex = 0;
|
||||
const MemoryInfo* memory = ScalarReadMemory(*read, memoryIndex);
|
||||
if (memory == nullptr || !MemoryIndexBelongsTo(memoryIndex, *read)) {
|
||||
@@ -802,6 +867,9 @@ private:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!AvailableAt(offset, handle.Parent())) {
|
||||
return false;
|
||||
}
|
||||
IrValue* key = nullptr;
|
||||
std::uint32_t stride = 0;
|
||||
std::uint32_t addend = 0;
|
||||
|
||||
Reference in new issue
Block a user