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
7 changed files with 93 additions and 188 deletions

View File

@ -101,32 +101,35 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0);
const OperationCode operation_code = [instr] {
switch (instr.suatom_d.operation) {
case Tegra::Shader::ImageAtomicOperation::Add:
return OperationCode::AtomicImageAdd;
case Tegra::Shader::ImageAtomicOperation::Min:
return OperationCode::AtomicImageMin;
case Tegra::Shader::ImageAtomicOperation::Max:
return OperationCode::AtomicImageMax;
case Tegra::Shader::ImageAtomicOperation::And:
return OperationCode::AtomicImageAnd;
case Tegra::Shader::ImageAtomicOperation::Or:
return OperationCode::AtomicImageOr;
case Tegra::Shader::ImageAtomicOperation::Xor:
return OperationCode::AtomicImageXor;
case Tegra::Shader::ImageAtomicOperation::Exch:
return OperationCode::AtomicImageExchange;
switch (instr.suatom_d.operation_type) {
case Tegra::Shader::ImageAtomicOperationType::S32:
case Tegra::Shader::ImageAtomicOperationType::U32:
switch (instr.suatom_d.operation) {
case Tegra::Shader::ImageAtomicOperation::Add:
return OperationCode::AtomicImageAdd;
case Tegra::Shader::ImageAtomicOperation::And:
return OperationCode::AtomicImageAnd;
case Tegra::Shader::ImageAtomicOperation::Or:
return OperationCode::AtomicImageOr;
case Tegra::Shader::ImageAtomicOperation::Xor:
return OperationCode::AtomicImageXor;
case Tegra::Shader::ImageAtomicOperation::Exch:
return OperationCode::AtomicImageExchange;
}
default:
UNIMPLEMENTED_MSG("Unimplemented operation={}",
static_cast<u32>(instr.suatom_d.operation.Value()));
return OperationCode::AtomicImageAdd;
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);
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)}};
SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type)));
@ -139,35 +142,32 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
return pc;
}
Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
std::optional<Tegra::Shader::ImageAtomicSize> size) {
Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
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;
}
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,
std::optional<Tegra::Shader::ImageAtomicSize> size) {
Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
const Node image_register{GetRegister(reg)};
const auto [base_image, cbuf_index, cbuf_offset]{
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)};
if (const auto image = TryUseExistingImage(cbuf_key, type, size)) {
if (const auto image = TryUseExistingImage(cbuf_key, type)) {
return *image;
}
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;
}
Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
std::optional<Tegra::Shader::ImageAtomicSize> size) {
Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type) {
auto it = used_images.find(offset);
if (it == used_images.end()) {
return nullptr;
@ -175,14 +175,6 @@ Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
auto& image = it->second;
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;
}

View File

@ -149,11 +149,10 @@ enum class OperationCode {
TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
TexelFetch, /// (MetaTexture, int[N], int) -> float4
ImageLoad, /// (MetaImage, int[N] coords) -> void
ImageStore, /// (MetaImage, int[N] coords) -> void
ImageLoad, /// (MetaImage, int[N] coords) -> void
ImageStore, /// (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
AtomicImageOr, /// (MetaImage, int[N] coords) -> void
AtomicImageXor, /// (MetaImage, int[N] coords) -> void
@ -295,21 +294,18 @@ private:
class Image final {
public:
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}, size{size} {}
constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type)
: offset{offset}, index{index}, type{type}, is_bindless{false} {}
constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
Tegra::Shader::ImageType type,
std::optional<Tegra::Shader::ImageAtomicSize> size)
Tegra::Shader::ImageType 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,
bool is_bindless, bool is_written, bool is_read,
std::optional<Tegra::Shader::ImageAtomicSize> size)
bool is_bindless, bool is_written, bool is_read, bool is_atomic)
: 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() {
is_written = true;
@ -319,8 +315,10 @@ public:
is_read = true;
}
void SetSize(Tegra::Shader::ImageAtomicSize size_) {
size = size_;
void MarkAtomic() {
MarkWrite();
MarkRead();
is_atomic = true;
}
constexpr std::size_t GetOffset() const {
@ -347,21 +345,17 @@ public:
return is_read;
}
constexpr bool IsAtomic() const {
return is_atomic;
}
constexpr std::pair<u32, u32> GetBindlessCBuf() const {
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 {
return std::tie(offset, index, type, size, is_bindless) <
std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless);
return std::tie(offset, index, type, is_bindless) <
std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless);
}
private:
@ -371,7 +365,7 @@ private:
bool is_bindless{};
bool is_written{};
bool is_read{};
std::optional<Tegra::Shader::ImageAtomicSize> size{};
bool is_atomic{};
};
struct GlobalMemoryBase {

View File

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