mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
shader: fix missing homogeneous semantics
This commit is contained in:
@@ -222,8 +222,8 @@ Prospero::BufferFormat BufferFormat(const ValueEmitContext& ctx, const IR::Inst&
|
|||||||
|
|
||||||
IR::MemoryInfo RebaseFormattedComponent(IR::MemoryInfo mem, Prospero::BufferFormat format,
|
IR::MemoryInfo RebaseFormattedComponent(IR::MemoryInfo mem, Prospero::BufferFormat format,
|
||||||
uint32_t component) {
|
uint32_t component) {
|
||||||
if (!mem.typed && component != 0u) {
|
if (!mem.typed) {
|
||||||
const auto component_slot = component * 4u;
|
const auto component_slot = mem.component_index * 4u;
|
||||||
mem.offset = mem.offset >= component_slot ? mem.offset - component_slot : 0u;
|
mem.offset = mem.offset >= component_slot ? mem.offset - component_slot : 0u;
|
||||||
mem.offset += Format::GetFormatComponentByteOffset(format, component);
|
mem.offset += Format::GetFormatComponentByteOffset(format, component);
|
||||||
}
|
}
|
||||||
@@ -234,12 +234,27 @@ uint32_t FormattedLoad(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Me
|
|||||||
const auto format = BufferFormat(ctx, inst, mem);
|
const auto format = BufferFormat(ctx, inst, mem);
|
||||||
if (!Format::IsKnownFormat(format)) return LoadWord(ctx, inst, mem);
|
if (!Format::IsKnownFormat(format)) return LoadWord(ctx, inst, mem);
|
||||||
const auto info = Format::GetFormatInfo(format);
|
const auto info = Format::GetFormatInfo(format);
|
||||||
const auto component = mem.component_index;
|
auto component = mem.component_index;
|
||||||
|
if (!mem.typed) {
|
||||||
|
const auto selector =
|
||||||
|
GetDstSel(ctx.state.program.info.buffers[mem.resource].descriptor_swizzle, component);
|
||||||
|
if (selector == 0u) return ConstantU32(ctx.state, 0);
|
||||||
|
if (selector == 1u) {
|
||||||
|
const auto integer = info.type == Format::ComponentType::Uint ||
|
||||||
|
info.type == Format::ComponentType::Sint;
|
||||||
|
return ConstantU32(ctx.state, integer ? 1u : 0x3f800000u);
|
||||||
|
}
|
||||||
|
if (selector < 4u) {
|
||||||
|
ExitDescriptorBindingFailure(ctx.state, IR::DescriptorBindingKind::Buffers,
|
||||||
|
mem.resource, "buffer descriptor has reserved dst_sel");
|
||||||
|
}
|
||||||
|
component = selector - 4u;
|
||||||
|
}
|
||||||
if (component >= info.component_count) return ConstantU32(ctx.state, 0);
|
if (component >= info.component_count) return ConstantU32(ctx.state, 0);
|
||||||
uint32_t raw = 0;
|
uint32_t raw = 0;
|
||||||
const auto bits = info.component_bits[component];
|
const auto bits = info.component_bits[component];
|
||||||
if (info.packed_bitfield) {
|
if (info.packed_bitfield) {
|
||||||
raw = LoadWord(ctx, inst, mem);
|
raw = LoadWord(ctx, inst, RebaseFormattedComponent(mem, format, component));
|
||||||
const auto type =
|
const auto type =
|
||||||
IsSignedFormatComponent(info.type) ? ctx.state.int_type : ctx.state.uint_type;
|
IsSignedFormatComponent(info.type) ? ctx.state.int_type : ctx.state.uint_type;
|
||||||
const auto source =
|
const auto source =
|
||||||
|
|||||||
@@ -168,17 +168,18 @@ struct DescriptorValue {
|
|||||||
struct BufferResource {
|
struct BufferResource {
|
||||||
static constexpr uint32_t NoImageAlias = UINT32_MAX;
|
static constexpr uint32_t NoImageAlias = UINT32_MAX;
|
||||||
|
|
||||||
uint32_t source = 0;
|
uint32_t source = 0;
|
||||||
uint32_t first_use_pc = 0;
|
uint32_t first_use_pc = 0;
|
||||||
uint32_t max_byte_extent = 0;
|
uint32_t max_byte_extent = 0;
|
||||||
uint32_t packed_stride = 0;
|
uint32_t packed_stride = 0;
|
||||||
Prospero::BufferFormat descriptor_format = Prospero::BufferFormat::kInvalid;
|
Prospero::BufferFormat descriptor_format = Prospero::BufferFormat::kInvalid;
|
||||||
uint32_t image_alias = NoImageAlias;
|
uint32_t descriptor_swizzle = DstSel(4, 5, 6, 7);
|
||||||
bool read = false;
|
uint32_t image_alias = NoImageAlias;
|
||||||
bool written = false;
|
bool read = false;
|
||||||
bool atomic = false;
|
bool written = false;
|
||||||
bool formatted = false;
|
bool atomic = false;
|
||||||
bool scalar = false;
|
bool formatted = false;
|
||||||
|
bool scalar = false;
|
||||||
|
|
||||||
bool operator==(const BufferResource& other) const = default;
|
bool operator==(const BufferResource& other) const = default;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -190,7 +190,8 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (buffer.packed_stride != descriptor.PackedStride() ||
|
if (buffer.packed_stride != descriptor.PackedStride() ||
|
||||||
buffer.descriptor_format != descriptor.Format()) {
|
buffer.descriptor_format != descriptor.Format() ||
|
||||||
|
buffer.descriptor_swizzle != descriptor.DstSelXYZW()) {
|
||||||
if (error != nullptr) {
|
if (error != nullptr) {
|
||||||
*error = fmt::format("buffer descriptor {} no longer matches specialization", i);
|
*error = fmt::format("buffer descriptor {} no longer matches specialization", i);
|
||||||
}
|
}
|
||||||
@@ -392,8 +393,9 @@ bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
next.buffers[i].packed_stride = descriptor.PackedStride();
|
next.buffers[i].packed_stride = descriptor.PackedStride();
|
||||||
next.buffers[i].descriptor_format = descriptor.Format();
|
next.buffers[i].descriptor_format = descriptor.Format();
|
||||||
|
next.buffers[i].descriptor_swizzle = descriptor.DstSelXYZW();
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < next.addresses.size(); i++) {
|
for (uint32_t i = 0; i < next.addresses.size(); i++) {
|
||||||
next.addresses[i].specialized_base =
|
next.addresses[i].specialized_base =
|
||||||
|
|||||||
@@ -1016,8 +1016,9 @@ static std::string ShaderDescribeSpecialization(const ShaderRecompiler::IR::Prog
|
|||||||
program.values != nullptr ? program.values->srt_reads.size() : 0u);
|
program.values != nullptr ? program.values->srt_reads.size() : 0u);
|
||||||
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
||||||
const auto& buffer = program.info.buffers[i];
|
const auto& buffer = program.info.buffers[i];
|
||||||
ret += fmt::format(" b{}[stride={} format={}]", i, buffer.packed_stride,
|
ret +=
|
||||||
static_cast<uint32_t>(buffer.descriptor_format));
|
fmt::format(" b{}[stride={} format={} swizzle=0x{:03x}]", i, buffer.packed_stride,
|
||||||
|
static_cast<uint32_t>(buffer.descriptor_format), buffer.descriptor_swizzle);
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||||
const auto& image = program.info.images[i];
|
const auto& image = program.info.images[i];
|
||||||
@@ -1054,6 +1055,7 @@ static void ShaderAppendNativeSpecialization(std::vector<uint32_t>&
|
|||||||
for (const auto& buffer: program.info.buffers) {
|
for (const auto& buffer: program.info.buffers) {
|
||||||
ids.push_back(buffer.packed_stride);
|
ids.push_back(buffer.packed_stride);
|
||||||
ids.push_back(static_cast<uint32_t>(buffer.descriptor_format));
|
ids.push_back(static_cast<uint32_t>(buffer.descriptor_format));
|
||||||
|
ids.push_back(buffer.descriptor_swizzle);
|
||||||
}
|
}
|
||||||
ids.push_back(static_cast<uint32_t>(program.info.images.size()));
|
ids.push_back(static_cast<uint32_t>(program.info.images.size()));
|
||||||
for (const auto& image: program.info.images) {
|
for (const auto& image: program.info.images) {
|
||||||
|
|||||||
@@ -575,6 +575,42 @@ void TestAddressMaterializationAndSpecialization() {
|
|||||||
"typed address specialization was not applied");
|
"typed address specialization was not applied");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestBufferSwizzleSpecialization() {
|
||||||
|
Fixture fixture;
|
||||||
|
const auto handle = fixture.Buffer(
|
||||||
|
{fixture.UserData(0), fixture.UserData(1), fixture.UserData(2),
|
||||||
|
fixture.UserData(3)},
|
||||||
|
4);
|
||||||
|
MemoryInfo memory;
|
||||||
|
memory.kind = ResourceKind::Buffer;
|
||||||
|
memory.formatted = true;
|
||||||
|
fixture.Emit(ValueOpcode::LoadBufferU32,
|
||||||
|
{handle, Value(0u), Value(0u), Value(0u), Value(true)},
|
||||||
|
fixture.AddMemory(memory, 4));
|
||||||
|
fixture.PlanAndTrack();
|
||||||
|
|
||||||
|
constexpr auto swizzle = Libs::Graphics::DstSel(4, 5, 0, 1);
|
||||||
|
std::array<uint32_t, 4> user_data{
|
||||||
|
0, 16u << 16u, 1,
|
||||||
|
swizzle |
|
||||||
|
(static_cast<uint32_t>(
|
||||||
|
Libs::Graphics::Prospero::BufferFormat::k32_32Float)
|
||||||
|
<< 12u) |
|
||||||
|
(1u << 24u)};
|
||||||
|
SrtRuntime runtime{.user_data = user_data};
|
||||||
|
ResourceSnapshot snapshot;
|
||||||
|
std::string error;
|
||||||
|
Check(MaterializeResources(fixture.program, runtime, snapshot, &error) &&
|
||||||
|
SpecializeResources(fixture.program, snapshot, &error) &&
|
||||||
|
fixture.program.info.buffers[0].descriptor_swizzle == swizzle &&
|
||||||
|
ValidateResourceSpecialization(fixture.program, snapshot, &error),
|
||||||
|
"buffer destination selectors were not specialized");
|
||||||
|
|
||||||
|
snapshot.buffers[0].dwords[3] ^= 1u << 9u;
|
||||||
|
Check(!ValidateResourceSpecialization(fixture.program, snapshot, &error),
|
||||||
|
"buffer swizzle change did not invalidate specialization");
|
||||||
|
}
|
||||||
|
|
||||||
void TestShaderInfoAndBindingLayout() {
|
void TestShaderInfoAndBindingLayout() {
|
||||||
Fixture fixture;
|
Fixture fixture;
|
||||||
const auto handle = fixture.Buffer(
|
const auto handle = fixture.Buffer(
|
||||||
@@ -667,6 +703,7 @@ int main() {
|
|||||||
Run("runtime-rooted loop", TestLoopCycleEnteredThroughRuntimeValue);
|
Run("runtime-rooted loop", TestLoopCycleEnteredThroughRuntimeValue);
|
||||||
Run("invariant loop phi", TestInvariantLoopPhi);
|
Run("invariant loop phi", TestInvariantLoopPhi);
|
||||||
Run("address materialization", TestAddressMaterializationAndSpecialization);
|
Run("address materialization", TestAddressMaterializationAndSpecialization);
|
||||||
|
Run("buffer swizzle specialization", TestBufferSwizzleSpecialization);
|
||||||
Run("shader info and bindings", TestShaderInfoAndBindingLayout);
|
Run("shader info and bindings", TestShaderInfoAndBindingLayout);
|
||||||
Run("resource limit", TestResourceLimitIsTransactional);
|
Run("resource limit", TestResourceLimitIsTransactional);
|
||||||
} catch (const std::exception &exception) {
|
} catch (const std::exception &exception) {
|
||||||
|
|||||||
@@ -1144,7 +1144,7 @@ std::array<u32, 64> MakeStructuredStorageBufferData(u32 stride_bytes,
|
|||||||
std::array<u32, 64> data{};
|
std::array<u32, 64> data{};
|
||||||
data[1] = (stride_bytes & 0x3fffu) << 16u;
|
data[1] = (stride_bytes & 0x3fffu) << 16u;
|
||||||
data[2] = num_records;
|
data[2] = num_records;
|
||||||
data[3] = 1u << 24u;
|
data[3] = DstSel(4, 5, 6, 7) | (1u << 24u);
|
||||||
if (add_tid) {
|
if (add_tid) {
|
||||||
data[3] |= 1u << 23u;
|
data[3] |= 1u << 23u;
|
||||||
}
|
}
|
||||||
@@ -14278,6 +14278,56 @@ TestCase BufferLoadFormatXyzwSnapshotsOverlappingAddress() {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase BufferLoadFormatXyzwResource32_32FloatAppliesXy01() {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
|
std::vector<u32> code;
|
||||||
|
AppendVMovU32(&code, 20, 0);
|
||||||
|
AppendBufferLoadOpcode(&code, 0x03, 0, 20);
|
||||||
|
for (u32 i = 0; i < 4; i++) {
|
||||||
|
AppendStoreVgpr(&code, i, i);
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
|
||||||
|
TestCase test;
|
||||||
|
test.name = "BufferLoadFormatXyzwResource32_32FloatAppliesXy01";
|
||||||
|
test.code = std::move(code);
|
||||||
|
test.initial = {0x3f800000u, 0x40000000u, 0, 0};
|
||||||
|
test.expected = {0x3f800000u, 0x40000000u, 0, 0x3f800000u};
|
||||||
|
test.opcodes = {O::VMovB32, O::BufferLoadFormatXyzw,
|
||||||
|
O::BufferStoreDword, O::SEndpgm};
|
||||||
|
test.user_data = MakeStructuredStorageBufferData(
|
||||||
|
16, 1, false, BufferFormat(Prospero::BufferFormat::k32_32Float));
|
||||||
|
test.user_data[3] = (test.user_data[3] & ~0xfffu) | DstSel(4, 5, 0, 1);
|
||||||
|
test.has_user_data = true;
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCase BufferLoadFormatXyzwResource8_8_8_8UintAppliesWzy1() {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
|
std::vector<u32> code;
|
||||||
|
AppendVMovU32(&code, 20, 0);
|
||||||
|
AppendBufferLoadOpcode(&code, 0x03, 0, 20);
|
||||||
|
for (u32 i = 0; i < 4; i++) {
|
||||||
|
AppendStoreVgpr(&code, i, i);
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
|
||||||
|
TestCase test;
|
||||||
|
test.name = "BufferLoadFormatXyzwResource8_8_8_8UintAppliesWzy1";
|
||||||
|
test.code = std::move(code);
|
||||||
|
test.initial = {0x11223344u, 0x55667788u, 0x99aabbccu, 0xddeeff00u};
|
||||||
|
test.expected = {0x11u, 0x22u, 0x33u, 1u};
|
||||||
|
test.opcodes = {O::VMovB32, O::BufferLoadFormatXyzw,
|
||||||
|
O::BufferStoreDword, O::SEndpgm};
|
||||||
|
test.user_data = MakeStructuredStorageBufferData(
|
||||||
|
16, 1, false, BufferFormat(Prospero::BufferFormat::k8_8_8_8UInt));
|
||||||
|
test.user_data[3] = (test.user_data[3] & ~0xfffu) | DstSel(7, 6, 5, 1);
|
||||||
|
test.has_user_data = true;
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase BufferLoadFormatXyzwInactiveExecPreservesOverlappingAddress() {
|
TestCase BufferLoadFormatXyzwInactiveExecPreservesOverlappingAddress() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -17264,6 +17314,8 @@ std::vector<TestCase> MakeCases() {
|
|||||||
AddCase(BufferStoreVariants);
|
AddCase(BufferStoreVariants);
|
||||||
AddCase(BufferFormatVariants);
|
AddCase(BufferFormatVariants);
|
||||||
AddCase(BufferLoadFormatXyzwSnapshotsOverlappingAddress);
|
AddCase(BufferLoadFormatXyzwSnapshotsOverlappingAddress);
|
||||||
|
AddCase(BufferLoadFormatXyzwResource32_32FloatAppliesXy01);
|
||||||
|
AddCase(BufferLoadFormatXyzwResource8_8_8_8UintAppliesWzy1);
|
||||||
AddCase(BufferLoadFormatXyzwInactiveExecPreservesOverlappingAddress);
|
AddCase(BufferLoadFormatXyzwInactiveExecPreservesOverlappingAddress);
|
||||||
AddCase(BufferFormatStoreVariants);
|
AddCase(BufferFormatStoreVariants);
|
||||||
AddCase(BufferStoreFormatXResource16UintWritesHalfword);
|
AddCase(BufferStoreFormatXResource16UintWritesHalfword);
|
||||||
|
|||||||
Reference in New Issue
Block a user