diff options
Diffstat (limited to '')
-rw-r--r-- | src/video_core/shader/decode/image.cpp | 137 | ||||
-rw-r--r-- | src/video_core/shader/node.h | 46 | ||||
-rw-r--r-- | src/video_core/shader/shader_ir.h | 9 |
3 files changed, 101 insertions, 91 deletions
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index d54fb88c9..95ec1cdd9 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp @@ -41,11 +41,46 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { const Instruction instr = {program_code[pc]}; const auto opcode = OpCode::Decode(instr); + const auto GetCoordinates = [this, instr](Tegra::Shader::ImageType image_type) { + std::vector<Node> coords; + const std::size_t num_coords{GetImageTypeNumCoordinates(image_type)}; + coords.reserve(num_coords); + for (std::size_t i = 0; i < num_coords; ++i) { + coords.push_back(GetRegister(instr.gpr8.Value() + i)); + } + return coords; + }; + switch (opcode->get().GetId()) { + case OpCode::Id::SULD: { + UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P); + UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != + Tegra::Shader::OutOfBoundsStore::Ignore); + + const auto type{instr.suldst.image_type}; + auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type) + : GetBindlessImage(instr.gpr39, type)}; + image.MarkRead(); + + u32 indexer = 0; + for (u32 element = 0; element < 4; ++element) { + if (!instr.suldst.IsComponentEnabled(element)) { + continue; + } + MetaImage meta{image, {}, element}; + Node value = Operation(OperationCode::ImageLoad, meta, GetCoordinates(type)); + SetTemporary(bb, indexer++, std::move(value)); + } + for (u32 i = 0; i < indexer; ++i) { + SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i)); + } + break; + } case OpCode::Id::SUST: { - UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P); - UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore); - UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store + UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P); + UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != + Tegra::Shader::OutOfBoundsStore::Ignore); + UNIMPLEMENTED_IF(instr.suldst.component_mask_selector != 0xf); // Ensure we have RGBA std::vector<Node> values; constexpr std::size_t hardcoded_size{4}; @@ -53,58 +88,51 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { values.push_back(GetRegister(instr.gpr0.Value() + i)); } - std::vector<Node> coords; - const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)}; - for (std::size_t i = 0; i < num_coords; ++i) { - coords.push_back(GetRegister(instr.gpr8.Value() + i)); - } - - const auto type{instr.sust.image_type}; - auto& image{instr.sust.is_immediate ? GetImage(instr.image, type) - : GetBindlessImage(instr.gpr39, type)}; + const auto type{instr.suldst.image_type}; + auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type) + : GetBindlessImage(instr.gpr39, type)}; image.MarkWrite(); - MetaImage meta{image, values}; - bb.push_back(Operation(OperationCode::ImageStore, meta, std::move(coords))); + MetaImage meta{image, std::move(values)}; + bb.push_back(Operation(OperationCode::ImageStore, meta, GetCoordinates(type))); break; } case OpCode::Id::SUATOM: { UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); - Node value = GetRegister(instr.gpr0); - - std::vector<Node> coords; - const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)}; - for (std::size_t i = 0; i < num_coords; ++i) { - coords.push_back(GetRegister(instr.gpr8.Value() + i)); - } - 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; }(); - const auto& image{GetImage(instr.image, instr.suatom_d.image_type, instr.suatom_d.size)}; + Node value = GetRegister(instr.gpr0); + + const auto type = instr.suatom_d.image_type; + auto& image = GetImage(instr.image, type); + image.MarkAtomic(); + MetaImage meta{image, {std::move(value)}}; - SetRegister(bb, instr.gpr0, Operation(operation_code, meta, std::move(coords))); + SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type))); break; } default: @@ -114,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; @@ -150,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 ℑ } diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index abf2cb1ab..338bab17c 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h @@ -149,10 +149,10 @@ enum class OperationCode { TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 TexelFetch, /// (MetaTexture, int[N], int) -> float4 - ImageStore, /// (MetaImage, int[N] values) -> 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 @@ -294,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; @@ -318,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 { @@ -346,21 +345,17 @@ public: return is_read; } - constexpr std::pair<u32, u32> GetBindlessCBuf() const { - return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; + constexpr bool IsAtomic() const { + return is_atomic; } - constexpr bool IsSizeKnown() const { - return size.has_value(); - } - - constexpr Tegra::Shader::ImageAtomicSize GetSize() const { - return size.value(); + constexpr std::pair<u32, u32> GetBindlessCBuf() const { + return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; } 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: @@ -370,7 +365,7 @@ private: bool is_bindless{}; bool is_written{}; bool is_read{}; - std::optional<Tegra::Shader::ImageAtomicSize> size{}; + bool is_atomic{}; }; struct GlobalMemoryBase { @@ -402,6 +397,7 @@ struct MetaTexture { struct MetaImage { const Image& image; std::vector<Node> values; + u32 element{}; }; /// Parameters that modify an operation but are not part of any particular operand diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 2f03d83ba..6f666ee30 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -284,16 +284,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); |