refactor(shader): preserve native wide shared operations

This commit is contained in:
nmzik
2026-08-19 09:11:25 +02:00
parent c9e942a972
commit c236ba713d
25 changed files with 1486 additions and 986 deletions
@@ -168,42 +168,33 @@ ResourceKind DsMemoryKind(const Decoder::Instruction& decoded) {
}
bool LowerDsRead(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
const auto ir_op = DsReadOpcode(decoded);
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
for (uint32_t i = 0; i < count; i++) {
Instruction inst;
inst.pc = decoded.pc;
inst.op = ir_op;
inst.src_count = 1;
inst.memory = OffsetMemoryInfo(decoded, DsMemoryKind(decoded), i);
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) ||
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
return false;
}
block.instructions.push_back(inst);
const auto ir_op = DsReadOpcode(decoded);
Instruction inst;
inst.pc = decoded.pc;
inst.op = ir_op;
inst.src_count = 1;
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
return false;
}
block.instructions.push_back(inst);
return true;
}
bool LowerDsRead2(const Decoder::Instruction& decoded, BasicBlock& block, uint32_t dwords_per_read,
std::string* error) {
const uint32_t offsets[] = {decoded.offset, decoded.secondary_offset};
for (uint32_t read = 0; read < 2u; read++) {
for (uint32_t dword = 0; dword < dwords_per_read; dword++) {
const auto index = read * dwords_per_read + dword;
Instruction inst;
inst.pc = decoded.pc;
inst.op = Opcode::DsReadB32;
inst.src_count = 1;
inst.memory =
ByteOffsetMemoryInfo(decoded, DsMemoryKind(decoded), offsets[read] + dword * 4u);
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, index), inst.dst, error) ||
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
return false;
}
block.instructions.push_back(inst);
}
Instruction inst;
inst.pc = decoded.pc;
inst.op = Opcode::DsRead2B32;
inst.src_count = 1;
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
inst.memory.data_dwords = dwords_per_read * 2u;
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
return false;
}
block.instructions.push_back(inst);
return true;
}
@@ -408,45 +399,36 @@ bool LowerFlatStore(const Decoder::Instruction& decoded, BasicBlock& block, std:
}
bool LowerDsWrite(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
const auto ir_op = DsWriteOpcode(decoded.data_bits);
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
for (uint32_t i = 0; i < count; i++) {
Instruction inst;
inst.pc = decoded.pc;
inst.op = ir_op;
inst.src_count = 2;
inst.memory = OffsetMemoryInfo(decoded, DsMemoryKind(decoded), i);
inst.dst.kind = OperandKind::Null;
if (!LowerSourceOperand(OffsetDecodedRegister(decoded.src1, i), inst.src[0], error) ||
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
return false;
}
block.instructions.push_back(inst);
const auto ir_op = DsWriteOpcode(decoded.data_bits);
Instruction inst;
inst.pc = decoded.pc;
inst.op = ir_op;
inst.src_count = 2;
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
inst.dst.kind = OperandKind::Null;
if (!LowerSourceOperand(decoded.src1, inst.src[0], error) ||
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
return false;
}
block.instructions.push_back(inst);
return true;
}
bool LowerDsWrite2(const Decoder::Instruction& decoded, BasicBlock& block,
uint32_t dwords_per_write, std::string* error) {
const Decoder::Operand* data[] = {&decoded.src1, &decoded.src2};
const uint32_t offsets[] = {decoded.offset, decoded.secondary_offset};
for (uint32_t write = 0; write < 2u; write++) {
for (uint32_t dword = 0; dword < dwords_per_write; dword++) {
Instruction inst;
inst.pc = decoded.pc;
inst.op = Opcode::DsWriteB32;
inst.src_count = 2;
inst.memory =
ByteOffsetMemoryInfo(decoded, DsMemoryKind(decoded), offsets[write] + dword * 4u);
inst.dst.kind = OperandKind::Null;
if (!LowerSourceOperand(OffsetDecodedRegister(*data[write], dword), inst.src[0],
error) ||
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
return false;
}
block.instructions.push_back(inst);
}
Instruction inst;
inst.pc = decoded.pc;
inst.op = Opcode::DsWrite2B32;
inst.src_count = 3;
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
inst.memory.data_dwords = dwords_per_write * 2u;
inst.dst.kind = OperandKind::Null;
if (!LowerSourceOperand(decoded.src1, inst.src[0], error) ||
!LowerSourceOperand(decoded.src0, inst.src[1], error) ||
!LowerSourceOperand(decoded.src2, inst.src[2], error)) {
return false;
}
block.instructions.push_back(inst);
return true;
}
@@ -618,7 +600,8 @@ bool LowerMemoryInstruction(const Decoder::Instruction& decoded, BasicBlock& blo
return LowerDsWriteAddtidB32(decoded, block, error);
case Decoder::Opcode::DS_READ_ADDTID_B32:
return LowerDsReadAddtidB32(decoded, block, error);
case Decoder::Opcode::DS_READ2_B32: return LowerDsRead2(decoded, block, 1, error);
case Decoder::Opcode::DS_READ2_B32:
case Decoder::Opcode::DS_READ2ST64_B32: return LowerDsRead2(decoded, block, 1, error);
case Decoder::Opcode::DS_READ2_B64:
case Decoder::Opcode::DS_READ2ST64_B64: return LowerDsRead2(decoded, block, 2, error);
case Decoder::Opcode::DS_READ_I8:
@@ -765,6 +748,7 @@ bool IsMemoryOpcode(Decoder::Opcode opcode) {
case Decoder::Opcode::DS_READ_I16:
case Decoder::Opcode::DS_READ_U16:
case Decoder::Opcode::DS_READ2_B32:
case Decoder::Opcode::DS_READ2ST64_B32:
case Decoder::Opcode::DS_READ_B32:
case Decoder::Opcode::DS_READ_B64:
case Decoder::Opcode::DS_READ2_B64:
@@ -31,8 +31,6 @@ std::string TypeName(Type type) {
"AddressResource",
"ImageResource",
"SamplerResource",
"LdsResource",
"GdsResource",
"ImageAddress",
};
const auto bits = static_cast<uint32_t>(type);
+1 -3
View File
@@ -28,9 +28,7 @@ enum class Type : uint32_t {
AddressResource = 1u << 18u,
ImageResource = 1u << 19u,
SamplerResource = 1u << 20u,
LdsResource = 1u << 21u,
GdsResource = 1u << 22u,
ImageAddress = 1u << 23u,
ImageAddress = 1u << 21u,
};
constexpr Type operator|(Type lhs, Type rhs) {
@@ -338,6 +338,34 @@ bool ValidateValueProgram(const ValueProgram& program, bool require_ssa, std::st
ValueOpcodeName(inst.GetOpcode())));
}
}
const auto shared_components = SharedComponentCount(inst.GetOpcode());
if (shared_components != 0u) {
const auto memory_index = inst.Flags<MemoryFlags>().index;
if (memory_index >= program.memory_info.size()) {
return Fail(error, fmt::format("{} has an invalid memory-info index",
ValueOpcodeName(inst.GetOpcode())));
}
const auto& memory = program.memory_info[memory_index];
if ((memory.kind != ResourceKind::Lds && memory.kind != ResourceKind::Gds) ||
memory.resource != 0u || memory.sampler != 0u || memory.component_count == 0u ||
memory.component_index >= memory.component_count) {
return Fail(error, fmt::format("{} has invalid shared-memory metadata",
ValueOpcodeName(inst.GetOpcode())));
}
uint32_t expected_bits = 32u;
if (inst.GetOpcode() == ValueOpcode::LoadSharedU8 ||
inst.GetOpcode() == ValueOpcode::WriteSharedU8) {
expected_bits = 8u;
} else if (inst.GetOpcode() == ValueOpcode::LoadSharedU16 ||
inst.GetOpcode() == ValueOpcode::WriteSharedU16) {
expected_bits = 16u;
}
if (memory.data_bits != expected_bits || memory.data_dwords != shared_components ||
(shared_components > 1u && memory.component_index != 0u)) {
return Fail(error, fmt::format("{} has inconsistent shared-memory width",
ValueOpcodeName(inst.GetOpcode())));
}
}
uint32_t composite_components = 0u;
switch (inst.GetOpcode()) {
case ValueOpcode::CompositeExtractU32x2: composite_components = 2u; break;
@@ -358,10 +386,11 @@ bool ValidateValueProgram(const ValueProgram& program, bool require_ssa, std::st
ValueOpcodeName(inst.GetOpcode())));
}
if (fixed_signature && arg.GetType() != ArgTypeOf(inst.GetOpcode(), arg_index)) {
return Fail(error, fmt::format("{} argument {} has type {}, expected {}",
ValueOpcodeName(inst.GetOpcode()), arg_index,
TypeName(arg.GetType()),
TypeName(ArgTypeOf(inst.GetOpcode(), arg_index))));
return Fail(error,
fmt::format("{} argument {} has type {}, expected {}",
ValueOpcodeName(inst.GetOpcode()), arg_index,
TypeName(arg.GetType()),
TypeName(ArgTypeOf(inst.GetOpcode(), arg_index))));
}
if (const auto* definition = arg.TryInstruction();
definition != nullptr && !instructions.contains(definition)) {
@@ -392,19 +392,20 @@ constexpr LowerMap LOWER_OPS[] = {
{Decoder::Opcode::DS_READ_U8, Opcode::DsReadUbyte},
{Decoder::Opcode::DS_READ_I16, Opcode::DsReadSshort},
{Decoder::Opcode::DS_READ_U16, Opcode::DsReadUshort},
{Decoder::Opcode::DS_READ2_B32, Opcode::DsReadB32},
{Decoder::Opcode::DS_READ2_B32, Opcode::DsRead2B32},
{Decoder::Opcode::DS_READ2ST64_B32, Opcode::DsRead2B32},
{Decoder::Opcode::DS_READ_B32, Opcode::DsReadB32},
{Decoder::Opcode::DS_READ_B64, Opcode::DsReadB32},
{Decoder::Opcode::DS_READ2_B64, Opcode::DsReadB32},
{Decoder::Opcode::DS_READ2ST64_B64, Opcode::DsReadB32},
{Decoder::Opcode::DS_READ2_B64, Opcode::DsRead2B32},
{Decoder::Opcode::DS_READ2ST64_B64, Opcode::DsRead2B32},
{Decoder::Opcode::DS_READ_B96, Opcode::DsReadB32},
{Decoder::Opcode::DS_READ_B128, Opcode::DsReadB32},
{Decoder::Opcode::DS_WRITE_B8, Opcode::DsWriteByte},
{Decoder::Opcode::DS_WRITE_B16, Opcode::DsWriteShort},
{Decoder::Opcode::DS_WRITE2_B32, Opcode::DsWriteB32},
{Decoder::Opcode::DS_WRITE2ST64_B32, Opcode::DsWriteB32},
{Decoder::Opcode::DS_WRITE2_B64, Opcode::DsWriteB32},
{Decoder::Opcode::DS_WRITE2ST64_B64, Opcode::DsWriteB32},
{Decoder::Opcode::DS_WRITE2_B32, Opcode::DsWrite2B32},
{Decoder::Opcode::DS_WRITE2ST64_B32, Opcode::DsWrite2B32},
{Decoder::Opcode::DS_WRITE2_B64, Opcode::DsWrite2B32},
{Decoder::Opcode::DS_WRITE2ST64_B64, Opcode::DsWrite2B32},
{Decoder::Opcode::DS_WRITE_B32, Opcode::DsWriteB32},
{Decoder::Opcode::DS_WRITE_B64, Opcode::DsWriteB32},
{Decoder::Opcode::DS_WRITE_B96, Opcode::DsWriteB32},
@@ -331,9 +331,11 @@ IR_OPCODE(DsReadSbyte, General, Memory)
IR_OPCODE(DsReadUshort, General, Memory)
IR_OPCODE(DsReadSshort, General, Memory)
IR_OPCODE(DsReadB32, General, Memory)
IR_OPCODE(DsRead2B32, General, Memory)
IR_OPCODE(DsWriteByte, General, Memory)
IR_OPCODE(DsWriteShort, General, Memory)
IR_OPCODE(DsWriteB32, General, Memory)
IR_OPCODE(DsWrite2B32, General, Memory)
IR_OPCODE(DsMinF32, General, Memory)
IR_OPCODE(DsMaxF32, General, Memory)
IR_OPCODE(DsSwizzleB32, General, Memory)
@@ -42,8 +42,6 @@ constexpr Type BufferResource = Type::BufferResource;
constexpr Type AddressResource = Type::AddressResource;
constexpr Type ImageResource = Type::ImageResource;
constexpr Type SamplerResource = Type::SamplerResource;
constexpr Type LdsResource = Type::LdsResource;
constexpr Type GdsResource = Type::GdsResource;
constexpr Type ImageAddress = Type::ImageAddress;
constexpr std::array<OpcodeMeta, static_cast<size_t>(ValueOpcode::Count)> MetaTable = {{
@@ -76,52 +74,23 @@ bool HasSideEffects(ValueOpcode opcode) {
if (buffer_access == BufferAccess::Write || buffer_access == BufferAccess::Atomic) {
return true;
}
const auto shared_access = SharedAccessOf(opcode);
if (shared_access == SharedAccess::Write || shared_access == SharedAccess::Atomic ||
shared_access == SharedAccess::Append || shared_access == SharedAccess::Consume) {
return true;
}
switch (opcode) {
case ValueOpcode::Reference:
case ValueOpcode::ReferenceU32:
case ValueOpcode::StoreAddressU8:
case ValueOpcode::StoreAddressU16:
case ValueOpcode::StoreAddressU32:
case ValueOpcode::WriteSharedU8:
case ValueOpcode::WriteSharedU16:
case ValueOpcode::WriteSharedU32:
case ValueOpcode::WriteGdsU8:
case ValueOpcode::WriteGdsU16:
case ValueOpcode::WriteGdsU32:
case ValueOpcode::SharedAtomicFMin32:
case ValueOpcode::SharedAtomicFMax32:
case ValueOpcode::GdsAtomicFMin32:
case ValueOpcode::GdsAtomicFMax32:
case ValueOpcode::SharedAtomicSwap32:
case ValueOpcode::SharedAtomicIAdd32:
case ValueOpcode::SharedAtomicISub32:
case ValueOpcode::SharedAtomicSMin32:
case ValueOpcode::SharedAtomicUMin32:
case ValueOpcode::SharedAtomicSMax32:
case ValueOpcode::SharedAtomicUMax32:
case ValueOpcode::SharedAtomicAnd32:
case ValueOpcode::SharedAtomicOr32:
case ValueOpcode::SharedAtomicXor32:
case ValueOpcode::GdsAtomicSwap32:
case ValueOpcode::GdsAtomicIAdd32:
case ValueOpcode::GdsAtomicISub32:
case ValueOpcode::GdsAtomicSMin32:
case ValueOpcode::GdsAtomicUMin32:
case ValueOpcode::GdsAtomicSMax32:
case ValueOpcode::GdsAtomicUMax32:
case ValueOpcode::GdsAtomicAnd32:
case ValueOpcode::GdsAtomicOr32:
case ValueOpcode::GdsAtomicXor32:
case ValueOpcode::ImageAtomicIAdd32:
case ValueOpcode::ImageAtomicUMin32:
case ValueOpcode::ImageAtomicUMax32:
case ValueOpcode::ImageAtomicAnd32:
case ValueOpcode::ImageAtomicOr32:
case ValueOpcode::ImageAtomicXor32:
case ValueOpcode::DataAppend:
case ValueOpcode::DataConsume:
case ValueOpcode::GdsDataAppend:
case ValueOpcode::GdsDataConsume:
case ValueOpcode::ImageWrite:
case ValueOpcode::SetAttribute:
case ValueOpcode::Barrier: return true;
@@ -172,4 +141,48 @@ uint32_t BufferComponentCount(ValueOpcode opcode) {
}
}
SharedAccess SharedAccessOf(ValueOpcode opcode) {
switch (opcode) {
case ValueOpcode::LoadSharedU8:
case ValueOpcode::LoadSharedU16:
case ValueOpcode::LoadSharedU32:
case ValueOpcode::LoadSharedU32x2:
case ValueOpcode::LoadSharedU32x3:
case ValueOpcode::LoadSharedU32x4: return SharedAccess::Read;
case ValueOpcode::WriteSharedU8:
case ValueOpcode::WriteSharedU16:
case ValueOpcode::WriteSharedU32:
case ValueOpcode::WriteSharedU32x2:
case ValueOpcode::WriteSharedU32x3:
case ValueOpcode::WriteSharedU32x4: return SharedAccess::Write;
case ValueOpcode::SharedAtomicFMin32:
case ValueOpcode::SharedAtomicFMax32:
case ValueOpcode::SharedAtomicSwap32:
case ValueOpcode::SharedAtomicIAdd32:
case ValueOpcode::SharedAtomicISub32:
case ValueOpcode::SharedAtomicSMin32:
case ValueOpcode::SharedAtomicUMin32:
case ValueOpcode::SharedAtomicSMax32:
case ValueOpcode::SharedAtomicUMax32:
case ValueOpcode::SharedAtomicAnd32:
case ValueOpcode::SharedAtomicOr32:
case ValueOpcode::SharedAtomicXor32: return SharedAccess::Atomic;
case ValueOpcode::DataAppend: return SharedAccess::Append;
case ValueOpcode::DataConsume: return SharedAccess::Consume;
default: return SharedAccess::None;
}
}
uint32_t SharedComponentCount(ValueOpcode opcode) {
switch (opcode) {
case ValueOpcode::LoadSharedU32x2:
case ValueOpcode::WriteSharedU32x2: return 2u;
case ValueOpcode::LoadSharedU32x3:
case ValueOpcode::WriteSharedU32x3: return 3u;
case ValueOpcode::LoadSharedU32x4:
case ValueOpcode::WriteSharedU32x4: return 4u;
default: return SharedAccessOf(opcode) == SharedAccess::None ? 0u : 1u;
}
}
} // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -17,6 +17,7 @@ enum class ValueOpcode {
};
enum class BufferAccess { None, Read, Write, Atomic };
enum class SharedAccess { None, Read, Write, Atomic, Append, Consume };
struct DppMoveFlags {
uint16_t control = 0;
@@ -56,6 +57,8 @@ static_assert(std::is_trivially_copyable_v<ExportFlags>);
[[nodiscard]] bool HasSideEffects(ValueOpcode opcode);
[[nodiscard]] BufferAccess BufferAccessOf(ValueOpcode opcode);
[[nodiscard]] uint32_t BufferComponentCount(ValueOpcode opcode);
[[nodiscard]] SharedAccess SharedAccessOf(ValueOpcode opcode);
[[nodiscard]] uint32_t SharedComponentCount(ValueOpcode opcode);
[[nodiscard]] std::string_view ValueOpcodeName(ValueOpcode opcode);
} // namespace Libs::Graphics::ShaderRecompiler::IR
@@ -202,8 +202,6 @@ VALUE_OPCODE(GetBufferResource, BufferResource, U32, U32, U32, U32)
VALUE_OPCODE(GetAddressResource, AddressResource, U32, U32)
VALUE_OPCODE(GetImageResource, ImageResource, U32, U32, U32, U32, U32, U32, U32, U32)
VALUE_OPCODE(GetSamplerResource, SamplerResource, U32, U32, U32, U32)
VALUE_OPCODE(GetLdsResource, LdsResource)
VALUE_OPCODE(GetGdsResource, GdsResource)
VALUE_OPCODE(MakeImageAddress, ImageAddress, U32, U32, U32, U32, U32, U32, U32, U32, U32, U32, U32,
U32, U32)
@@ -240,46 +238,32 @@ VALUE_OPCODE(BufferAtomicXor32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicFMin32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(BufferAtomicFMax32, U32, BufferResource, U32, U32, U32, U32, U1)
VALUE_OPCODE(LoadSharedU8, U8, LdsResource, U32, U1)
VALUE_OPCODE(LoadSharedU16, U16, LdsResource, U32, U1)
VALUE_OPCODE(LoadSharedU32, U32, LdsResource, U32, U1)
VALUE_OPCODE(WriteSharedU8, Void, LdsResource, U32, U8, U1)
VALUE_OPCODE(WriteSharedU16, Void, LdsResource, U32, U16, U1)
VALUE_OPCODE(WriteSharedU32, Void, LdsResource, U32, U32, U1)
VALUE_OPCODE(LoadGdsU8, U8, GdsResource, U32, U1)
VALUE_OPCODE(LoadGdsU16, U16, GdsResource, U32, U1)
VALUE_OPCODE(LoadGdsU32, U32, GdsResource, U32, U1)
VALUE_OPCODE(WriteGdsU8, Void, GdsResource, U32, U8, U1)
VALUE_OPCODE(WriteGdsU16, Void, GdsResource, U32, U16, U1)
VALUE_OPCODE(WriteGdsU32, Void, GdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicFMin32, Void, LdsResource, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicFMax32, Void, LdsResource, U32, U32, U32, U1)
VALUE_OPCODE(GdsAtomicFMin32, Void, GdsResource, U32, U32, U32, U1)
VALUE_OPCODE(GdsAtomicFMax32, Void, GdsResource, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicSwap32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicIAdd32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicISub32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicSMin32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicUMin32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicSMax32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicUMax32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicAnd32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicOr32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(SharedAtomicXor32, U32, LdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicSwap32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicIAdd32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicISub32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicSMin32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicUMin32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicSMax32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicUMax32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicAnd32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicOr32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(GdsAtomicXor32, U32, GdsResource, U32, U32, U1)
VALUE_OPCODE(DataAppend, U32, LdsResource, U32, U1, U32, U32)
VALUE_OPCODE(DataConsume, U32, LdsResource, U32, U1, U32, U32)
VALUE_OPCODE(GdsDataAppend, U32, GdsResource, U32, U1, U32, U32)
VALUE_OPCODE(GdsDataConsume, U32, GdsResource, U32, U1, U32, U32)
VALUE_OPCODE(LoadSharedU8, U8, U32, U1)
VALUE_OPCODE(LoadSharedU16, U16, U32, U1)
VALUE_OPCODE(LoadSharedU32, U32, U32, U1)
VALUE_OPCODE(LoadSharedU32x2, U32x2, U32, U1)
VALUE_OPCODE(LoadSharedU32x3, U32x3, U32, U1)
VALUE_OPCODE(LoadSharedU32x4, U32x4, U32, U1)
VALUE_OPCODE(WriteSharedU8, Void, U32, U8, U1)
VALUE_OPCODE(WriteSharedU16, Void, U32, U16, U1)
VALUE_OPCODE(WriteSharedU32, Void, U32, U32, U1)
VALUE_OPCODE(WriteSharedU32x2, Void, U32, U32, U32, U1)
VALUE_OPCODE(WriteSharedU32x3, Void, U32, U32, U32, U32, U1)
VALUE_OPCODE(WriteSharedU32x4, Void, U32, U32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicFMin32, Void, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicFMax32, Void, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicSwap32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicIAdd32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicISub32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicSMin32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicUMin32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicSMax32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicUMax32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicAnd32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicOr32, U32, U32, U32, U1)
VALUE_OPCODE(SharedAtomicXor32, U32, U32, U32, U1)
VALUE_OPCODE(DataAppend, U32, U32, U1, U32, U32)
VALUE_OPCODE(DataConsume, U32, U32, U1, U32, U32)
VALUE_OPCODE(SwizzleU32, U32, U32, U32, U1)
VALUE_OPCODE(ImageQueryDimensions, U32x4, ImageResource, ImageAddress)
@@ -115,20 +115,25 @@ void AddBinding(BindingLayout& layout, DescriptorBindingKind kind,
{kind, static_cast<uint32_t>(layout.descriptors.size()), std::move(resources)});
}
bool UsesGds(const Program& program) {
bool UsesGds(const Program& program, bool& uses_gds) {
uses_gds = false;
for (const auto* block: program.values->blocks) {
for (const auto& inst: *block) {
if (inst.GetOpcode() == ValueOpcode::GetGdsResource && inst.HasUses()) {
return true;
if (SharedAccessOf(inst.GetOpcode()) == SharedAccess::None) {
continue;
}
for (size_t index = 0; index < inst.NumArgs(); index++) {
if (inst.Arg(index).GetType() == Type::GdsResource) {
return true;
}
const auto index = inst.Flags<MemoryFlags>().index;
if (index >= program.values->memory_info.size()) {
return false;
}
const auto kind = program.values->memory_info[index].kind;
if (kind != ResourceKind::Lds && kind != ResourceKind::Gds) {
return false;
}
uses_gds |= kind == ResourceKind::Gds;
}
}
return false;
return true;
}
} // namespace
@@ -220,7 +225,14 @@ bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std
}
AddBinding(next, DescriptorBindingKind::Samplers, std::move(resources));
}
if (UsesGds(program)) {
bool uses_gds = false;
if (!UsesGds(program, uses_gds)) {
if (error != nullptr) {
*error = "typed shader contains invalid shared-memory metadata";
}
return false;
}
if (uses_gds) {
AddBinding(next, DescriptorBindingKind::Gds);
}
if (!program.info.addresses.empty()) {