summaryrefslogtreecommitdiff
path: root/src/video_core/shader
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-07-17 21:03:53 -0300
committerGravatar ReinUsesLisp2019-09-10 20:22:31 -0300
commit36abf67e79b234a361b99a342391249095ccd79c (patch)
tree3e6e0e818e952a038fbe10262bf39cf6d52eaa61 /src/video_core/shader
parentMerge pull request #2823 from ReinUsesLisp/shr-clamp (diff)
downloadyuzu-36abf67e79b234a361b99a342391249095ccd79c.tar.gz
yuzu-36abf67e79b234a361b99a342391249095ccd79c.tar.xz
yuzu-36abf67e79b234a361b99a342391249095ccd79c.zip
shader/image: Implement SUATOM and fix SUST
Diffstat (limited to 'src/video_core/shader')
-rw-r--r--src/video_core/shader/decode/image.cpp92
-rw-r--r--src/video_core/shader/node.h57
-rw-r--r--src/video_core/shader/shader_ir.h10
3 files changed, 122 insertions, 37 deletions
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp
index 008109a99..d54fb88c9 100644
--- a/src/video_core/shader/decode/image.cpp
+++ b/src/video_core/shader/decode/image.cpp
@@ -44,7 +44,6 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
44 switch (opcode->get().GetId()) { 44 switch (opcode->get().GetId()) {
45 case OpCode::Id::SUST: { 45 case OpCode::Id::SUST: {
46 UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P); 46 UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P);
47 UNIMPLEMENTED_IF(instr.sust.image_type == Tegra::Shader::ImageType::TextureBuffer);
48 UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore); 47 UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore);
49 UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store 48 UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store
50 49
@@ -66,8 +65,46 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
66 image.MarkWrite(); 65 image.MarkWrite();
67 66
68 MetaImage meta{image, values}; 67 MetaImage meta{image, values};
69 const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))}; 68 bb.push_back(Operation(OperationCode::ImageStore, meta, std::move(coords)));
70 bb.push_back(store); 69 break;
70 }
71 case OpCode::Id::SUATOM: {
72 UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0);
73
74 Node value = GetRegister(instr.gpr0);
75
76 std::vector<Node> coords;
77 const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)};
78 for (std::size_t i = 0; i < num_coords; ++i) {
79 coords.push_back(GetRegister(instr.gpr8.Value() + i));
80 }
81
82 const OperationCode operation_code = [instr] {
83 switch (instr.suatom_d.operation) {
84 case Tegra::Shader::ImageAtomicOperation::Add:
85 return OperationCode::AtomicImageAdd;
86 case Tegra::Shader::ImageAtomicOperation::Min:
87 return OperationCode::AtomicImageMin;
88 case Tegra::Shader::ImageAtomicOperation::Max:
89 return OperationCode::AtomicImageMax;
90 case Tegra::Shader::ImageAtomicOperation::And:
91 return OperationCode::AtomicImageAnd;
92 case Tegra::Shader::ImageAtomicOperation::Or:
93 return OperationCode::AtomicImageOr;
94 case Tegra::Shader::ImageAtomicOperation::Xor:
95 return OperationCode::AtomicImageXor;
96 case Tegra::Shader::ImageAtomicOperation::Exch:
97 return OperationCode::AtomicImageExchange;
98 default:
99 UNIMPLEMENTED_MSG("Unimplemented operation={}",
100 static_cast<u32>(instr.suatom_d.operation.Value()));
101 return OperationCode::AtomicImageAdd;
102 }
103 }();
104
105 const auto& image{GetImage(instr.image, instr.suatom_d.image_type, instr.suatom_d.size)};
106 MetaImage meta{image, {std::move(value)}};
107 SetRegister(bb, instr.gpr0, Operation(operation_code, meta, std::move(coords)));
71 break; 108 break;
72 } 109 }
73 default: 110 default:
@@ -77,38 +114,51 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
77 return pc; 114 return pc;
78} 115}
79 116
80Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { 117Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
81 const auto offset{static_cast<u64>(image.index.Value())}; 118 std::optional<Tegra::Shader::ImageAtomicSize> size) {
82 119 const auto offset{static_cast<std::size_t>(image.index.Value())};
83 // If this image has already been used, return the existing mapping. 120 if (const auto image = TryUseExistingImage(offset, type, size)) {
84 const auto it = used_images.find(offset); 121 return *image;
85 if (it != used_images.end()) {
86 ASSERT(it->second.GetType() == type);
87 return it->second;
88 } 122 }
89 123
90 // Otherwise create a new mapping for this image.
91 const std::size_t next_index{used_images.size()}; 124 const std::size_t next_index{used_images.size()};
92 return used_images.emplace(offset, Image{offset, next_index, type}).first->second; 125 return used_images.emplace(offset, Image{offset, next_index, type, size}).first->second;
93} 126}
94 127
95Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) { 128Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type,
129 std::optional<Tegra::Shader::ImageAtomicSize> size) {
96 const Node image_register{GetRegister(reg)}; 130 const Node image_register{GetRegister(reg)};
97 const auto [base_image, cbuf_index, cbuf_offset]{ 131 const auto [base_image, cbuf_index, cbuf_offset]{
98 TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; 132 TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
99 const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; 133 const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
100 134
101 // If this image has already been used, return the existing mapping. 135 if (const auto image = TryUseExistingImage(cbuf_key, type, size)) {
102 const auto it = used_images.find(cbuf_key); 136 return *image;
103 if (it != used_images.end()) {
104 ASSERT(it->second.GetType() == type);
105 return it->second;
106 } 137 }
107 138
108 // Otherwise create a new mapping for this image.
109 const std::size_t next_index{used_images.size()}; 139 const std::size_t next_index{used_images.size()};
110 return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type}) 140 return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type, size})
111 .first->second; 141 .first->second;
112} 142}
113 143
144Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
145 std::optional<Tegra::Shader::ImageAtomicSize> size) {
146 auto it = used_images.find(offset);
147 if (it == used_images.end()) {
148 return nullptr;
149 }
150 auto& image = it->second;
151 ASSERT(image.GetType() == type);
152
153 if (size) {
154 // We know the size, if it's known it has to be the same as before, otherwise we can set it.
155 if (image.IsSizeKnown()) {
156 ASSERT(image.GetSize() == size);
157 } else {
158 image.SetSize(*size);
159 }
160 }
161 return &image;
162}
163
114} // namespace VideoCommon::Shader 164} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index b29aedce8..b47b201cf 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <memory> 9#include <memory>
10#include <optional>
10#include <string> 11#include <string>
11#include <tuple> 12#include <tuple>
12#include <utility> 13#include <utility>
@@ -148,7 +149,14 @@ enum class OperationCode {
148 TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 149 TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
149 TexelFetch, /// (MetaTexture, int[N], int) -> float4 150 TexelFetch, /// (MetaTexture, int[N], int) -> float4
150 151
151 ImageStore, /// (MetaImage, float[N] coords) -> void 152 ImageStore, /// (MetaImage, int[N] values) -> void
153 AtomicImageAdd, /// (MetaImage, int[N] coords) -> void
154 AtomicImageMin, /// (MetaImage, int[N] coords) -> void
155 AtomicImageMax, /// (MetaImage, int[N] coords) -> void
156 AtomicImageAnd, /// (MetaImage, int[N] coords) -> void
157 AtomicImageOr, /// (MetaImage, int[N] coords) -> void
158 AtomicImageXor, /// (MetaImage, int[N] coords) -> void
159 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
152 160
153 Branch, /// (uint branch_target) -> void 161 Branch, /// (uint branch_target) -> void
154 BranchIndirect, /// (uint branch_target) -> void 162 BranchIndirect, /// (uint branch_target) -> void
@@ -275,25 +283,32 @@ private:
275 283
276class Image final { 284class Image final {
277public: 285public:
278 constexpr explicit Image(u64 offset, std::size_t index, Tegra::Shader::ImageType type) 286 constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
279 : offset{offset}, index{index}, type{type}, is_bindless{false} {} 287 std::optional<Tegra::Shader::ImageAtomicSize> size)
288 : offset{offset}, index{index}, type{type}, is_bindless{false}, size{size} {}
280 289
281 constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, 290 constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
282 Tegra::Shader::ImageType type) 291 Tegra::Shader::ImageType type,
292 std::optional<Tegra::Shader::ImageAtomicSize> size)
283 : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, 293 : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
284 is_bindless{true} {} 294 is_bindless{true}, size{size} {}
285 295
286 constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, 296 constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
287 bool is_bindless, bool is_written, bool is_read) 297 bool is_bindless, bool is_written, bool is_read,
298 std::optional<Tegra::Shader::ImageAtomicSize> size)
288 : offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, 299 : offset{offset}, index{index}, type{type}, is_bindless{is_bindless},
289 is_written{is_written}, is_read{is_read} {} 300 is_written{is_written}, is_read{is_read}, size{size} {}
301
302 void MarkWrite() {
303 is_written = true;
304 }
290 305
291 void MarkRead() { 306 void MarkRead() {
292 is_read = true; 307 is_read = true;
293 } 308 }
294 309
295 void MarkWrite() { 310 void SetSize(Tegra::Shader::ImageAtomicSize size_) {
296 is_written = true; 311 size = size_;
297 } 312 }
298 313
299 constexpr std::size_t GetOffset() const { 314 constexpr std::size_t GetOffset() const {
@@ -312,25 +327,39 @@ public:
312 return is_bindless; 327 return is_bindless;
313 } 328 }
314 329
315 constexpr bool IsRead() const {
316 return is_read;
317 }
318
319 constexpr bool IsWritten() const { 330 constexpr bool IsWritten() const {
320 return is_written; 331 return is_written;
321 } 332 }
322 333
334 constexpr bool IsRead() const {
335 return is_read;
336 }
337
323 constexpr std::pair<u32, u32> GetBindlessCBuf() const { 338 constexpr std::pair<u32, u32> GetBindlessCBuf() const {
324 return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; 339 return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
325 } 340 }
326 341
342 constexpr bool IsSizeKnown() const {
343 return size.has_value();
344 }
345
346 constexpr Tegra::Shader::ImageAtomicSize GetSize() const {
347 return size.value();
348 }
349
350 constexpr bool operator<(const Image& rhs) const {
351 return std::tie(offset, index, type, size, is_bindless) <
352 std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless);
353 }
354
327private: 355private:
328 u64 offset{}; 356 u64 offset{};
329 std::size_t index{}; 357 std::size_t index{};
330 Tegra::Shader::ImageType type{}; 358 Tegra::Shader::ImageType type{};
331 bool is_bindless{}; 359 bool is_bindless{};
332 bool is_read{};
333 bool is_written{}; 360 bool is_written{};
361 bool is_read{};
362 std::optional<Tegra::Shader::ImageAtomicSize> size{};
334}; 363};
335 364
336struct GlobalMemoryBase { 365struct GlobalMemoryBase {
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 0f891eace..62816bd56 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -272,10 +272,16 @@ private:
272 bool is_shadow); 272 bool is_shadow);
273 273
274 /// Accesses an image. 274 /// Accesses an image.
275 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); 275 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
276 std::optional<Tegra::Shader::ImageAtomicSize> size = {});
276 277
277 /// Access a bindless image sampler. 278 /// Access a bindless image sampler.
278 Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type); 279 Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type,
280 std::optional<Tegra::Shader::ImageAtomicSize> size = {});
281
282 /// Tries to access an existing image, updating it's state as needed
283 Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
284 std::optional<Tegra::Shader::ImageAtomicSize> size);
279 285
280 /// Extracts a sequence of bits from a node 286 /// Extracts a sequence of bits from a node
281 Node BitfieldExtract(Node value, u32 offset, u32 bits); 287 Node BitfieldExtract(Node value, u32 offset, u32 bits);