mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
Preserve shared scalar loads during embedded vertex fetch replacement
This commit is contained in:
@@ -87,7 +87,6 @@ struct EmbeddedFetchSgprInfo {
|
|||||||
EmbeddedFetchValueType type = EmbeddedFetchValueType::Unknown;
|
EmbeddedFetchValueType type = EmbeddedFetchValueType::Unknown;
|
||||||
int attrib_id = 0;
|
int attrib_id = 0;
|
||||||
uint32_t value = 0;
|
uint32_t value = 0;
|
||||||
std::vector<uint32_t> prolog_loads;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using EmbeddedFetchVectorLanes = std::map<uint64_t, EmbeddedFetchSgprInfo>;
|
using EmbeddedFetchVectorLanes = std::map<uint64_t, EmbeddedFetchSgprInfo>;
|
||||||
@@ -326,7 +325,6 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
auto& dst = sgprs[DecodedSgprReg(inst.dst)];
|
auto& dst = sgprs[DecodedSgprReg(inst.dst)];
|
||||||
dst.type = EmbeddedFetchValueType::Constant;
|
dst.type = EmbeddedFetchValueType::Constant;
|
||||||
dst.value = value;
|
dst.value = value;
|
||||||
dst.prolog_loads.clear();
|
|
||||||
} else {
|
} else {
|
||||||
ClearEmbeddedFetchSgprs(sgprs, inst.dst, 1);
|
ClearEmbeddedFetchSgprs(sgprs, inst.dst, 1);
|
||||||
}
|
}
|
||||||
@@ -337,7 +335,6 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
auto& dst = sgprs[DecodedSgprReg(inst.dst)];
|
auto& dst = sgprs[DecodedSgprReg(inst.dst)];
|
||||||
dst.type = EmbeddedFetchValueType::Constant;
|
dst.type = EmbeddedFetchValueType::Constant;
|
||||||
dst.value = inst.src0.value;
|
dst.value = inst.src0.value;
|
||||||
dst.prolog_loads.clear();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -354,7 +351,6 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
auto& dst = sgprs[register_id + i];
|
auto& dst = sgprs[register_id + i];
|
||||||
dst.type = EmbeddedFetchValueType::Attrib;
|
dst.type = EmbeddedFetchValueType::Attrib;
|
||||||
dst.attrib_id = index + static_cast<int>(i);
|
dst.attrib_id = index + static_cast<int>(i);
|
||||||
dst.prolog_loads = {inst.pc};
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ClearEmbeddedFetchSgprs(sgprs, inst.dst, DecodedDstSize(inst));
|
ClearEmbeddedFetchSgprs(sgprs, inst.dst, DecodedDstSize(inst));
|
||||||
@@ -372,7 +368,6 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
dst.type = EmbeddedFetchValueType::Buffer;
|
dst.type = EmbeddedFetchValueType::Buffer;
|
||||||
dst.attrib_id =
|
dst.attrib_id =
|
||||||
BufferTableAttribFromOffset(raw_offset, static_cast<int>(i));
|
BufferTableAttribFromOffset(raw_offset, static_cast<int>(i));
|
||||||
dst.prolog_loads = {inst.pc};
|
|
||||||
}
|
}
|
||||||
} else if (IsDecodedSgpr(inst.src1) &&
|
} else if (IsDecodedSgpr(inst.src1) &&
|
||||||
DecodedSgprReg(inst.src1) < sgprs.size() &&
|
DecodedSgprReg(inst.src1) < sgprs.size() &&
|
||||||
@@ -384,8 +379,6 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
auto& dst = sgprs[register_id + i];
|
auto& dst = sgprs[register_id + i];
|
||||||
dst.type = EmbeddedFetchValueType::Buffer;
|
dst.type = EmbeddedFetchValueType::Buffer;
|
||||||
dst.attrib_id = sgprs[DecodedSgprReg(inst.src1)].attrib_id;
|
dst.attrib_id = sgprs[DecodedSgprReg(inst.src1)].attrib_id;
|
||||||
dst.prolog_loads = sgprs[DecodedSgprReg(inst.src1)].prolog_loads;
|
|
||||||
dst.prolog_loads.push_back(inst.pc);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ClearEmbeddedFetchSgprs(sgprs, inst.dst, DecodedDstSize(inst));
|
ClearEmbeddedFetchSgprs(sgprs, inst.dst, DecodedDstSize(inst));
|
||||||
@@ -424,7 +417,6 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
break;
|
break;
|
||||||
default: dst.value = src0 + src1; break;
|
default: dst.value = src0 + src1; break;
|
||||||
}
|
}
|
||||||
dst.prolog_loads.clear();
|
|
||||||
} else {
|
} else {
|
||||||
ClearEmbeddedFetchSgprs(sgprs, inst.dst, 1);
|
ClearEmbeddedFetchSgprs(sgprs, inst.dst, 1);
|
||||||
}
|
}
|
||||||
@@ -447,7 +439,6 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
load.pc = inst.pc;
|
load.pc = inst.pc;
|
||||||
load.attrib_id = buffer.attrib_id;
|
load.attrib_id = buffer.attrib_id;
|
||||||
load.components = DecodedDstSize(inst);
|
load.components = DecodedDstSize(inst);
|
||||||
load.prolog_loads = buffer.prolog_loads;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -789,15 +789,6 @@ const EmbeddedFetchLoad* FindEmbeddedFetchLoad(const EmbeddedFetchPlan* plan, ui
|
|||||||
return found != plan->loads.end() ? &*found : nullptr;
|
return found != plan->loads.end() ? &*found : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsEmbeddedFetchPrologLoad(const EmbeddedFetchPlan* plan, uint32_t pc) {
|
|
||||||
if (plan == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return std::ranges::any_of(plan->loads, [pc](const auto& load) {
|
|
||||||
return std::ranges::find(load.prolog_loads, pc) != load.prolog_loads.end();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
int ResolveEmbeddedFetchResource(const ShaderVertexInputInfo& input,
|
int ResolveEmbeddedFetchResource(const ShaderVertexInputInfo& input,
|
||||||
const EmbeddedFetchLoad& load) {
|
const EmbeddedFetchLoad& load) {
|
||||||
if (load.attrib_id >= 0 && load.attrib_id < input.resources_num &&
|
if (load.attrib_id >= 0 && load.attrib_id < input.resources_num &&
|
||||||
@@ -819,22 +810,6 @@ int ResolveEmbeddedFetchResource(const ShaderVertexInputInfo& input,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsScalarMemoryLoad(Decoder::Opcode opcode) {
|
|
||||||
switch (opcode) {
|
|
||||||
case Decoder::Opcode::S_LOAD_DWORD:
|
|
||||||
case Decoder::Opcode::S_LOAD_DWORDX2:
|
|
||||||
case Decoder::Opcode::S_LOAD_DWORDX4:
|
|
||||||
case Decoder::Opcode::S_LOAD_DWORDX8:
|
|
||||||
case Decoder::Opcode::S_LOAD_DWORDX16:
|
|
||||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORD:
|
|
||||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORDX2:
|
|
||||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORDX4:
|
|
||||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORDX8:
|
|
||||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORDX16: return true;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsBufferDwordLoad(Decoder::Opcode opcode) {
|
bool IsBufferDwordLoad(Decoder::Opcode opcode) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case Decoder::Opcode::BUFFER_LOAD_DWORD:
|
case Decoder::Opcode::BUFFER_LOAD_DWORD:
|
||||||
@@ -1258,10 +1233,6 @@ IR::Program TranslateProgram(const Decoder::Program& decoded, const CFG::Graph&
|
|||||||
if (IsCodeTableLoad(cfg, instruction.pc)) {
|
if (IsCodeTableLoad(cfg, instruction.pc)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (IsScalarMemoryLoad(instruction.opcode) &&
|
|
||||||
IsEmbeddedFetchPrologLoad(options.embedded_fetch, instruction.pc)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto* embedded = FindEmbeddedFetchLoad(options.embedded_fetch, instruction.pc);
|
const auto* embedded = FindEmbeddedFetchLoad(options.embedded_fetch, instruction.pc);
|
||||||
if (embedded != nullptr && IsBufferDwordLoad(instruction.opcode) &&
|
if (embedded != nullptr && IsBufferDwordLoad(instruction.opcode) &&
|
||||||
instruction.data_dwords == embedded->components &&
|
instruction.data_dwords == embedded->components &&
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ struct EmbeddedFetchLoad {
|
|||||||
uint32_t pc = 0;
|
uint32_t pc = 0;
|
||||||
int attrib_id = -1;
|
int attrib_id = -1;
|
||||||
uint32_t components = 0;
|
uint32_t components = 0;
|
||||||
std::vector<uint32_t> prolog_loads;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmbeddedFetchPlan {
|
struct EmbeddedFetchPlan {
|
||||||
|
|||||||
@@ -9561,6 +9561,54 @@ void TestMergedShaderUserDataSnapshot() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestEmbeddedFetchPreservesSharedScalarLoad() {
|
||||||
|
using namespace ShaderRecompiler;
|
||||||
|
const uint32_t code[] = {
|
||||||
|
EncodeSMovB32(5, 255), 0x47f,
|
||||||
|
EncodeSmem0(0x03, 0, 11), (125u << 25u) | 4u, // s_load_dwordx8 s[0:7], s[22:23], 4
|
||||||
|
EncodeSop2(0x1e, 9, 0, 132), // s_lshl_b32 s9, s0, 4
|
||||||
|
EncodeSop2(0x0e, 9, 9, 255), 0x1f0,
|
||||||
|
EncodeSmem0(0x02, 24, 10), 9u << 25u,
|
||||||
|
EncodeVop2(0x01, 0, 256 + 8, 5), // vertex/instance index selection
|
||||||
|
EncodeMubuf0(0x02), EncodeMubuf1(9, 6, 0), // replaced vertex fetch
|
||||||
|
EncodeSop2(0x1e, 9, 5, 132), // another component of the same scalar load
|
||||||
|
EncodeSop2(0x0e, 9, 9, 255), 0x1f0,
|
||||||
|
EncodeSmem0(0x02, 28, 10), 9u << 25u,
|
||||||
|
EncodeMubuf0(0x0c), EncodeMubuf1(12, 7, 1),
|
||||||
|
EncodeExp0(0x0c, 0xf), EncodeExp1(9, 10, 11, 12), EncodeSopp(0x01),
|
||||||
|
};
|
||||||
|
std::array<std::array<uint32_t, 4>, 32> buffers{};
|
||||||
|
buffers[2] = {0x12340000, 0, 64, 0x00027000};
|
||||||
|
buffers[31] = {0x56780000, 0, 64, 0x00027000};
|
||||||
|
const std::array<uint32_t, 9> attributes = {0, 0, 0, 0, 0, 0, 2, 0, 0};
|
||||||
|
std::array<uint32_t, 16> user_data{};
|
||||||
|
const uint64_t tables[] = {reinterpret_cast<uint64_t>(buffers.data()),
|
||||||
|
reinterpret_cast<uint64_t>(attributes.data())};
|
||||||
|
std::memcpy(user_data.data() + 12, tables, sizeof(tables));
|
||||||
|
ShaderVertexInputInfo input{};
|
||||||
|
input.fetch_embedded = true;
|
||||||
|
input.fetch_buffer_reg = 12;
|
||||||
|
input.fetch_attrib_reg = 14;
|
||||||
|
input.resources_num = 1;
|
||||||
|
input.resources_dst[0].attr_id = 1;
|
||||||
|
input.resources[0].fields[1] = 12u << 16u;
|
||||||
|
input.resources[0].fields[2] = 1;
|
||||||
|
input.resources[0].fields[3] =
|
||||||
|
(static_cast<uint32_t>(Prospero::BufferFormat::k32_32_32Float) << 12u) |
|
||||||
|
DstSel(4, 5, 6, 7);
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Vertex);
|
||||||
|
options.user_data_base = 8;
|
||||||
|
options.user_data = user_data;
|
||||||
|
options.input_info.vertex = &input;
|
||||||
|
auto result = RecompileForTest(code, options);
|
||||||
|
Check(result.program.info.vertex_fetch_components[0] == 3 &&
|
||||||
|
result.resources.buffers.size() == 1 &&
|
||||||
|
std::equal(buffers[2].begin(), buffers[2].end(),
|
||||||
|
result.resources.buffers[0].dwords.begin()),
|
||||||
|
"embedded fetch discarded a scalar-load component used by another buffer read");
|
||||||
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
|
}
|
||||||
|
|
||||||
void TestEmbeddedVertexFormatSwizzle() {
|
void TestEmbeddedVertexFormatSwizzle() {
|
||||||
using namespace ShaderRecompiler;
|
using namespace ShaderRecompiler;
|
||||||
using namespace ShaderRecompiler::IR;
|
using namespace ShaderRecompiler::IR;
|
||||||
@@ -13346,6 +13394,7 @@ int main() {
|
|||||||
TestMeshExportStorage();
|
TestMeshExportStorage();
|
||||||
TestMergedShaderUserDataSnapshot();
|
TestMergedShaderUserDataSnapshot();
|
||||||
TestMeshInputAssembly();
|
TestMeshInputAssembly();
|
||||||
|
TestEmbeddedFetchPreservesSharedScalarLoad();
|
||||||
TestEmbeddedVertexFormatSwizzle();
|
TestEmbeddedVertexFormatSwizzle();
|
||||||
TestNewShaderRecompilerSetpcJumpTable();
|
TestNewShaderRecompilerSetpcJumpTable();
|
||||||
TestNewShaderRecompilerPrunesUnreachableSetpcMetadata();
|
TestNewShaderRecompilerPrunesUnreachableSetpcMetadata();
|
||||||
|
|||||||
Reference in New Issue
Block a user