diff options
| author | 2018-12-21 01:27:47 -0300 | |
|---|---|---|
| committer | 2019-01-15 17:54:50 -0300 | |
| commit | 878672f371e71d7d7a5b44aec0dc4918a682732d (patch) | |
| tree | e054b8bd76d07972fc11a41a09842f2201269312 /src | |
| parent | shader_decode: Implement FSETP (diff) | |
| download | yuzu-878672f371e71d7d7a5b44aec0dc4918a682732d.tar.gz yuzu-878672f371e71d7d7a5b44aec0dc4918a682732d.tar.xz yuzu-878672f371e71d7d7a5b44aec0dc4918a682732d.zip | |
shader_decode: Implement TEXS (F32)
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/shader/decode/memory.cpp | 199 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 18 |
2 files changed, 217 insertions, 0 deletions
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index aea1a0675..1f458b6d7 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 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 <vector> | ||
| 6 | |||
| 5 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 6 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 7 | #include "video_core/engines/shader_bytecode.h" | 9 | #include "video_core/engines/shader_bytecode.h" |
| @@ -13,6 +15,24 @@ using Tegra::Shader::Attribute; | |||
| 13 | using Tegra::Shader::Instruction; | 15 | using Tegra::Shader::Instruction; |
| 14 | using Tegra::Shader::OpCode; | 16 | using Tegra::Shader::OpCode; |
| 15 | using Tegra::Shader::Register; | 17 | using Tegra::Shader::Register; |
| 18 | using Tegra::Shader::TextureMiscMode; | ||
| 19 | using Tegra::Shader::TextureProcessMode; | ||
| 20 | using Tegra::Shader::TextureType; | ||
| 21 | |||
| 22 | static std::size_t GetCoordCount(TextureType texture_type) { | ||
| 23 | switch (texture_type) { | ||
| 24 | case TextureType::Texture1D: | ||
| 25 | return 1; | ||
| 26 | case TextureType::Texture2D: | ||
| 27 | return 2; | ||
| 28 | case TextureType::Texture3D: | ||
| 29 | case TextureType::TextureCube: | ||
| 30 | return 3; | ||
| 31 | default: | ||
| 32 | UNIMPLEMENTED_MSG("Unhandled texture type: {}", static_cast<u32>(texture_type)); | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | } | ||
| 16 | 36 | ||
| 17 | u32 ShaderIR::DecodeMemory(BasicBlock& bb, u32 pc) { | 37 | u32 ShaderIR::DecodeMemory(BasicBlock& bb, u32 pc) { |
| 18 | const Instruction instr = {program_code[pc]}; | 38 | const Instruction instr = {program_code[pc]}; |
| @@ -82,6 +102,27 @@ u32 ShaderIR::DecodeMemory(BasicBlock& bb, u32 pc) { | |||
| 82 | 102 | ||
| 83 | break; | 103 | break; |
| 84 | } | 104 | } |
| 105 | case OpCode::Id::TEXS: { | ||
| 106 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; | ||
| 107 | const bool is_array{instr.texs.IsArrayTexture()}; | ||
| 108 | const bool depth_compare = instr.texs.UsesMiscMode(TextureMiscMode::DC); | ||
| 109 | const auto process_mode = instr.texs.GetTextureProcessMode(); | ||
| 110 | |||
| 111 | if (instr.texs.UsesMiscMode(TextureMiscMode::NODEP)) { | ||
| 112 | LOG_WARNING(HW_GPU, "TEXS.NODEP implementation is incomplete"); | ||
| 113 | } | ||
| 114 | |||
| 115 | const Node texture = | ||
| 116 | GetTexsCode(instr, texture_type, process_mode, depth_compare, is_array); | ||
| 117 | |||
| 118 | if (instr.texs.fp32_flag) { | ||
| 119 | WriteTexsInstructionFloat(bb, instr, texture); | ||
| 120 | } else { | ||
| 121 | UNIMPLEMENTED(); | ||
| 122 | // WriteTexsInstructionHalfFloat(bb, instr, texture); | ||
| 123 | } | ||
| 124 | break; | ||
| 125 | } | ||
| 85 | default: | 126 | default: |
| 86 | UNIMPLEMENTED_MSG("Unhandled memory instruction: {}", opcode->get().GetName()); | 127 | UNIMPLEMENTED_MSG("Unhandled memory instruction: {}", opcode->get().GetName()); |
| 87 | } | 128 | } |
| @@ -89,4 +130,162 @@ u32 ShaderIR::DecodeMemory(BasicBlock& bb, u32 pc) { | |||
| 89 | return pc; | 130 | return pc; |
| 90 | } | 131 | } |
| 91 | 132 | ||
| 133 | const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, TextureType type, | ||
| 134 | bool is_array, bool is_shadow) { | ||
| 135 | const auto offset = static_cast<std::size_t>(sampler.index.Value()); | ||
| 136 | |||
| 137 | // If this sampler has already been used, return the existing mapping. | ||
| 138 | const auto itr = | ||
| 139 | std::find_if(used_samplers.begin(), used_samplers.end(), | ||
| 140 | [&](const Sampler& entry) { return entry.GetOffset() == offset; }); | ||
| 141 | if (itr != used_samplers.end()) { | ||
| 142 | ASSERT(itr->GetType() == type && itr->IsArray() == is_array && | ||
| 143 | itr->IsShadow() == is_shadow); | ||
| 144 | return *itr; | ||
| 145 | } | ||
| 146 | |||
| 147 | // Otherwise create a new mapping for this sampler | ||
| 148 | const std::size_t next_index = used_samplers.size(); | ||
| 149 | const Sampler entry{offset, next_index, type, is_array, is_shadow}; | ||
| 150 | return *used_samplers.emplace(entry).first; | ||
| 151 | } | ||
| 152 | |||
| 153 | void ShaderIR::WriteTexsInstructionFloat(BasicBlock& bb, Tegra::Shader::Instruction instr, | ||
| 154 | Node texture) { | ||
| 155 | // TEXS has two destination registers and a swizzle. The first two elements in the swizzle | ||
| 156 | // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 | ||
| 157 | |||
| 158 | MetaComponents meta; | ||
| 159 | std::array<Node, 4> dest; | ||
| 160 | |||
| 161 | std::size_t written_components = 0; | ||
| 162 | for (u32 component = 0; component < 4; ++component) { | ||
| 163 | if (!instr.texs.IsComponentEnabled(component)) { | ||
| 164 | continue; | ||
| 165 | } | ||
| 166 | meta.components_map[written_components] = static_cast<u32>(component); | ||
| 167 | |||
| 168 | if (written_components < 2) { | ||
| 169 | // Write the first two swizzle components to gpr0 and gpr0+1 | ||
| 170 | dest[written_components] = GetRegister(instr.gpr0.Value() + written_components % 2); | ||
| 171 | } else { | ||
| 172 | ASSERT(instr.texs.HasTwoDestinations()); | ||
| 173 | // Write the rest of the swizzle components to gpr28 and gpr28+1 | ||
| 174 | dest[written_components] = GetRegister(instr.gpr28.Value() + written_components % 2); | ||
| 175 | } | ||
| 176 | |||
| 177 | ++written_components; | ||
| 178 | } | ||
| 179 | |||
| 180 | std::generate(dest.begin() + written_components, dest.end(), [&]() { return GetRegister(RZ); }); | ||
| 181 | |||
| 182 | bb.push_back(Operation(OperationCode::AssignComposite, meta, texture, dest[0], dest[1], dest[2], | ||
| 183 | dest[3])); | ||
| 184 | } | ||
| 185 | |||
| 186 | Node ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | ||
| 187 | TextureProcessMode process_mode, bool depth_compare, bool is_array, | ||
| 188 | std::size_t bias_offset, std::vector<Node>&& coords) { | ||
| 189 | UNIMPLEMENTED_IF_MSG( | ||
| 190 | (texture_type == TextureType::Texture3D && (is_array || depth_compare)) || | ||
| 191 | (texture_type == TextureType::TextureCube && is_array && depth_compare), | ||
| 192 | "This method is not supported."); | ||
| 193 | |||
| 194 | const auto& sampler = GetSampler(instr.sampler, texture_type, is_array, depth_compare); | ||
| 195 | |||
| 196 | const bool lod_needed = process_mode == TextureProcessMode::LZ || | ||
| 197 | process_mode == TextureProcessMode::LL || | ||
| 198 | process_mode == TextureProcessMode::LLA; | ||
| 199 | |||
| 200 | const bool gl_lod_supported = | ||
| 201 | !((texture_type == TextureType::Texture2D && is_array && depth_compare) || | ||
| 202 | (texture_type == TextureType::TextureCube && !is_array && depth_compare)); | ||
| 203 | |||
| 204 | const OperationCode read_method = | ||
| 205 | lod_needed && gl_lod_supported ? OperationCode::F4TextureLod : OperationCode::F4Texture; | ||
| 206 | |||
| 207 | const MetaTexture meta{sampler, static_cast<u32>(coords.size())}; | ||
| 208 | |||
| 209 | std::vector<Node> params = std::move(coords); | ||
| 210 | |||
| 211 | if (process_mode != TextureProcessMode::None) { | ||
| 212 | if (process_mode == TextureProcessMode::LZ) { | ||
| 213 | if (gl_lod_supported) { | ||
| 214 | params.push_back(Immediate(0)); | ||
| 215 | } else { | ||
| 216 | // Lod 0 is emulated by a big negative bias in scenarios that are not supported by | ||
| 217 | // GLSL | ||
| 218 | params.push_back(Immediate(-1000)); | ||
| 219 | } | ||
| 220 | } else { | ||
| 221 | // If present, lod or bias are always stored in the register indexed by the gpr20 field | ||
| 222 | // with an offset depending on the usage of the other registers | ||
| 223 | params.push_back(GetRegister(instr.gpr20.Value() + bias_offset)); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | return Operation(read_method, meta, std::move(params)); | ||
| 228 | } | ||
| 229 | |||
| 230 | Node ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, | ||
| 231 | TextureProcessMode process_mode, bool depth_compare, bool is_array) { | ||
| 232 | |||
| 233 | const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None && | ||
| 234 | process_mode != Tegra::Shader::TextureProcessMode::LZ); | ||
| 235 | |||
| 236 | const auto [coord_count, total_coord_count] = ValidateAndGetCoordinateElement( | ||
| 237 | texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4); | ||
| 238 | // If enabled arrays index is always stored in the gpr8 field | ||
| 239 | const u64 array_register = instr.gpr8.Value(); | ||
| 240 | // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used | ||
| 241 | const u64 coord_register = array_register + (is_array ? 1 : 0); | ||
| 242 | const u64 last_coord_register = | ||
| 243 | (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2)) | ||
| 244 | ? static_cast<u64>(instr.gpr20.Value()) | ||
| 245 | : coord_register + 1; | ||
| 246 | |||
| 247 | std::vector<Node> coords; | ||
| 248 | for (std::size_t i = 0; i < coord_count; ++i) { | ||
| 249 | const bool last = (i == (coord_count - 1)) && (coord_count > 1); | ||
| 250 | coords.push_back(GetRegister(last ? last_coord_register : coord_register + i)); | ||
| 251 | } | ||
| 252 | |||
| 253 | if (depth_compare) { | ||
| 254 | // Depth is always stored in the register signaled by gpr20 | ||
| 255 | // or in the next register if lod or bias are used | ||
| 256 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); | ||
| 257 | coords.push_back(GetRegister(depth_register)); | ||
| 258 | } | ||
| 259 | if (is_array) { | ||
| 260 | coords.push_back( | ||
| 261 | Operation(OperationCode::ICastFloat, NO_PRECISE, GetRegister(array_register))); | ||
| 262 | } | ||
| 263 | // Fill ignored coordinates | ||
| 264 | while (coords.size() < total_coord_count) { | ||
| 265 | coords.push_back(Immediate(0)); | ||
| 266 | } | ||
| 267 | |||
| 268 | return GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, | ||
| 269 | (coord_count > 2 ? 1 : 0), std::move(coords)); | ||
| 270 | } | ||
| 271 | |||
| 272 | std::tuple<std::size_t, std::size_t> ShaderIR::ValidateAndGetCoordinateElement( | ||
| 273 | TextureType texture_type, bool depth_compare, bool is_array, bool lod_bias_enabled, | ||
| 274 | std::size_t max_coords, std::size_t max_inputs) { | ||
| 275 | |||
| 276 | const std::size_t coord_count = GetCoordCount(texture_type); | ||
| 277 | |||
| 278 | std::size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0); | ||
| 279 | const std::size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0); | ||
| 280 | if (total_coord_count > max_coords || total_reg_count > max_inputs) { | ||
| 281 | UNIMPLEMENTED_MSG("Unsupported Texture operation"); | ||
| 282 | total_coord_count = std::min(total_coord_count, max_coords); | ||
| 283 | } | ||
| 284 | // 1D.DC OpenGL is using a vec3 but 2nd component is ignored later. | ||
| 285 | total_coord_count += | ||
| 286 | (depth_compare && !is_array && texture_type == TextureType::Texture1D) ? 1 : 0; | ||
| 287 | |||
| 288 | return {coord_count, total_coord_count}; | ||
| 289 | } | ||
| 290 | |||
| 92 | } // namespace VideoCommon::Shader \ No newline at end of file | 291 | } // namespace VideoCommon::Shader \ No newline at end of file |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 8223ff044..4716d4c90 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -675,6 +675,24 @@ private: | |||
| 675 | /// Returns a condition code evaluated from internal flags | 675 | /// Returns a condition code evaluated from internal flags |
| 676 | Node GetConditionCode(Tegra::Shader::ConditionCode cc); | 676 | Node GetConditionCode(Tegra::Shader::ConditionCode cc); |
| 677 | 677 | ||
| 678 | /// Accesses a texture sampler | ||
| 679 | const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, | ||
| 680 | Tegra::Shader::TextureType type, bool is_array, bool is_shadow); | ||
| 681 | |||
| 682 | void WriteTexsInstructionFloat(BasicBlock& bb, Tegra::Shader::Instruction instr, Node texture); | ||
| 683 | |||
| 684 | Node GetTexsCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | ||
| 685 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, | ||
| 686 | bool is_array); | ||
| 687 | |||
| 688 | std::tuple<std::size_t, std::size_t> ValidateAndGetCoordinateElement( | ||
| 689 | Tegra::Shader::TextureType texture_type, bool depth_compare, bool is_array, | ||
| 690 | bool lod_bias_enabled, std::size_t max_coords, std::size_t max_inputs); | ||
| 691 | |||
| 692 | Node GetTextureCode(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, | ||
| 693 | Tegra::Shader::TextureProcessMode process_mode, bool depth_compare, | ||
| 694 | bool is_array, std::size_t bias_offset, std::vector<Node>&& coords); | ||
| 695 | |||
| 678 | template <typename... T> | 696 | template <typename... T> |
| 679 | inline Node Operation(OperationCode code, const T*... operands) { | 697 | inline Node Operation(OperationCode code, const T*... operands) { |
| 680 | return StoreNode(OperationNode(code, operands...)); | 698 | return StoreNode(OperationNode(code, operands...)); |