mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
Implement vertex swizzle
This commit is contained in:
@@ -5700,24 +5700,24 @@ TestCase VectorVop3FloatCompareNegSourceModifier() {
|
||||
{O::VMovB32, O::VCmpLtF32, O::BufferStoreDword, O::SEndpgm}};
|
||||
}
|
||||
|
||||
TestCase VectorVop3CmpxWritesExecMask() {
|
||||
TestCase VectorVop3CmpxWritesScalarDstAndExecMask() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
std::vector<u32> code;
|
||||
AppendVMovU32(&code, 0, 2);
|
||||
AppendVMovU32(&code, 1, 1);
|
||||
AppendVMovU32(&code, 2, 0);
|
||||
AppendVMovU32(&code, 30, 0);
|
||||
AppendVop3(&code, 0xd1, 5, Vgpr(0), Vgpr(1)); // v_cmpx_lt_u32, false
|
||||
AppendVMovU32(&code, 2, 7);
|
||||
AppendBufferStoreDword(&code, 2, 30);
|
||||
AppendEnd(&code);
|
||||
AppendVMovU32(&code, 0, 1);
|
||||
AppendVMovU32(&code, 1, 1);
|
||||
AppendVMovU32(&code, 2, 7);
|
||||
AppendVMovU32(&code, 30, 0);
|
||||
AppendVop3(&code, 0xd2, 5, Vgpr(0), Vgpr(1)); // v_cmpx_eq_u32 s[5:6], true
|
||||
code.push_back(EncodeSop1(0x0a, 126, 5)); // s_wqm_b64 exec, s[5:6]
|
||||
AppendBufferStoreDword(&code, 2, 30);
|
||||
AppendEnd(&code);
|
||||
|
||||
return {"VectorVop3CmpxWritesExecMask",
|
||||
code,
|
||||
{0},
|
||||
{0},
|
||||
{O::VMovB32, O::VCmpxLtU32, O::BufferStoreDword, O::SEndpgm}};
|
||||
return {"VectorVop3CmpxWritesScalarDstAndExecMask",
|
||||
code,
|
||||
{0},
|
||||
{7},
|
||||
{O::VMovB32, O::VCmpxEqU32, O::SWqmB64, O::BufferStoreDword, O::SEndpgm}};
|
||||
}
|
||||
|
||||
TestCase VectorVopcSdwaCmpxWritesExecMask() {
|
||||
@@ -5741,6 +5741,28 @@ TestCase VectorVopcSdwaCmpxWritesExecMask() {
|
||||
{O::VMovB32, O::VCmpxLtU32, O::BufferStoreDword, O::SEndpgm}};
|
||||
}
|
||||
|
||||
TestCase VectorVopcCmpxPreservesVccForWqm() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
std::vector<u32> code;
|
||||
AppendVMovU32(&code, 0, 1);
|
||||
AppendVMovU32(&code, 1, 1);
|
||||
AppendVMovU32(&code, 2, 7);
|
||||
AppendVMovU32(&code, 30, 0);
|
||||
code.push_back(EncodeSop1(0x04, 106, InlineU32(0))); // s_mov_b64 vcc, 0
|
||||
code.push_back(EncodeVopc(0xd2, Vgpr(0), 1)); // v_cmpx_eq_u32, true
|
||||
code.push_back(EncodeSop1(0x0a, 126, 106)); // s_wqm_b64 exec, vcc
|
||||
AppendBufferStoreDword(&code, 2, 30);
|
||||
AppendEnd(&code);
|
||||
|
||||
return {"VectorVopcCmpxPreservesVccForWqm",
|
||||
code,
|
||||
{0},
|
||||
{7},
|
||||
{O::VMovB32, O::SMovB64, O::VCmpxEqU32, O::SWqmB64,
|
||||
O::BufferStoreDword, O::SEndpgm}};
|
||||
}
|
||||
|
||||
TestCase VectorCompareInvertedMaskSelect() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -8638,8 +8660,9 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(Vop3CndmaskAllowsDataSourceModifier);
|
||||
AddCase(VectorCompareExecOps);
|
||||
AddCase(VectorVop3FloatCompareNegSourceModifier);
|
||||
AddCase(VectorVop3CmpxWritesExecMask);
|
||||
AddCase(VectorVop3CmpxWritesScalarDstAndExecMask);
|
||||
AddCase(VectorVopcSdwaCmpxWritesExecMask);
|
||||
AddCase(VectorVopcCmpxPreservesVccForWqm);
|
||||
AddCase(VectorCompareInvertedMaskSelect);
|
||||
AddCase(BranchSelect);
|
||||
AddCase(SimpleLoop);
|
||||
|
||||
@@ -9,85 +9,122 @@ namespace {
|
||||
|
||||
using namespace Libs::Graphics;
|
||||
|
||||
void Check(bool value, const char* text) {
|
||||
if (!value) {
|
||||
std::fprintf(stderr, "ShaderVertexMetadataTests: failed: %s\n", text);
|
||||
std::abort();
|
||||
}
|
||||
void Check(bool value, const char *text) {
|
||||
if (!value) {
|
||||
std::fprintf(stderr, "ShaderVertexMetadataTests: failed: %s\n", text);
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
struct Fixture {
|
||||
std::array<uint16_t, static_cast<size_t>(AgcDirectResourceType::Last) + 1> offsets {};
|
||||
ShaderUserData user_data {};
|
||||
ShaderSemantic semantic {};
|
||||
ShaderMappedData mapped {};
|
||||
std::array<uint16_t, static_cast<size_t>(AgcDirectResourceType::Last) + 1>
|
||||
offsets{};
|
||||
ShaderUserData user_data{};
|
||||
ShaderSemantic semantic{};
|
||||
ShaderMappedData mapped{};
|
||||
|
||||
Fixture() {
|
||||
offsets.fill(AGC_ILLEGAL_DIRECT_OFFSET);
|
||||
offsets[static_cast<size_t>(AgcDirectResourceType::PtrVertexBufferTable)] = 2;
|
||||
offsets[static_cast<size_t>(AgcDirectResourceType::PtrVertexAttribDescTable)] = 4;
|
||||
user_data.direct_resource_offset = offsets.data();
|
||||
user_data.direct_resource_count = static_cast<uint16_t>(offsets.size());
|
||||
mapped.user_data = &user_data;
|
||||
mapped.input_semantics = &semantic;
|
||||
mapped.num_input_semantics = 1;
|
||||
}
|
||||
Fixture() {
|
||||
offsets.fill(AGC_ILLEGAL_DIRECT_OFFSET);
|
||||
offsets[static_cast<size_t>(AgcDirectResourceType::PtrVertexBufferTable)] =
|
||||
2;
|
||||
offsets[static_cast<size_t>(
|
||||
AgcDirectResourceType::PtrVertexAttribDescTable)] = 4;
|
||||
user_data.direct_resource_offset = offsets.data();
|
||||
user_data.direct_resource_count = static_cast<uint16_t>(offsets.size());
|
||||
mapped.user_data = &user_data;
|
||||
mapped.input_semantics = &semantic;
|
||||
mapped.num_input_semantics = 1;
|
||||
}
|
||||
};
|
||||
|
||||
void CheckRejected(const ShaderMappedData& data, const char* text) {
|
||||
ShaderVertexMetadata output;
|
||||
output.vertex_buffer_reg = 37;
|
||||
output.vertex_attrib_reg = 41;
|
||||
output.input_semantics_count = 7;
|
||||
std::string error;
|
||||
Check(!ShaderReadVertexMetadata(data, 64, &output, &error), text);
|
||||
Check(!error.empty(), "metadata rejection omitted its diagnostic");
|
||||
Check(output.vertex_buffer_reg == 37 && output.vertex_attrib_reg == 41 &&
|
||||
output.input_semantics_count == 7,
|
||||
"metadata rejection changed the prior output");
|
||||
void CheckRejected(const ShaderMappedData &data, const char *text) {
|
||||
ShaderVertexMetadata output;
|
||||
output.vertex_buffer_reg = 37;
|
||||
output.vertex_attrib_reg = 41;
|
||||
output.input_semantics_count = 7;
|
||||
std::string error;
|
||||
Check(!ShaderReadVertexMetadata(data, 64, &output, &error), text);
|
||||
Check(!error.empty(), "metadata rejection omitted its diagnostic");
|
||||
Check(output.vertex_buffer_reg == 37 && output.vertex_attrib_reg == 41 &&
|
||||
output.input_semantics_count == 7,
|
||||
"metadata rejection changed the prior output");
|
||||
}
|
||||
|
||||
void TestValidAndInvalidMetadata() {
|
||||
Fixture fixture;
|
||||
ShaderVertexMetadata output;
|
||||
std::string error;
|
||||
Check(ShaderReadVertexMetadata(fixture.mapped, 64, &output, &error),
|
||||
"valid AGC vertex metadata was rejected");
|
||||
Check(output.vertex_buffer_reg == 2 && output.vertex_attrib_reg == 4 &&
|
||||
output.input_semantics_count == 1,
|
||||
"valid AGC vertex metadata was decoded incorrectly");
|
||||
Fixture fixture;
|
||||
ShaderVertexMetadata output;
|
||||
std::string error;
|
||||
Check(ShaderReadVertexMetadata(fixture.mapped, 64, &output, &error),
|
||||
"valid AGC vertex metadata was rejected");
|
||||
Check(output.vertex_buffer_reg == 2 && output.vertex_attrib_reg == 4 &&
|
||||
output.input_semantics_count == 1,
|
||||
"valid AGC vertex metadata was decoded incorrectly");
|
||||
|
||||
auto missing_header = fixture.mapped;
|
||||
missing_header.user_data = nullptr;
|
||||
CheckRejected(missing_header, "missing AGC user-data header was accepted");
|
||||
auto missing_header = fixture.mapped;
|
||||
missing_header.user_data = nullptr;
|
||||
CheckRejected(missing_header, "missing AGC user-data header was accepted");
|
||||
|
||||
Fixture missing_offsets;
|
||||
missing_offsets.user_data.direct_resource_offset = nullptr;
|
||||
CheckRejected(missing_offsets.mapped, "missing direct-resource offsets were accepted");
|
||||
Fixture missing_offsets;
|
||||
missing_offsets.user_data.direct_resource_offset = nullptr;
|
||||
CheckRejected(missing_offsets.mapped,
|
||||
"missing direct-resource offsets were accepted");
|
||||
|
||||
Fixture excessive_resources;
|
||||
excessive_resources.user_data.direct_resource_count =
|
||||
static_cast<uint16_t>(excessive_resources.offsets.size() + 1);
|
||||
CheckRejected(excessive_resources.mapped, "excessive direct-resource count was accepted");
|
||||
Fixture excessive_resources;
|
||||
excessive_resources.user_data.direct_resource_count =
|
||||
static_cast<uint16_t>(excessive_resources.offsets.size() + 1);
|
||||
CheckRejected(excessive_resources.mapped,
|
||||
"excessive direct-resource count was accepted");
|
||||
|
||||
Fixture excessive_semantics;
|
||||
excessive_semantics.mapped.num_input_semantics = ShaderVertexInputInfo::RES_MAX + 1;
|
||||
CheckRejected(excessive_semantics.mapped, "excessive vertex semantic count was accepted");
|
||||
Fixture excessive_semantics;
|
||||
excessive_semantics.mapped.num_input_semantics =
|
||||
ShaderVertexInputInfo::RES_MAX + 1;
|
||||
CheckRejected(excessive_semantics.mapped,
|
||||
"excessive vertex semantic count was accepted");
|
||||
|
||||
Fixture excessive_register;
|
||||
excessive_register.offsets[
|
||||
static_cast<size_t>(AgcDirectResourceType::PtrVertexBufferTable)] = 63;
|
||||
CheckRejected(excessive_register.mapped, "out-of-domain vertex table SGPR was accepted");
|
||||
Fixture excessive_register;
|
||||
excessive_register.offsets[static_cast<size_t>(
|
||||
AgcDirectResourceType::PtrVertexBufferTable)] = 63;
|
||||
CheckRejected(excessive_register.mapped,
|
||||
"out-of-domain vertex table SGPR was accepted");
|
||||
|
||||
Fixture missing_semantics;
|
||||
missing_semantics.mapped.input_semantics = nullptr;
|
||||
CheckRejected(missing_semantics.mapped, "missing vertex semantic array was accepted");
|
||||
Fixture missing_semantics;
|
||||
missing_semantics.mapped.input_semantics = nullptr;
|
||||
CheckRejected(missing_semantics.mapped,
|
||||
"missing vertex semantic array was accepted");
|
||||
}
|
||||
|
||||
void TestVertexDstSelectors() {
|
||||
const auto zero = DecodeVertexDstSelector(0);
|
||||
const auto one = DecodeVertexDstSelector(1);
|
||||
Check(zero.kind == VertexDstSelectKind::Zero &&
|
||||
one.kind == VertexDstSelectKind::One,
|
||||
"vertex constant selectors were decoded incorrectly");
|
||||
for (uint8_t selector = 4; selector <= 7; selector++) {
|
||||
const auto component = DecodeVertexDstSelector(selector);
|
||||
Check(component.kind == VertexDstSelectKind::Component &&
|
||||
component.source_component == selector - 4,
|
||||
"vertex component selector was decoded incorrectly");
|
||||
}
|
||||
Check(DecodeVertexDstSelector(2).kind == VertexDstSelectKind::Reserved &&
|
||||
DecodeVertexDstSelector(3).kind == VertexDstSelectKind::Reserved,
|
||||
"reserved vertex selectors were accepted");
|
||||
Check(GetDstSel(DstSel(6, 5, 4, 7), 0) == 6 &&
|
||||
GetDstSel(DstSel(6, 5, 4, 7), 1) == 5 &&
|
||||
GetDstSel(DstSel(6, 5, 4, 7), 2) == 4 &&
|
||||
GetDstSel(DstSel(6, 5, 4, 7), 3) == 7,
|
||||
"BGRA vertex selector packing was decoded incorrectly");
|
||||
Check(VertexRawComponentCount(DstSel(7, 0, 0, 0), 1) == 4,
|
||||
"W-to-X did not widen the raw vertex interface to four components");
|
||||
Check(VertexRawComponentCount(DstSel(4, 4, 4, 4), 4) == 4 &&
|
||||
VertexRawComponentCount(DstSel(4, 0, 0, 1), 4) == 4,
|
||||
"replication or constant selectors changed raw vertex width");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
TestValidAndInvalidMetadata();
|
||||
std::puts("ShaderVertexMetadataTests: all cases passed");
|
||||
return 0;
|
||||
TestValidAndInvalidMetadata();
|
||||
TestVertexDstSelectors();
|
||||
std::puts("ShaderVertexMetadataTests: all cases passed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
+20
-15
@@ -1473,9 +1473,11 @@ void TestNewShaderRecompilerMoreAluFamilies() {
|
||||
"new decoder did not decode old-backed V_CMP_NEQ_F32");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_cmp_neq_f32 s0, 0.500000, v1"),
|
||||
"new decoder did not decode old-backed V_CMP_NEQ_F32 SDWA scalar destination");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_cmpx_lt_u32 exec_lo, v5.sdwa(sel=4") &&
|
||||
Common::ContainsStr(result.ir_dump, "CompareMaskLtU32 exec_lo"),
|
||||
"new decoder did not route V_CMPX SDWA destination to exec");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_cmpx_lt_u32 vcc_lo, v5.sdwa(sel=4") &&
|
||||
Common::ContainsStr(result.ir_dump, "CompareMaskLtU32 vcc_lo") &&
|
||||
Common::ContainsStr(result.ir_dump, "MoveU32 exec_lo, vcc_lo") &&
|
||||
Common::ContainsStr(result.ir_dump, "MoveU32 exec_hi, vcc_hi"),
|
||||
"new decoder did not preserve V_CMPX SDWA destination and mirror its mask to exec");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_cmp_nlt_f32"),
|
||||
"new decoder did not decode old-backed V_CMP_NLT_F32");
|
||||
Check(Common::ContainsStr(result.decoded_dump, "v_cmpx_nge_f32"),
|
||||
@@ -1774,10 +1776,12 @@ void TestNewShaderRecompilerMoreAluFamilies() {
|
||||
"VOP3-encoded VOP1 find-first-bit-low did not lower through shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareGtF32"),
|
||||
"VOPC float compare did not lower to IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskGtF32 exec_lo"),
|
||||
"VOPC float compare-and-mask did not lower to exec mask IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskGtU32 exec_lo"),
|
||||
"VOPC uint compare-and-mask did not lower to exec mask IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskGtF32 vcc_lo") &&
|
||||
Common::ContainsStr(result.ir_dump, "MoveU32 exec_lo, vcc_lo"),
|
||||
"VOPC float compare-and-mask did not lower to VCC plus EXEC IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskGtU32 vcc_lo") &&
|
||||
Common::ContainsStr(result.ir_dump, "MoveU32 exec_hi, vcc_hi"),
|
||||
"VOPC uint compare-and-mask did not lower to VCC plus EXEC IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareFalse vcc_lo, v6, v6"),
|
||||
"VOPC false compare did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareTrue vcc_lo, v6, v6"),
|
||||
@@ -1800,17 +1804,17 @@ void TestNewShaderRecompilerMoreAluFamilies() {
|
||||
"VOPC SDWA unordered-not-equal compare did not lower to scalar-destination IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareUnordGeF32 vcc_lo, v6, v6"),
|
||||
"VOPC unordered-greater-equal compare did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordLtF32 exec_lo, v6, v6"),
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordLtF32 vcc_lo, v6, v6"),
|
||||
"VOPC unordered-less compare-and-mask did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordEqF32 exec_lo, v6, v6"),
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordEqF32 vcc_lo, v6, v6"),
|
||||
"VOPC unordered-equal compare-and-mask did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordLeF32 exec_lo, v6, v6"),
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordLeF32 vcc_lo, v6, v6"),
|
||||
"VOPC unordered-less-equal compare-and-mask did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordGtF32 exec_lo, v6, v6"),
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordGtF32 vcc_lo, v6, v6"),
|
||||
"VOPC unordered-greater compare-and-mask did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordNeF32 exec_lo, v6, v6"),
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordNeF32 vcc_lo, v6, v6"),
|
||||
"VOPC unordered-not-equal compare-and-mask did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordGeF32 exec_lo, v6, v6"),
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskUnordGeF32 vcc_lo, v6, v6"),
|
||||
"VOPC unordered-greater-equal compare-and-mask did not lower to shared IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareFalse vcc_lo, v5, v5"),
|
||||
"VOPC integer false compare did not lower to shared IR");
|
||||
@@ -2687,8 +2691,9 @@ void TestNewShaderRecompilerSignedCompareAlu() {
|
||||
"signed halfword greater-or-equal compare did not lower to IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareLtU16"),
|
||||
"unsigned halfword less-than compare did not lower to IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskGtI32 exec_lo"),
|
||||
"signed compare-and-mask did not lower to exec mask IR");
|
||||
Check(Common::ContainsStr(result.ir_dump, "CompareMaskGtI32 vcc_lo") &&
|
||||
Common::ContainsStr(result.ir_dump, "MoveU32 exec_lo, vcc_lo"),
|
||||
"signed compare-and-mask did not lower to VCC plus EXEC IR");
|
||||
Check(SpirvContainsOpcode(result.spirv, 173), "SPIR-V binary does not contain OpSGreaterThan");
|
||||
Check(SpirvContainsOpcode(result.spirv, 177), "SPIR-V binary does not contain OpSLessThan");
|
||||
Check(SpirvContainsOpcode(result.spirv, 202),
|
||||
|
||||
Reference in New Issue
Block a user