gl_shader_decompiler: Use uint for images and fix SUATOM

In the process remove implementation of SUATOM.MIN and SUATOM.MAX as
these require a distinction between U32 and S32. These have to be
implemented with imageCompSwap loop.
This commit is contained in:
ReinUsesLisp 2019-09-18 01:50:40 -03:00
parent 675f23aedc
commit 44000971e2
No known key found for this signature in database
GPG key ID: 2DFC508897B39CFE
7 changed files with 93 additions and 188 deletions

View file

@ -544,7 +544,7 @@ enum class VoteOperation : u64 {
Eq = 2, // allThreadsEqualNV Eq = 2, // allThreadsEqualNV
}; };
enum class ImageAtomicSize : u64 { enum class ImageAtomicOperationType : u64 {
U32 = 0, U32 = 0,
S32 = 1, S32 = 1,
U64 = 2, U64 = 2,
@ -1431,7 +1431,7 @@ union Instruction {
union { union {
BitField<28, 1, u64> is_ba; BitField<28, 1, u64> is_ba;
BitField<51, 3, ImageAtomicSize> size; BitField<51, 3, ImageAtomicOperationType> operation_type;
BitField<33, 3, ImageType> image_type; BitField<33, 3, ImageType> image_type;
BitField<29, 4, ImageAtomicOperation> operation; BitField<29, 4, ImageAtomicOperation> operation;
BitField<49, 2, OutOfBoundsStore> out_of_bounds_store; BitField<49, 2, OutOfBoundsStore> out_of_bounds_store;

View file

@ -716,36 +716,20 @@ private:
const char* image_type = [&] { const char* image_type = [&] {
switch (image.GetType()) { switch (image.GetType()) {
case Tegra::Shader::ImageType::Texture1D: case Tegra::Shader::ImageType::Texture1D:
return "image1D"; return "1D";
case Tegra::Shader::ImageType::TextureBuffer: case Tegra::Shader::ImageType::TextureBuffer:
return "imageBuffer"; return "Buffer";
case Tegra::Shader::ImageType::Texture1DArray: case Tegra::Shader::ImageType::Texture1DArray:
return "image1DArray"; return "1DArray";
case Tegra::Shader::ImageType::Texture2D: case Tegra::Shader::ImageType::Texture2D:
return "image2D"; return "2D";
case Tegra::Shader::ImageType::Texture2DArray: case Tegra::Shader::ImageType::Texture2DArray:
return "image2DArray"; return "2DArray";
case Tegra::Shader::ImageType::Texture3D: case Tegra::Shader::ImageType::Texture3D:
return "image3D"; return "3D";
default: default:
UNREACHABLE(); UNREACHABLE();
return "image1D"; return "1D";
}
}();
const auto [type_prefix, format] = [&]() -> std::pair<const char*, const char*> {
if (!image.IsSizeKnown()) {
return {"", ""};
}
switch (image.GetSize()) {
case Tegra::Shader::ImageAtomicSize::U32:
return {"u", "r32ui, "};
case Tegra::Shader::ImageAtomicSize::S32:
return {"i", "r32i, "};
default:
UNIMPLEMENTED_MSG("Unimplemented atomic size={}",
static_cast<u32>(image.GetSize()));
return {"", ""};
} }
}(); }();
@ -756,8 +740,12 @@ private:
qualifier += " writeonly"; qualifier += " writeonly";
} }
code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform " std::string format;
"{} {};", if (image.IsAtomic()) {
format = "r32ui, ";
}
code.AddLine("layout ({}binding = IMAGE_BINDING_{}) {} uniform uimage{} {};", format,
image.GetIndex(), qualifier, image_type, GetImage(image)); image.GetIndex(), qualifier, image_type, GetImage(image));
} }
if (!images.empty()) { if (!images.empty()) {
@ -1225,28 +1213,13 @@ private:
} }
std::string BuildImageValues(Operation operation) { std::string BuildImageValues(Operation operation) {
constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"};
const auto meta{std::get<MetaImage>(operation.GetMeta())}; const auto meta{std::get<MetaImage>(operation.GetMeta())};
const auto [constructors, type] = [&]() -> std::pair<std::array<const char*, 4>, Type> {
constexpr std::array float_constructors{"float", "vec2", "vec3", "vec4"};
if (!meta.image.IsSizeKnown()) {
return {float_constructors, Type::Float};
}
switch (meta.image.GetSize()) {
case Tegra::Shader::ImageAtomicSize::U32:
return {{"uint", "uvec2", "uvec3", "uvec4"}, Type::Uint};
case Tegra::Shader::ImageAtomicSize::S32:
return {{"int", "ivec2", "ivec3", "ivec4"}, Type::Uint};
default:
UNIMPLEMENTED_MSG("Unimplemented image size={}",
static_cast<u32>(meta.image.GetSize()));
return {float_constructors, Type::Float};
}
}();
const std::size_t values_count{meta.values.size()}; const std::size_t values_count{meta.values.size()};
std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); std::string expr = fmt::format("{}(", constructors.at(values_count - 1));
for (std::size_t i = 0; i < values_count; ++i) { for (std::size_t i = 0; i < values_count; ++i) {
expr += Visit(meta.values.at(i)).As(type); expr += Visit(meta.values.at(i)).AsUint();
if (i + 1 < values_count) { if (i + 1 < values_count) {
expr += ", "; expr += ", ";
} }
@ -1255,29 +1228,6 @@ private:
return expr; return expr;
} }
Expression AtomicImage(Operation operation, const char* opname) {
constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
const auto meta{std::get<MetaImage>(operation.GetMeta())};
ASSERT(meta.values.size() == 1);
ASSERT(meta.image.IsSizeKnown());
const auto type = [&]() {
switch (const auto size = meta.image.GetSize()) {
case Tegra::Shader::ImageAtomicSize::U32:
return Type::Uint;
case Tegra::Shader::ImageAtomicSize::S32:
return Type::Int;
default:
UNIMPLEMENTED_MSG("Unimplemented image size={}", static_cast<u32>(size));
return Type::Uint;
}
}();
return {fmt::format("{}({}, {}, {})", opname, GetImage(meta.image),
BuildIntegerCoordinates(operation), Visit(meta.values[0]).As(type)),
type};
}
Expression Assign(Operation operation) { Expression Assign(Operation operation) {
const Node& dest = operation[0]; const Node& dest = operation[0];
const Node& src = operation[1]; const Node& src = operation[1];
@ -1810,7 +1760,7 @@ private:
const auto meta{std::get<MetaImage>(operation.GetMeta())}; const auto meta{std::get<MetaImage>(operation.GetMeta())};
return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image), return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image),
BuildIntegerCoordinates(operation), GetSwizzle(meta.element)), BuildIntegerCoordinates(operation), GetSwizzle(meta.element)),
Type::Float}; Type::Uint};
} }
Expression ImageStore(Operation operation) { Expression ImageStore(Operation operation) {
@ -1820,31 +1770,14 @@ private:
return {}; return {};
} }
Expression AtomicImageAdd(Operation operation) { template <const std::string_view& opname>
return AtomicImage(operation, "imageAtomicAdd"); Expression AtomicImage(Operation operation) {
} const auto meta{std::get<MetaImage>(operation.GetMeta())};
ASSERT(meta.values.size() == 1);
Expression AtomicImageMin(Operation operation) { return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image),
return AtomicImage(operation, "imageAtomicMin"); BuildIntegerCoordinates(operation), Visit(meta.values[0]).AsUint()),
} Type::Uint};
Expression AtomicImageMax(Operation operation) {
return AtomicImage(operation, "imageAtomicMax");
}
Expression AtomicImageAnd(Operation operation) {
return AtomicImage(operation, "imageAtomicAnd");
}
Expression AtomicImageOr(Operation operation) {
return AtomicImage(operation, "imageAtomicOr");
}
Expression AtomicImageXor(Operation operation) {
return AtomicImage(operation, "imageAtomicXor");
}
Expression AtomicImageExchange(Operation operation) {
return AtomicImage(operation, "imageAtomicExchange");
} }
Expression Branch(Operation operation) { Expression Branch(Operation operation) {
@ -2039,6 +1972,12 @@ private:
Func() = delete; Func() = delete;
~Func() = delete; ~Func() = delete;
static constexpr std::string_view Add = "Add";
static constexpr std::string_view And = "And";
static constexpr std::string_view Or = "Or";
static constexpr std::string_view Xor = "Xor";
static constexpr std::string_view Exchange = "Exchange";
static constexpr std::string_view ShuffleIndexed = "shuffleNV"; static constexpr std::string_view ShuffleIndexed = "shuffleNV";
static constexpr std::string_view ShuffleUp = "shuffleUpNV"; static constexpr std::string_view ShuffleUp = "shuffleUpNV";
static constexpr std::string_view ShuffleDown = "shuffleDownNV"; static constexpr std::string_view ShuffleDown = "shuffleDownNV";
@ -2178,13 +2117,12 @@ private:
&GLSLDecompiler::ImageLoad, &GLSLDecompiler::ImageLoad,
&GLSLDecompiler::ImageStore, &GLSLDecompiler::ImageStore,
&GLSLDecompiler::AtomicImageAdd,
&GLSLDecompiler::AtomicImageMin, &GLSLDecompiler::AtomicImage<Func::Add>,
&GLSLDecompiler::AtomicImageMax, &GLSLDecompiler::AtomicImage<Func::And>,
&GLSLDecompiler::AtomicImageAnd, &GLSLDecompiler::AtomicImage<Func::Or>,
&GLSLDecompiler::AtomicImageOr, &GLSLDecompiler::AtomicImage<Func::Xor>,
&GLSLDecompiler::AtomicImageXor, &GLSLDecompiler::AtomicImage<Func::Exchange>,
&GLSLDecompiler::AtomicImageExchange,
&GLSLDecompiler::Branch, &GLSLDecompiler::Branch,
&GLSLDecompiler::BranchIndirect, &GLSLDecompiler::BranchIndirect,

View file

@ -343,20 +343,17 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
u8 is_bindless{}; u8 is_bindless{};
u8 is_written{}; u8 is_written{};
u8 is_read{}; u8 is_read{};
u8 is_size_known{}; u8 is_atomic{};
u32 size{};
if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
!LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) || !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) ||
!LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) || !LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) ||
!LoadObjectFromPrecompiled(is_size_known) || !LoadObjectFromPrecompiled(size)) { !LoadObjectFromPrecompiled(is_atomic)) {
return {}; return {};
} }
entry.entries.images.emplace_back( entry.entries.images.emplace_back(
static_cast<std::size_t>(offset), static_cast<std::size_t>(index), static_cast<std::size_t>(offset), static_cast<std::size_t>(index),
static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0, static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0,
is_read != 0, is_read != 0, is_atomic != 0);
is_size_known ? std::make_optional(static_cast<Tegra::Shader::ImageAtomicSize>(size))
: std::nullopt);
} }
u32 global_memory_count{}; u32 global_memory_count{};
@ -429,14 +426,13 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
return false; return false;
} }
for (const auto& image : entries.images) { for (const auto& image : entries.images) {
const u32 size = image.IsSizeKnown() ? static_cast<u32>(image.GetSize()) : 0U;
if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
!SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
!SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) || !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) || !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) ||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) || !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) ||
!SaveObjectToPrecompiled(image.IsSizeKnown()) || !SaveObjectToPrecompiled(size)) { !SaveObjectToPrecompiled(static_cast<u8>(image.IsAtomic() ? 1 : 0))) {
return false; return false;
} }
} }

View file

@ -955,16 +955,6 @@ private:
return {}; return {};
} }
Id AtomicImageMin(Operation operation) {
UNIMPLEMENTED();
return {};
}
Id AtomicImageMax(Operation operation) {
UNIMPLEMENTED();
return {};
}
Id AtomicImageAnd(Operation operation) { Id AtomicImageAnd(Operation operation) {
UNIMPLEMENTED(); UNIMPLEMENTED();
return {}; return {};
@ -1449,8 +1439,6 @@ private:
&SPIRVDecompiler::ImageLoad, &SPIRVDecompiler::ImageLoad,
&SPIRVDecompiler::ImageStore, &SPIRVDecompiler::ImageStore,
&SPIRVDecompiler::AtomicImageAdd, &SPIRVDecompiler::AtomicImageAdd,
&SPIRVDecompiler::AtomicImageMin,
&SPIRVDecompiler::AtomicImageMax,
&SPIRVDecompiler::AtomicImageAnd, &SPIRVDecompiler::AtomicImageAnd,
&SPIRVDecompiler::AtomicImageOr, &SPIRVDecompiler::AtomicImageOr,
&SPIRVDecompiler::AtomicImageXor, &SPIRVDecompiler::AtomicImageXor,

View file

@ -101,13 +101,12 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0);
const OperationCode operation_code = [instr] { const OperationCode operation_code = [instr] {
switch (instr.suatom_d.operation_type) {
case Tegra::Shader::ImageAtomicOperationType::S32:
case Tegra::Shader::ImageAtomicOperationType::U32:
switch (instr.suatom_d.operation) { switch (instr.suatom_d.operation) {
case Tegra::Shader::ImageAtomicOperation::Add: case Tegra::Shader::ImageAtomicOperation::Add:
return OperationCode::AtomicImageAdd; return OperationCode::AtomicImageAdd;
case Tegra::Shader::ImageAtomicOperation::Min:
return OperationCode::AtomicImageMin;
case Tegra::Shader::ImageAtomicOperation::Max:
return OperationCode::AtomicImageMax;
case Tegra::Shader::ImageAtomicOperation::And: case Tegra::Shader::ImageAtomicOperation::And:
return OperationCode::AtomicImageAnd; return OperationCode::AtomicImageAnd;
case Tegra::Shader::ImageAtomicOperation::Or: case Tegra::Shader::ImageAtomicOperation::Or:
@ -116,17 +115,21 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
return OperationCode::AtomicImageXor; return OperationCode::AtomicImageXor;
case Tegra::Shader::ImageAtomicOperation::Exch: case Tegra::Shader::ImageAtomicOperation::Exch:
return OperationCode::AtomicImageExchange; return OperationCode::AtomicImageExchange;
default:
UNIMPLEMENTED_MSG("Unimplemented operation={}",
static_cast<u32>(instr.suatom_d.operation.Value()));
return OperationCode::AtomicImageAdd;
} }
default:
break;
}
UNIMPLEMENTED_MSG("Unimplemented operation={} type={}",
static_cast<u64>(instr.suatom_d.operation.Value()),
static_cast<u64>(instr.suatom_d.operation_type.Value()));
return OperationCode::AtomicImageAdd;
}(); }();
Node value = GetRegister(instr.gpr0); Node value = GetRegister(instr.gpr0);
const auto type = instr.suatom_d.image_type; const auto type = instr.suatom_d.image_type;
const auto& image{GetImage(instr.image, type, instr.suatom_d.size)}; auto& image = GetImage(instr.image, type);
image.MarkAtomic();
MetaImage meta{image, {std::move(value)}}; MetaImage meta{image, {std::move(value)}};
SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type))); SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type)));
@ -139,35 +142,32 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
return pc; return pc;
} }
Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
std::optional<Tegra::Shader::ImageAtomicSize> size) {
const auto offset{static_cast<std::size_t>(image.index.Value())}; const auto offset{static_cast<std::size_t>(image.index.Value())};
if (const auto image = TryUseExistingImage(offset, type, size)) { if (const auto image = TryUseExistingImage(offset, type)) {
return *image; return *image;
} }
const std::size_t next_index{used_images.size()}; const std::size_t next_index{used_images.size()};
return used_images.emplace(offset, Image{offset, next_index, type, size}).first->second; return used_images.emplace(offset, Image{offset, next_index, type}).first->second;
} }
Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
std::optional<Tegra::Shader::ImageAtomicSize> size) {
const Node image_register{GetRegister(reg)}; const Node image_register{GetRegister(reg)};
const auto [base_image, cbuf_index, cbuf_offset]{ const auto [base_image, cbuf_index, cbuf_offset]{
TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
if (const auto image = TryUseExistingImage(cbuf_key, type, size)) { if (const auto image = TryUseExistingImage(cbuf_key, type)) {
return *image; return *image;
} }
const std::size_t next_index{used_images.size()}; const std::size_t next_index{used_images.size()};
return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type, size}) return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type})
.first->second; .first->second;
} }
Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type) {
std::optional<Tegra::Shader::ImageAtomicSize> size) {
auto it = used_images.find(offset); auto it = used_images.find(offset);
if (it == used_images.end()) { if (it == used_images.end()) {
return nullptr; return nullptr;
@ -175,14 +175,6 @@ Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
auto& image = it->second; auto& image = it->second;
ASSERT(image.GetType() == type); ASSERT(image.GetType() == type);
if (size) {
// We know the size, if it's known it has to be the same as before, otherwise we can set it.
if (image.IsSizeKnown()) {
ASSERT(image.GetSize() == size);
} else {
image.SetSize(*size);
}
}
return &image; return &image;
} }

View file

@ -151,9 +151,8 @@ enum class OperationCode {
ImageLoad, /// (MetaImage, int[N] coords) -> void ImageLoad, /// (MetaImage, int[N] coords) -> void
ImageStore, /// (MetaImage, int[N] coords) -> void ImageStore, /// (MetaImage, int[N] coords) -> void
AtomicImageAdd, /// (MetaImage, int[N] coords) -> void AtomicImageAdd, /// (MetaImage, int[N] coords) -> void
AtomicImageMin, /// (MetaImage, int[N] coords) -> void
AtomicImageMax, /// (MetaImage, int[N] coords) -> void
AtomicImageAnd, /// (MetaImage, int[N] coords) -> void AtomicImageAnd, /// (MetaImage, int[N] coords) -> void
AtomicImageOr, /// (MetaImage, int[N] coords) -> void AtomicImageOr, /// (MetaImage, int[N] coords) -> void
AtomicImageXor, /// (MetaImage, int[N] coords) -> void AtomicImageXor, /// (MetaImage, int[N] coords) -> void
@ -295,21 +294,18 @@ private:
class Image final { class Image final {
public: public:
constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type)
std::optional<Tegra::Shader::ImageAtomicSize> size) : offset{offset}, index{index}, type{type}, is_bindless{false} {}
: offset{offset}, index{index}, type{type}, is_bindless{false}, size{size} {}
constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
Tegra::Shader::ImageType type, Tegra::Shader::ImageType type)
std::optional<Tegra::Shader::ImageAtomicSize> size)
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
is_bindless{true}, size{size} {} is_bindless{true} {}
constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
bool is_bindless, bool is_written, bool is_read, bool is_bindless, bool is_written, bool is_read, bool is_atomic)
std::optional<Tegra::Shader::ImageAtomicSize> size)
: offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, : offset{offset}, index{index}, type{type}, is_bindless{is_bindless},
is_written{is_written}, is_read{is_read}, size{size} {} is_written{is_written}, is_read{is_read}, is_atomic{is_atomic} {}
void MarkWrite() { void MarkWrite() {
is_written = true; is_written = true;
@ -319,8 +315,10 @@ public:
is_read = true; is_read = true;
} }
void SetSize(Tegra::Shader::ImageAtomicSize size_) { void MarkAtomic() {
size = size_; MarkWrite();
MarkRead();
is_atomic = true;
} }
constexpr std::size_t GetOffset() const { constexpr std::size_t GetOffset() const {
@ -347,21 +345,17 @@ public:
return is_read; return is_read;
} }
constexpr bool IsAtomic() const {
return is_atomic;
}
constexpr std::pair<u32, u32> GetBindlessCBuf() const { constexpr std::pair<u32, u32> GetBindlessCBuf() const {
return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
} }
constexpr bool IsSizeKnown() const {
return size.has_value();
}
constexpr Tegra::Shader::ImageAtomicSize GetSize() const {
return size.value();
}
constexpr bool operator<(const Image& rhs) const { constexpr bool operator<(const Image& rhs) const {
return std::tie(offset, index, type, size, is_bindless) < return std::tie(offset, index, type, is_bindless) <
std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless); std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless);
} }
private: private:
@ -371,7 +365,7 @@ private:
bool is_bindless{}; bool is_bindless{};
bool is_written{}; bool is_written{};
bool is_read{}; bool is_read{};
std::optional<Tegra::Shader::ImageAtomicSize> size{}; bool is_atomic{};
}; };
struct GlobalMemoryBase { struct GlobalMemoryBase {

View file

@ -276,16 +276,13 @@ private:
bool is_shadow); bool is_shadow);
/// Accesses an image. /// Accesses an image.
Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
std::optional<Tegra::Shader::ImageAtomicSize> size = {});
/// Access a bindless image sampler. /// Access a bindless image sampler.
Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
std::optional<Tegra::Shader::ImageAtomicSize> size = {});
/// Tries to access an existing image, updating it's state as needed /// Tries to access an existing image, updating it's state as needed
Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type);
std::optional<Tegra::Shader::ImageAtomicSize> size);
/// Extracts a sequence of bits from a node /// Extracts a sequence of bits from a node
Node BitfieldExtract(Node value, u32 offset, u32 bits); Node BitfieldExtract(Node value, u32 offset, u32 bits);