mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-26 12:56:54 +01:00
shader: compare real nested descriptor pointer instructions
This commit is contained in:
@@ -21,6 +21,7 @@ class Value {
|
|||||||
public:
|
public:
|
||||||
Value() = default;
|
Value() = default;
|
||||||
explicit Value(Inst* value);
|
explicit Value(Inst* value);
|
||||||
|
explicit Value(const Inst* value) = delete;
|
||||||
explicit Value(ScalarReg value);
|
explicit Value(ScalarReg value);
|
||||||
explicit Value(VectorReg value);
|
explicit Value(VectorReg value);
|
||||||
explicit Value(bool value);
|
explicit Value(bool value);
|
||||||
|
|||||||
@@ -2768,7 +2768,7 @@ private:
|
|||||||
IndirectDescriptorPlan& plan) {
|
IndirectDescriptorPlan& plan) {
|
||||||
if (handle.GetOpcode() != ValueOpcode::GetImageResource &&
|
if (handle.GetOpcode() != ValueOpcode::GetImageResource &&
|
||||||
handle.GetOpcode() != ValueOpcode::GetSamplerResource) return false;
|
handle.GetOpcode() != ValueOpcode::GetSamplerResource) return false;
|
||||||
const Inst* pointer = nullptr;
|
Inst* pointer = nullptr;
|
||||||
uint32_t descriptor_offset = 0;
|
uint32_t descriptor_offset = 0;
|
||||||
for (uint32_t word = 0; word < handle.NumArgs(); ++word) {
|
for (uint32_t word = 0; word < handle.NumArgs(); ++word) {
|
||||||
const auto* read = descriptor.dwords[word].Resolve().TryInstruction();
|
const auto* read = descriptor.dwords[word].Resolve().TryInstruction();
|
||||||
@@ -2777,7 +2777,7 @@ private:
|
|||||||
if (memory == nullptr || memory->kind != ResourceKind::ScalarAddress ||
|
if (memory == nullptr || memory->kind != ResourceKind::ScalarAddress ||
|
||||||
memory->offset > INT32_MAX || !ImmediateU32(read->Arg(1), offset) ||
|
memory->offset > INT32_MAX || !ImmediateU32(read->Arg(1), offset) ||
|
||||||
!AvailableBefore(*read, handle)) return false;
|
!AvailableBefore(*read, handle)) return false;
|
||||||
const auto* address = read->Arg(0).Resolve().TryInstruction();
|
auto* address = read->Arg(0).Resolve().TryInstruction();
|
||||||
const uint64_t current_offset = uint64_t {offset & ~3u} + (memory->offset & ~3u);
|
const uint64_t current_offset = uint64_t {offset & ~3u} + (memory->offset & ~3u);
|
||||||
if (address == nullptr || address->GetOpcode() != ValueOpcode::GetAddressResource ||
|
if (address == nullptr || address->GetOpcode() != ValueOpcode::GetAddressResource ||
|
||||||
address->NumArgs() != 2u || current_offset > UINT32_MAX ||
|
address->NumArgs() != 2u || current_offset > UINT32_MAX ||
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -25,6 +26,10 @@ using Libs::Graphics::ShaderComputeInputInfo;
|
|||||||
using Libs::Graphics::ShaderType;
|
using Libs::Graphics::ShaderType;
|
||||||
namespace Decoder = Libs::Graphics::ShaderRecompiler::Decoder;
|
namespace Decoder = Libs::Graphics::ShaderRecompiler::Decoder;
|
||||||
|
|
||||||
|
static_assert(std::is_constructible_v<Value, Inst*> &&
|
||||||
|
std::is_constructible_v<Value, bool> &&
|
||||||
|
!std::is_constructible_v<Value, const Inst*>);
|
||||||
|
|
||||||
void Check(bool condition, const char *message) {
|
void Check(bool condition, const char *message) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw std::runtime_error(message);
|
throw std::runtime_error(message);
|
||||||
@@ -692,7 +697,8 @@ void TestWaterfallImageTable() {
|
|||||||
|
|
||||||
void TestNestedPointerImageTable() {
|
void TestNestedPointerImageTable() {
|
||||||
namespace CFG = Libs::Graphics::ShaderRecompiler::CFG;
|
namespace CFG = Libs::Graphics::ShaderRecompiler::CFG;
|
||||||
const auto make = [](uint32_t variant = 0u) {
|
enum class Address { Shared, Equivalent, ImageMismatch, SamplerMismatch };
|
||||||
|
const auto make = [](uint32_t variant = 0u, Address choice = Address::Shared) {
|
||||||
auto fixture = std::make_unique<Fixture>();
|
auto fixture = std::make_unique<Fixture>();
|
||||||
std::array<Value, 4> table_words, key_words;
|
std::array<Value, 4> table_words, key_words;
|
||||||
for (uint32_t word = 0; word < 4u; ++word) {
|
for (uint32_t word = 0; word < 4u; ++word) {
|
||||||
@@ -749,6 +755,19 @@ void TestNestedPointerImageTable() {
|
|||||||
fixture->AddMemory(memory, 0x1f4u));
|
fixture->AddMemory(memory, 0x1f4u));
|
||||||
}
|
}
|
||||||
const auto address = fixture->Address(pointer[0], pointer[1]);
|
const auto address = fixture->Address(pointer[0], pointer[1]);
|
||||||
|
auto other_address = address;
|
||||||
|
if (choice == Address::Equivalent) {
|
||||||
|
other_address = fixture->Address(pointer[0], pointer[1]);
|
||||||
|
} else if (choice != Address::Shared) {
|
||||||
|
for (uint32_t word = 0; word < 2u; ++word) {
|
||||||
|
MemoryInfo memory;
|
||||||
|
memory.kind = ResourceKind::ScalarBuffer;
|
||||||
|
memory.offset = 8u + word * 4u;
|
||||||
|
pointer[word] = fixture->Emit(ValueOpcode::ReadConstBuffer, {table, offset},
|
||||||
|
fixture->AddMemory(memory, 0x1fcu));
|
||||||
|
}
|
||||||
|
other_address = fixture->Address(pointer[0], pointer[1]);
|
||||||
|
}
|
||||||
const auto load = [&](uint32_t first, uint32_t width) {
|
const auto load = [&](uint32_t first, uint32_t width) {
|
||||||
if (width == 8u && variant >= 7u && variant <= 9u)
|
if (width == 8u && variant >= 7u && variant <= 9u)
|
||||||
first = variant == 7u ? 0x4000u : variant == 8u ? 0x3ff0u : 0x3fe0u;
|
first = variant == 7u ? 0x4000u : variant == 8u ? 0x3ff0u : 0x3fe0u;
|
||||||
@@ -759,8 +778,12 @@ void TestNestedPointerImageTable() {
|
|||||||
memory.kind = ResourceKind::ScalarAddress;
|
memory.kind = ResourceKind::ScalarAddress;
|
||||||
memory.offset = first + word * 4u;
|
memory.offset = first + word * 4u;
|
||||||
if (variant == 3u && width == 8u && word == 7u) memory.offset += 4u;
|
if (variant == 3u && width == 8u && word == 7u) memory.offset += 4u;
|
||||||
|
const bool alternate = word == 1u &&
|
||||||
|
(choice == Address::Equivalent ||
|
||||||
|
(choice == Address::ImageMismatch && width == 8u) ||
|
||||||
|
(choice == Address::SamplerMismatch && width == 4u));
|
||||||
words[word] = fixture->Emit(ValueOpcode::LoadAddressU32,
|
words[word] = fixture->Emit(ValueOpcode::LoadAddressU32,
|
||||||
{address, Value(0u), Value(0u), Value(true)},
|
{alternate ? other_address : address, Value(0u), Value(0u), Value(true)},
|
||||||
fixture->AddMemory(memory, first == 0x3d0u ? 0x1110u : 0x1118u));
|
fixture->AddMemory(memory, first == 0x3d0u ? 0x1110u : 0x1118u));
|
||||||
}
|
}
|
||||||
return words;
|
return words;
|
||||||
@@ -820,6 +843,16 @@ void TestNestedPointerImageTable() {
|
|||||||
snapshot.samplers[row + 1u].dwords[0] == row,
|
snapshot.samplers[row + 1u].dwords[0] == row,
|
||||||
"nested pointer table mixed rows or pointee members");
|
"nested pointer table mixed rows or pointee members");
|
||||||
const auto populated = specialization;
|
const auto populated = specialization;
|
||||||
|
auto equivalent = make(0u, Address::Equivalent);
|
||||||
|
equivalent->PlanAndTrack();
|
||||||
|
Check(MaterializeResources(ExtractResourcePlan(equivalent->program), runtime, snapshot, specialization) &&
|
||||||
|
specialization == populated,
|
||||||
|
"equivalent nested pointer address instructions changed descriptor selection");
|
||||||
|
for (const auto choice : {Address::ImageMismatch, Address::SamplerMismatch}) {
|
||||||
|
auto mismatched = make(0u, choice);
|
||||||
|
CheckFatal([&] { mismatched->PlanAndTrack(); }, "not a valid runtime value",
|
||||||
|
"nested pointer planning combined descriptor words from different pointer pairs");
|
||||||
|
}
|
||||||
const auto reads = memory.reads;
|
const auto reads = memory.reads;
|
||||||
user_data[2] = 0u;
|
user_data[2] = 0u;
|
||||||
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
|
|||||||
Reference in New Issue
Block a user