diff options
Diffstat (limited to 'src/video_core/shader')
| -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) { | |||
| 41 | const Instruction instr = {program_code[pc]}; | 41 | const Instruction instr = {program_code[pc]}; |
| 42 | const auto opcode = OpCode::Decode(instr); | 42 | const auto opcode = OpCode::Decode(instr); |
| 43 | 43 | ||
| 44 | const auto GetCoordinates = [this, instr](Tegra::Shader::ImageType image_type) { | ||
| 45 | std::vector<Node> coords; | ||
| 46 | const std::size_t num_coords{GetImageTypeNumCoordinates(image_type)}; | ||
| 47 | coords.reserve(num_coords); | ||
| 48 | for (std::size_t i = 0; i < num_coords; ++i) { | ||
| 49 | coords.push_back(GetRegister(instr.gpr8.Value() + i)); | ||
| 50 | } | ||
| 51 | return coords; | ||
| 52 | }; | ||
| 53 | |||
| 44 | switch (opcode->get().GetId()) { | 54 | switch (opcode->get().GetId()) { |
| 55 | case OpCode::Id::SULD: { | ||
| 56 | UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P); | ||
| 57 | UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != | ||
| 58 | Tegra::Shader::OutOfBoundsStore::Ignore); | ||
| 59 | |||
| 60 | const auto type{instr.suldst.image_type}; | ||
| 61 | auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type) | ||
| 62 | : GetBindlessImage(instr.gpr39, type)}; | ||
| 63 | image.MarkRead(); | ||
| 64 | |||
| 65 | u32 indexer = 0; | ||
| 66 | for (u32 element = 0; element < 4; ++element) { | ||
| 67 | if (!instr.suldst.IsComponentEnabled(element)) { | ||
| 68 | continue; | ||
| 69 | } | ||
| 70 | MetaImage meta{image, {}, element}; | ||
| 71 | Node value = Operation(OperationCode::ImageLoad, meta, GetCoordinates(type)); | ||
| 72 | SetTemporary(bb, indexer++, std::move(value)); | ||
| 73 | } | ||
| 74 | for (u32 i = 0; i < indexer; ++i) { | ||
| 75 | SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i)); | ||
| 76 | } | ||
| 77 | break; | ||
| 78 | } | ||
| 45 | case OpCode::Id::SUST: { | 79 | case OpCode::Id::SUST: { |
| 46 | UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P); | 80 | UNIMPLEMENTED_IF(instr.suldst.mode != Tegra::Shader::SurfaceDataMode::P); |
| 47 | UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore); | 81 | UNIMPLEMENTED_IF(instr.suldst.out_of_bounds_store != |
| 48 | UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store | 82 | Tegra::Shader::OutOfBoundsStore::Ignore); |
| 83 | UNIMPLEMENTED_IF(instr.suldst.component_mask_selector != 0xf); // Ensure we have RGBA | ||
| 49 | 84 | ||
| 50 | std::vector<Node> values; | 85 | std::vector<Node> values; |
| 51 | constexpr std::size_t hardcoded_size{4}; | 86 | constexpr std::size_t hardcoded_size{4}; |
| @@ -53,58 +88,51 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 53 | values.push_back(GetRegister(instr.gpr0.Value() + i)); | 88 | values.push_back(GetRegister(instr.gpr0.Value() + i)); |
| 54 | } | 89 | } |
| 55 | 90 | ||
| 56 | std::vector<Node> coords; | 91 | const auto type{instr.suldst.image_type}; |
| 57 | const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)}; | 92 | auto& image{instr.suldst.is_immediate ? GetImage(instr.image, type) |
| 58 | for (std::size_t i = 0; i < num_coords; ++i) { | 93 | : GetBindlessImage(instr.gpr39, type)}; |
| 59 | coords.push_back(GetRegister(instr.gpr8.Value() + i)); | ||
| 60 | } | ||
| 61 | |||
| 62 | const auto type{instr.sust.image_type}; | ||
| 63 | auto& image{instr.sust.is_immediate ? GetImage(instr.image, type) | ||
| 64 | : GetBindlessImage(instr.gpr39, type)}; | ||
| 65 | image.MarkWrite(); | 94 | image.MarkWrite(); |
| 66 | 95 | ||
| 67 | MetaImage meta{image, values}; | 96 | MetaImage meta{image, std::move(values)}; |
| 68 | bb.push_back(Operation(OperationCode::ImageStore, meta, std::move(coords))); | 97 | bb.push_back(Operation(OperationCode::ImageStore, meta, GetCoordinates(type))); |
| 69 | break; | 98 | break; |
| 70 | } | 99 | } |
| 71 | case OpCode::Id::SUATOM: { | 100 | case OpCode::Id::SUATOM: { |
| 72 | UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); | 101 | UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0); |
| 73 | 102 | ||
| 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] { | 103 | const OperationCode operation_code = [instr] { |
| 83 | switch (instr.suatom_d.operation) { | 104 | switch (instr.suatom_d.operation_type) { |
| 84 | case Tegra::Shader::ImageAtomicOperation::Add: | 105 | case Tegra::Shader::ImageAtomicOperationType::S32: |
| 85 | return OperationCode::AtomicImageAdd; | 106 | case Tegra::Shader::ImageAtomicOperationType::U32: |
| 86 | case Tegra::Shader::ImageAtomicOperation::Min: | 107 | switch (instr.suatom_d.operation) { |
| 87 | return OperationCode::AtomicImageMin; | 108 | case Tegra::Shader::ImageAtomicOperation::Add: |
| 88 | case Tegra::Shader::ImageAtomicOperation::Max: | 109 | return OperationCode::AtomicImageAdd; |
| 89 | return OperationCode::AtomicImageMax; | 110 | case Tegra::Shader::ImageAtomicOperation::And: |
| 90 | case Tegra::Shader::ImageAtomicOperation::And: | 111 | return OperationCode::AtomicImageAnd; |
| 91 | return OperationCode::AtomicImageAnd; | 112 | case Tegra::Shader::ImageAtomicOperation::Or: |
| 92 | case Tegra::Shader::ImageAtomicOperation::Or: | 113 | return OperationCode::AtomicImageOr; |
| 93 | return OperationCode::AtomicImageOr; | 114 | case Tegra::Shader::ImageAtomicOperation::Xor: |
| 94 | case Tegra::Shader::ImageAtomicOperation::Xor: | 115 | return OperationCode::AtomicImageXor; |
| 95 | return OperationCode::AtomicImageXor; | 116 | case Tegra::Shader::ImageAtomicOperation::Exch: |
| 96 | case Tegra::Shader::ImageAtomicOperation::Exch: | 117 | return OperationCode::AtomicImageExchange; |
| 97 | return OperationCode::AtomicImageExchange; | 118 | } |
| 98 | default: | 119 | default: |
| 99 | UNIMPLEMENTED_MSG("Unimplemented operation={}", | 120 | break; |
| 100 | static_cast<u32>(instr.suatom_d.operation.Value())); | ||
| 101 | return OperationCode::AtomicImageAdd; | ||
| 102 | } | 121 | } |
| 122 | UNIMPLEMENTED_MSG("Unimplemented operation={} type={}", | ||
| 123 | static_cast<u64>(instr.suatom_d.operation.Value()), | ||
| 124 | static_cast<u64>(instr.suatom_d.operation_type.Value())); | ||
| 125 | return OperationCode::AtomicImageAdd; | ||
| 103 | }(); | 126 | }(); |
| 104 | 127 | ||
| 105 | const auto& image{GetImage(instr.image, instr.suatom_d.image_type, instr.suatom_d.size)}; | 128 | Node value = GetRegister(instr.gpr0); |
| 129 | |||
| 130 | const auto type = instr.suatom_d.image_type; | ||
| 131 | auto& image = GetImage(instr.image, type); | ||
| 132 | image.MarkAtomic(); | ||
| 133 | |||
| 106 | MetaImage meta{image, {std::move(value)}}; | 134 | MetaImage meta{image, {std::move(value)}}; |
| 107 | SetRegister(bb, instr.gpr0, Operation(operation_code, meta, std::move(coords))); | 135 | SetRegister(bb, instr.gpr0, Operation(operation_code, meta, GetCoordinates(type))); |
| 108 | break; | 136 | break; |
| 109 | } | 137 | } |
| 110 | default: | 138 | default: |
| @@ -114,35 +142,32 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { | |||
| 114 | return pc; | 142 | return pc; |
| 115 | } | 143 | } |
| 116 | 144 | ||
| 117 | Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, | 145 | Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { |
| 118 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 119 | const auto offset{static_cast<std::size_t>(image.index.Value())}; | 146 | const auto offset{static_cast<std::size_t>(image.index.Value())}; |
| 120 | if (const auto image = TryUseExistingImage(offset, type, size)) { | 147 | if (const auto image = TryUseExistingImage(offset, type)) { |
| 121 | return *image; | 148 | return *image; |
| 122 | } | 149 | } |
| 123 | 150 | ||
| 124 | const std::size_t next_index{used_images.size()}; | 151 | const std::size_t next_index{used_images.size()}; |
| 125 | return used_images.emplace(offset, Image{offset, next_index, type, size}).first->second; | 152 | return used_images.emplace(offset, Image{offset, next_index, type}).first->second; |
| 126 | } | 153 | } |
| 127 | 154 | ||
| 128 | Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, | 155 | Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) { |
| 129 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 130 | const Node image_register{GetRegister(reg)}; | 156 | const Node image_register{GetRegister(reg)}; |
| 131 | const auto [base_image, cbuf_index, cbuf_offset]{ | 157 | const auto [base_image, cbuf_index, cbuf_offset]{ |
| 132 | TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; | 158 | TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; |
| 133 | const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; | 159 | const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; |
| 134 | 160 | ||
| 135 | if (const auto image = TryUseExistingImage(cbuf_key, type, size)) { | 161 | if (const auto image = TryUseExistingImage(cbuf_key, type)) { |
| 136 | return *image; | 162 | return *image; |
| 137 | } | 163 | } |
| 138 | 164 | ||
| 139 | const std::size_t next_index{used_images.size()}; | 165 | const std::size_t next_index{used_images.size()}; |
| 140 | return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type, size}) | 166 | return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type}) |
| 141 | .first->second; | 167 | .first->second; |
| 142 | } | 168 | } |
| 143 | 169 | ||
| 144 | Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | 170 | Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type) { |
| 145 | std::optional<Tegra::Shader::ImageAtomicSize> size) { | ||
| 146 | auto it = used_images.find(offset); | 171 | auto it = used_images.find(offset); |
| 147 | if (it == used_images.end()) { | 172 | if (it == used_images.end()) { |
| 148 | return nullptr; | 173 | return nullptr; |
| @@ -150,14 +175,6 @@ Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | |||
| 150 | auto& image = it->second; | 175 | auto& image = it->second; |
| 151 | ASSERT(image.GetType() == type); | 176 | ASSERT(image.GetType() == type); |
| 152 | 177 | ||
| 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 ℑ | 178 | return ℑ |
| 162 | } | 179 | } |
| 163 | 180 | ||
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 { | |||
| 149 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 | 149 | TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 |
| 150 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 | 150 | TexelFetch, /// (MetaTexture, int[N], int) -> float4 |
| 151 | 151 | ||
| 152 | ImageStore, /// (MetaImage, int[N] values) -> void | 152 | ImageLoad, /// (MetaImage, int[N] coords) -> void |
| 153 | ImageStore, /// (MetaImage, int[N] coords) -> void | ||
| 154 | |||
| 153 | AtomicImageAdd, /// (MetaImage, int[N] coords) -> void | 155 | 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 | 156 | AtomicImageAnd, /// (MetaImage, int[N] coords) -> void |
| 157 | AtomicImageOr, /// (MetaImage, int[N] coords) -> void | 157 | AtomicImageOr, /// (MetaImage, int[N] coords) -> void |
| 158 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void | 158 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void |
| @@ -294,21 +294,18 @@ private: | |||
| 294 | 294 | ||
| 295 | class Image final { | 295 | class Image final { |
| 296 | public: | 296 | public: |
| 297 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, | 297 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type) |
| 298 | std::optional<Tegra::Shader::ImageAtomicSize> size) | 298 | : offset{offset}, index{index}, type{type}, is_bindless{false} {} |
| 299 | : offset{offset}, index{index}, type{type}, is_bindless{false}, size{size} {} | ||
| 300 | 299 | ||
| 301 | constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, | 300 | constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, |
| 302 | Tegra::Shader::ImageType type, | 301 | Tegra::Shader::ImageType type) |
| 303 | std::optional<Tegra::Shader::ImageAtomicSize> size) | ||
| 304 | : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, | 302 | : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, |
| 305 | is_bindless{true}, size{size} {} | 303 | is_bindless{true} {} |
| 306 | 304 | ||
| 307 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, | 305 | constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, |
| 308 | bool is_bindless, bool is_written, bool is_read, | 306 | bool is_bindless, bool is_written, bool is_read, bool is_atomic) |
| 309 | std::optional<Tegra::Shader::ImageAtomicSize> size) | ||
| 310 | : offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, | 307 | : offset{offset}, index{index}, type{type}, is_bindless{is_bindless}, |
| 311 | is_written{is_written}, is_read{is_read}, size{size} {} | 308 | is_written{is_written}, is_read{is_read}, is_atomic{is_atomic} {} |
| 312 | 309 | ||
| 313 | void MarkWrite() { | 310 | void MarkWrite() { |
| 314 | is_written = true; | 311 | is_written = true; |
| @@ -318,8 +315,10 @@ public: | |||
| 318 | is_read = true; | 315 | is_read = true; |
| 319 | } | 316 | } |
| 320 | 317 | ||
| 321 | void SetSize(Tegra::Shader::ImageAtomicSize size_) { | 318 | void MarkAtomic() { |
| 322 | size = size_; | 319 | MarkWrite(); |
| 320 | MarkRead(); | ||
| 321 | is_atomic = true; | ||
| 323 | } | 322 | } |
| 324 | 323 | ||
| 325 | constexpr std::size_t GetOffset() const { | 324 | constexpr std::size_t GetOffset() const { |
| @@ -346,21 +345,17 @@ public: | |||
| 346 | return is_read; | 345 | return is_read; |
| 347 | } | 346 | } |
| 348 | 347 | ||
| 349 | constexpr std::pair<u32, u32> GetBindlessCBuf() const { | 348 | constexpr bool IsAtomic() const { |
| 350 | return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; | 349 | return is_atomic; |
| 351 | } | 350 | } |
| 352 | 351 | ||
| 353 | constexpr bool IsSizeKnown() const { | 352 | constexpr std::pair<u32, u32> GetBindlessCBuf() const { |
| 354 | return size.has_value(); | 353 | return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; |
| 355 | } | ||
| 356 | |||
| 357 | constexpr Tegra::Shader::ImageAtomicSize GetSize() const { | ||
| 358 | return size.value(); | ||
| 359 | } | 354 | } |
| 360 | 355 | ||
| 361 | constexpr bool operator<(const Image& rhs) const { | 356 | constexpr bool operator<(const Image& rhs) const { |
| 362 | return std::tie(offset, index, type, size, is_bindless) < | 357 | return std::tie(offset, index, type, is_bindless) < |
| 363 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless); | 358 | std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless); |
| 364 | } | 359 | } |
| 365 | 360 | ||
| 366 | private: | 361 | private: |
| @@ -370,7 +365,7 @@ private: | |||
| 370 | bool is_bindless{}; | 365 | bool is_bindless{}; |
| 371 | bool is_written{}; | 366 | bool is_written{}; |
| 372 | bool is_read{}; | 367 | bool is_read{}; |
| 373 | std::optional<Tegra::Shader::ImageAtomicSize> size{}; | 368 | bool is_atomic{}; |
| 374 | }; | 369 | }; |
| 375 | 370 | ||
| 376 | struct GlobalMemoryBase { | 371 | struct GlobalMemoryBase { |
| @@ -402,6 +397,7 @@ struct MetaTexture { | |||
| 402 | struct MetaImage { | 397 | struct MetaImage { |
| 403 | const Image& image; | 398 | const Image& image; |
| 404 | std::vector<Node> values; | 399 | std::vector<Node> values; |
| 400 | u32 element{}; | ||
| 405 | }; | 401 | }; |
| 406 | 402 | ||
| 407 | /// Parameters that modify an operation but are not part of any particular operand | 403 | /// 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: | |||
| 284 | bool is_shadow); | 284 | bool is_shadow); |
| 285 | 285 | ||
| 286 | /// Accesses an image. | 286 | /// Accesses an image. |
| 287 | Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type, | 287 | Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); |
| 288 | std::optional<Tegra::Shader::ImageAtomicSize> size = {}); | ||
| 289 | 288 | ||
| 290 | /// Access a bindless image sampler. | 289 | /// Access a bindless image sampler. |
| 291 | Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type, | 290 | Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type); |
| 292 | std::optional<Tegra::Shader::ImageAtomicSize> size = {}); | ||
| 293 | 291 | ||
| 294 | /// Tries to access an existing image, updating it's state as needed | 292 | /// Tries to access an existing image, updating it's state as needed |
| 295 | Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type, | 293 | Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type); |
| 296 | std::optional<Tegra::Shader::ImageAtomicSize> size); | ||
| 297 | 294 | ||
| 298 | /// Extracts a sequence of bits from a node | 295 | /// Extracts a sequence of bits from a node |
| 299 | Node BitfieldExtract(Node value, u32 offset, u32 bits); | 296 | Node BitfieldExtract(Node value, u32 offset, u32 bits); |