diff options
| author | 2018-12-13 16:59:28 -0300 | |
|---|---|---|
| committer | 2019-01-15 17:54:50 -0300 | |
| commit | 2b90637f4bb0358525715c113f903d0c069b0eb4 (patch) | |
| tree | d9af8e549affccb86a250aec2217c9504ee71a12 /src | |
| parent | shader_decode: Implement TEXS (F32) (diff) | |
| download | yuzu-2b90637f4bb0358525715c113f903d0c069b0eb4.tar.gz yuzu-2b90637f4bb0358525715c113f903d0c069b0eb4.tar.xz yuzu-2b90637f4bb0358525715c113f903d0c069b0eb4.zip | |
shader_decode: Implement TEX and TXQ
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/shader/decode/memory.cpp | 219 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 4 |
2 files changed, 223 insertions, 0 deletions
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index 1f458b6d7..220238ce8 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 5 | #include <vector> | 6 | #include <vector> |
| 6 | 7 | ||
| 7 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| @@ -102,6 +103,44 @@ u32 ShaderIR::DecodeMemory(BasicBlock& bb, u32 pc) { | |||
| 102 | 103 | ||
| 103 | break; | 104 | break; |
| 104 | } | 105 | } |
| 106 | case OpCode::Id::TEX: { | ||
| 107 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; | ||
| 108 | const bool is_array = instr.tex.array != 0; | ||
| 109 | const bool depth_compare = instr.tex.UsesMiscMode(TextureMiscMode::DC); | ||
| 110 | const auto process_mode = instr.tex.GetTextureProcessMode(); | ||
| 111 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(TextureMiscMode::AOFFI), | ||
| 112 | "AOFFI is not implemented"); | ||
| 113 | |||
| 114 | if (instr.tex.UsesMiscMode(TextureMiscMode::NODEP)) { | ||
| 115 | LOG_WARNING(HW_GPU, "TEX.NODEP is not implemented"); | ||
| 116 | } | ||
| 117 | |||
| 118 | const Node texture = GetTexCode(instr, texture_type, process_mode, depth_compare, is_array); | ||
| 119 | |||
| 120 | if (depth_compare) { | ||
| 121 | SetRegister(bb, instr.gpr0, texture); | ||
| 122 | } else { | ||
| 123 | MetaComponents meta; | ||
| 124 | std::array<Node, 4> dest; | ||
| 125 | |||
| 126 | std::size_t dest_elem = 0; | ||
| 127 | for (std::size_t elem = 0; elem < 4; ++elem) { | ||
| 128 | if (!instr.tex.IsComponentEnabled(elem)) { | ||
| 129 | // Skip disabled components | ||
| 130 | continue; | ||
| 131 | } | ||
| 132 | meta.components_map[dest_elem] = static_cast<u32>(elem); | ||
| 133 | dest[dest_elem] = GetRegister(instr.gpr0.Value() + dest_elem); | ||
| 134 | |||
| 135 | ++dest_elem; | ||
| 136 | } | ||
| 137 | std::generate(dest.begin() + dest_elem, dest.end(), [&]() { return GetRegister(RZ); }); | ||
| 138 | |||
| 139 | bb.push_back(Operation(OperationCode::AssignComposite, std::move(meta), texture, | ||
| 140 | dest[0], dest[1], dest[2], dest[3])); | ||
| 141 | } | ||
| 142 | break; | ||
| 143 | } | ||
| 105 | case OpCode::Id::TEXS: { | 144 | case OpCode::Id::TEXS: { |
| 106 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; | 145 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; |
| 107 | const bool is_array{instr.texs.IsArrayTexture()}; | 146 | const bool is_array{instr.texs.IsArrayTexture()}; |
| @@ -123,6 +162,148 @@ u32 ShaderIR::DecodeMemory(BasicBlock& bb, u32 pc) { | |||
| 123 | } | 162 | } |
| 124 | break; | 163 | break; |
| 125 | } | 164 | } |
| 165 | case OpCode::Id::TLD4: { | ||
| 166 | ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); | ||
| 167 | ASSERT(instr.tld4.array == 0); | ||
| 168 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::AOFFI), | ||
| 169 | "AOFFI is not implemented"); | ||
| 170 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::NDV), | ||
| 171 | "NDV is not implemented"); | ||
| 172 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::PTP), | ||
| 173 | "PTP is not implemented"); | ||
| 174 | |||
| 175 | if (instr.tld4.UsesMiscMode(TextureMiscMode::NODEP)) { | ||
| 176 | LOG_WARNING(HW_GPU, "TLD4.NODEP implementation is incomplete"); | ||
| 177 | } | ||
| 178 | |||
| 179 | const bool depth_compare = instr.tld4.UsesMiscMode(TextureMiscMode::DC); | ||
| 180 | auto texture_type = instr.tld4.texture_type.Value(); | ||
| 181 | u32 num_coordinates = static_cast<u32>(GetCoordCount(texture_type)); | ||
| 182 | if (depth_compare) | ||
| 183 | num_coordinates += 1; | ||
| 184 | |||
| 185 | std::vector<Node> params; | ||
| 186 | |||
| 187 | switch (num_coordinates) { | ||
| 188 | case 2: { | ||
| 189 | params.push_back(GetRegister(instr.gpr8)); | ||
| 190 | params.push_back(GetRegister(instr.gpr8.Value() + 1)); | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | case 3: { | ||
| 194 | params.push_back(GetRegister(instr.gpr8)); | ||
| 195 | params.push_back(GetRegister(instr.gpr8.Value() + 1)); | ||
| 196 | params.push_back(GetRegister(instr.gpr8.Value() + 2)); | ||
| 197 | break; | ||
| 198 | } | ||
| 199 | default: | ||
| 200 | UNIMPLEMENTED_MSG("Unhandled coordinates number {}", static_cast<u32>(num_coordinates)); | ||
| 201 | params.push_back(GetRegister(instr.gpr8)); | ||
| 202 | params.push_back(GetRegister(instr.gpr8.Value() + 1)); | ||
| 203 | num_coordinates = 2; | ||
| 204 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 205 | } | ||
| 206 | params.push_back(Immediate(static_cast<u32>(instr.tld4.component))); | ||
| 207 | |||
| 208 | const auto& sampler = GetSampler(instr.sampler, texture_type, false, depth_compare); | ||
| 209 | const MetaTexture meta{sampler, num_coordinates}; | ||
| 210 | |||
| 211 | const Node texture = | ||
| 212 | Operation(OperationCode::F4TextureGather, std::move(meta), std::move(params)); | ||
| 213 | |||
| 214 | if (depth_compare) { | ||
| 215 | SetRegister(bb, instr.gpr0, texture); | ||
| 216 | } else { | ||
| 217 | MetaComponents meta; | ||
| 218 | std::array<Node, 4> dest; | ||
| 219 | |||
| 220 | std::size_t dest_elem = 0; | ||
| 221 | for (std::size_t elem = 0; elem < 4; ++elem) { | ||
| 222 | if (!instr.tex.IsComponentEnabled(elem)) { | ||
| 223 | // Skip disabled components | ||
| 224 | continue; | ||
| 225 | } | ||
| 226 | meta.components_map[dest_elem] = static_cast<u32>(elem); | ||
| 227 | dest[dest_elem] = GetRegister(instr.gpr0.Value() + dest_elem); | ||
| 228 | |||
| 229 | ++dest_elem; | ||
| 230 | } | ||
| 231 | std::generate(dest.begin() + dest_elem, dest.end(), [&]() { return GetRegister(RZ); }); | ||
| 232 | |||
| 233 | bb.push_back(Operation(OperationCode::AssignComposite, std::move(meta), texture, | ||
| 234 | dest[0], dest[1], dest[2], dest[3])); | ||
| 235 | } | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | case OpCode::Id::TLD4S: { | ||
| 239 | UNIMPLEMENTED_IF_MSG(instr.tld4s.UsesMiscMode(TextureMiscMode::AOFFI), | ||
| 240 | "AOFFI is not implemented"); | ||
| 241 | |||
| 242 | if (instr.tld4s.UsesMiscMode(TextureMiscMode::NODEP)) { | ||
| 243 | LOG_WARNING(HW_GPU, "TLD4S.NODEP is not implemented"); | ||
| 244 | } | ||
| 245 | |||
| 246 | const bool depth_compare = instr.tld4s.UsesMiscMode(TextureMiscMode::DC); | ||
| 247 | const Node op_a = GetRegister(instr.gpr8); | ||
| 248 | const Node op_b = GetRegister(instr.gpr20); | ||
| 249 | |||
| 250 | std::vector<Node> params; | ||
| 251 | |||
| 252 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | ||
| 253 | if (depth_compare) { | ||
| 254 | // Note: TLD4S coordinate encoding works just like TEXS's | ||
| 255 | const Node op_y = GetRegister(instr.gpr8.Value() + 1); | ||
| 256 | params.push_back(op_a); | ||
| 257 | params.push_back(op_y); | ||
| 258 | params.push_back(op_b); | ||
| 259 | } else { | ||
| 260 | params.push_back(op_a); | ||
| 261 | params.push_back(op_b); | ||
| 262 | } | ||
| 263 | const auto num_coords = static_cast<u32>(params.size()); | ||
| 264 | params.push_back(Immediate(static_cast<u32>(instr.tld4s.component))); | ||
| 265 | |||
| 266 | const auto& sampler = | ||
| 267 | GetSampler(instr.sampler, TextureType::Texture2D, false, depth_compare); | ||
| 268 | const MetaTexture meta{sampler, num_coords}; | ||
| 269 | |||
| 270 | WriteTexsInstructionFloat( | ||
| 271 | bb, instr, Operation(OperationCode::F4TextureGather, meta, std::move(params))); | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | case OpCode::Id::TXQ: { | ||
| 275 | if (instr.txq.UsesMiscMode(TextureMiscMode::NODEP)) { | ||
| 276 | LOG_WARNING(HW_GPU, "TXQ.NODEP is not implemented"); | ||
| 277 | } | ||
| 278 | |||
| 279 | // TODO: The new commits on the texture refactor, change the way samplers work. | ||
| 280 | // Sadly, not all texture instructions specify the type of texture their sampler | ||
| 281 | // uses. This must be fixed at a later instance. | ||
| 282 | const auto& sampler = | ||
| 283 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); | ||
| 284 | |||
| 285 | switch (instr.txq.query_type) { | ||
| 286 | case Tegra::Shader::TextureQueryType::Dimension: { | ||
| 287 | const MetaTexture meta_texture{sampler}; | ||
| 288 | const MetaComponents meta_components{{0, 1, 2, 3}}; | ||
| 289 | |||
| 290 | const Node texture = Operation(OperationCode::F4TextureQueryDimensions, meta_texture, | ||
| 291 | GetRegister(instr.gpr8)); | ||
| 292 | std::array<Node, 4> dest; | ||
| 293 | for (std::size_t i = 0; i < dest.size(); ++i) { | ||
| 294 | dest[i] = GetRegister(instr.gpr0.Value() + i); | ||
| 295 | } | ||
| 296 | |||
| 297 | bb.push_back(Operation(OperationCode::AssignComposite, meta_components, texture, | ||
| 298 | dest[0], dest[1], dest[2], dest[3])); | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | default: | ||
| 302 | UNIMPLEMENTED_MSG("Unhandled texture query type: {}", | ||
| 303 | static_cast<u32>(instr.txq.query_type.Value())); | ||
| 304 | } | ||
| 305 | break; | ||
| 306 | } | ||
| 126 | default: | 307 | default: |
| 127 | UNIMPLEMENTED_MSG("Unhandled memory instruction: {}", opcode->get().GetName()); | 308 | UNIMPLEMENTED_MSG("Unhandled memory instruction: {}", opcode->get().GetName()); |
| 128 | } | 309 | } |
| @@ -227,6 +408,44 @@ Node ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | |||
| 227 | return Operation(read_method, meta, std::move(params)); | 408 | return Operation(read_method, meta, std::move(params)); |
| 228 | } | 409 | } |
| 229 | 410 | ||
| 411 | Node ShaderIR::GetTexCode(Instruction instr, TextureType texture_type, | ||
| 412 | TextureProcessMode process_mode, bool depth_compare, bool is_array) { | ||
| 413 | const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None && | ||
| 414 | process_mode != Tegra::Shader::TextureProcessMode::LZ); | ||
| 415 | |||
| 416 | const auto [coord_count, total_coord_count] = ValidateAndGetCoordinateElement( | ||
| 417 | texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5); | ||
| 418 | // If enabled arrays index is always stored in the gpr8 field | ||
| 419 | const u64 array_register = instr.gpr8.Value(); | ||
| 420 | // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used | ||
| 421 | const u64 coord_register = array_register + (is_array ? 1 : 0); | ||
| 422 | |||
| 423 | std::vector<Node> coords; | ||
| 424 | for (std::size_t i = 0; i < coord_count; ++i) { | ||
| 425 | coords.push_back(GetRegister(coord_register + i)); | ||
| 426 | } | ||
| 427 | // 1D.DC in opengl the 2nd component is ignored. | ||
| 428 | if (depth_compare && !is_array && texture_type == TextureType::Texture1D) { | ||
| 429 | coords.push_back(Immediate(0.0f)); | ||
| 430 | } | ||
| 431 | if (depth_compare) { | ||
| 432 | // Depth is always stored in the register signaled by gpr20 | ||
| 433 | // or in the next register if lod or bias are used | ||
| 434 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); | ||
| 435 | coords.push_back(GetRegister(depth_register)); | ||
| 436 | } | ||
| 437 | if (is_array) { | ||
| 438 | coords.push_back(GetRegister(array_register)); | ||
| 439 | } | ||
| 440 | // Fill ignored coordinates | ||
| 441 | while (coords.size() < total_coord_count) { | ||
| 442 | coords.push_back(Immediate(0)); | ||
| 443 | } | ||
| 444 | |||
| 445 | return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0, | ||
| 446 | std::move(coords)); | ||
| 447 | } | ||
| 448 | |||
| 230 | Node ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | 449 | Node ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, |
| 231 | TextureProcessMode process_mode, bool depth_compare, bool is_array) { | 450 | TextureProcessMode process_mode, bool depth_compare, bool is_array) { |
| 232 | 451 | ||
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 4716d4c90..23a4de2a7 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -681,6 +681,10 @@ private: | |||
| 681 | 681 | ||
| 682 | void WriteTexsInstructionFloat(BasicBlock& bb, Tegra::Shader::Instruction instr, Node texture); | 682 | void WriteTexsInstructionFloat(BasicBlock& bb, Tegra::Shader::Instruction instr, Node texture); |
| 683 | 683 | ||
| 684 | Node GetTexCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | ||
| 685 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, | ||
| 686 | bool is_array); | ||
| 687 | |||
| 684 | Node GetTexsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | 688 | Node GetTexsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, |
| 685 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, | 689 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, |
| 686 | bool is_array); | 690 | bool is_array); |