diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 463 |
1 files changed, 213 insertions, 250 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 0c1632bd1..d235bfcd4 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -201,14 +201,53 @@ private: | |||
| 201 | } | 201 | } |
| 202 | }; | 202 | }; |
| 203 | 203 | ||
| 204 | template <typename T> | ||
| 205 | class ShaderScopedScope { | ||
| 206 | public: | ||
| 207 | explicit ShaderScopedScope(T& writer, std::string_view begin_expr, std::string end_expr) | ||
| 208 | : writer(writer), end_expr(std::move(end_expr)) { | ||
| 209 | |||
| 210 | if (begin_expr.empty()) { | ||
| 211 | writer.AddLine('{'); | ||
| 212 | } else { | ||
| 213 | writer.AddExpression(begin_expr); | ||
| 214 | writer.AddLine(" {"); | ||
| 215 | } | ||
| 216 | ++writer.scope; | ||
| 217 | } | ||
| 218 | |||
| 219 | ShaderScopedScope(const ShaderScopedScope&) = delete; | ||
| 220 | |||
| 221 | ~ShaderScopedScope() { | ||
| 222 | --writer.scope; | ||
| 223 | if (end_expr.empty()) { | ||
| 224 | writer.AddLine('}'); | ||
| 225 | } else { | ||
| 226 | writer.AddExpression("} "); | ||
| 227 | writer.AddExpression(end_expr); | ||
| 228 | writer.AddLine(';'); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | ShaderScopedScope& operator=(const ShaderScopedScope&) = delete; | ||
| 233 | |||
| 234 | private: | ||
| 235 | T& writer; | ||
| 236 | std::string end_expr; | ||
| 237 | }; | ||
| 238 | |||
| 204 | class ShaderWriter { | 239 | class ShaderWriter { |
| 205 | public: | 240 | public: |
| 206 | void AddLine(std::string_view text) { | 241 | void AddExpression(std::string_view text) { |
| 207 | DEBUG_ASSERT(scope >= 0); | 242 | DEBUG_ASSERT(scope >= 0); |
| 208 | if (!text.empty()) { | 243 | if (!text.empty()) { |
| 209 | AppendIndentation(); | 244 | AppendIndentation(); |
| 210 | } | 245 | } |
| 211 | shader_source += text; | 246 | shader_source += text; |
| 247 | } | ||
| 248 | |||
| 249 | void AddLine(std::string_view text) { | ||
| 250 | AddExpression(text); | ||
| 212 | AddNewLine(); | 251 | AddNewLine(); |
| 213 | } | 252 | } |
| 214 | 253 | ||
| @@ -228,6 +267,11 @@ public: | |||
| 228 | return std::move(shader_source); | 267 | return std::move(shader_source); |
| 229 | } | 268 | } |
| 230 | 269 | ||
| 270 | ShaderScopedScope<ShaderWriter> Scope(std::string_view begin_expr = {}, | ||
| 271 | std::string end_expr = {}) { | ||
| 272 | return ShaderScopedScope(*this, begin_expr, end_expr); | ||
| 273 | } | ||
| 274 | |||
| 231 | int scope = 0; | 275 | int scope = 0; |
| 232 | 276 | ||
| 233 | private: | 277 | private: |
| @@ -311,7 +355,7 @@ public: | |||
| 311 | // Default - do nothing | 355 | // Default - do nothing |
| 312 | return value; | 356 | return value; |
| 313 | default: | 357 | default: |
| 314 | UNIMPLEMENTED_MSG("Unimplemented conversion size: {}", static_cast<u32>(size)); | 358 | UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size)); |
| 315 | } | 359 | } |
| 316 | } | 360 | } |
| 317 | 361 | ||
| @@ -816,14 +860,12 @@ private: | |||
| 816 | } | 860 | } |
| 817 | 861 | ||
| 818 | if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) { | 862 | if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) { |
| 819 | shader.AddLine('{'); | 863 | const auto scope = shader.Scope(); |
| 820 | ++shader.scope; | 864 | |
| 821 | // This avoids optimizations of constant propagation and keeps the code as the original | 865 | // This avoids optimizations of constant propagation and keeps the code as the original |
| 822 | // Sadly using the precise keyword causes "linking" errors on fragment shaders. | 866 | // Sadly using the precise keyword causes "linking" errors on fragment shaders. |
| 823 | shader.AddLine("precise float tmp = " + src + ';'); | 867 | shader.AddLine("precise float tmp = " + src + ';'); |
| 824 | shader.AddLine(dest + " = tmp;"); | 868 | shader.AddLine(dest + " = tmp;"); |
| 825 | --shader.scope; | ||
| 826 | shader.AddLine('}'); | ||
| 827 | } else { | 869 | } else { |
| 828 | shader.AddLine(dest + " = " + src + ';'); | 870 | shader.AddLine(dest + " = " + src + ';'); |
| 829 | } | 871 | } |
| @@ -1301,15 +1343,7 @@ private: | |||
| 1301 | regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); | 1343 | regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); |
| 1302 | } | 1344 | } |
| 1303 | 1345 | ||
| 1304 | void WriteTexsInstruction(const Instruction& instr, const std::string& coord, | 1346 | void WriteTexsInstruction(const Instruction& instr, const std::string& texture) { |
| 1305 | const std::string& texture) { | ||
| 1306 | // Add an extra scope and declare the texture coords inside to prevent | ||
| 1307 | // overwriting them in case they are used as outputs of the texs instruction. | ||
| 1308 | shader.AddLine('{'); | ||
| 1309 | ++shader.scope; | ||
| 1310 | shader.AddLine(coord); | ||
| 1311 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); | ||
| 1312 | |||
| 1313 | // TEXS has two destination registers and a swizzle. The first two elements in the swizzle | 1347 | // TEXS has two destination registers and a swizzle. The first two elements in the swizzle |
| 1314 | // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 | 1348 | // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 |
| 1315 | 1349 | ||
| @@ -1321,19 +1355,17 @@ private: | |||
| 1321 | 1355 | ||
| 1322 | if (written_components < 2) { | 1356 | if (written_components < 2) { |
| 1323 | // Write the first two swizzle components to gpr0 and gpr0+1 | 1357 | // Write the first two swizzle components to gpr0 and gpr0+1 |
| 1324 | regs.SetRegisterToFloat(instr.gpr0, component, "texture_tmp", 1, 4, false, | 1358 | regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false, |
| 1325 | written_components % 2); | 1359 | written_components % 2); |
| 1326 | } else { | 1360 | } else { |
| 1327 | ASSERT(instr.texs.HasTwoDestinations()); | 1361 | ASSERT(instr.texs.HasTwoDestinations()); |
| 1328 | // Write the rest of the swizzle components to gpr28 and gpr28+1 | 1362 | // Write the rest of the swizzle components to gpr28 and gpr28+1 |
| 1329 | regs.SetRegisterToFloat(instr.gpr28, component, "texture_tmp", 1, 4, false, | 1363 | regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false, |
| 1330 | written_components % 2); | 1364 | written_components % 2); |
| 1331 | } | 1365 | } |
| 1332 | 1366 | ||
| 1333 | ++written_components; | 1367 | ++written_components; |
| 1334 | } | 1368 | } |
| 1335 | --shader.scope; | ||
| 1336 | shader.AddLine('}'); | ||
| 1337 | } | 1369 | } |
| 1338 | 1370 | ||
| 1339 | static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { | 1371 | static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { |
| @@ -1356,12 +1388,10 @@ private: | |||
| 1356 | * top. | 1388 | * top. |
| 1357 | */ | 1389 | */ |
| 1358 | void EmitPushToFlowStack(u32 target) { | 1390 | void EmitPushToFlowStack(u32 target) { |
| 1359 | shader.AddLine('{'); | 1391 | const auto scope = shader.Scope(); |
| 1360 | ++shader.scope; | 1392 | |
| 1361 | shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;"); | 1393 | shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;"); |
| 1362 | shader.AddLine("flow_stack_top++;"); | 1394 | shader.AddLine("flow_stack_top++;"); |
| 1363 | --shader.scope; | ||
| 1364 | shader.AddLine('}'); | ||
| 1365 | } | 1395 | } |
| 1366 | 1396 | ||
| 1367 | /* | 1397 | /* |
| @@ -1369,13 +1399,11 @@ private: | |||
| 1369 | * popped address and decrementing the stack top. | 1399 | * popped address and decrementing the stack top. |
| 1370 | */ | 1400 | */ |
| 1371 | void EmitPopFromFlowStack() { | 1401 | void EmitPopFromFlowStack() { |
| 1372 | shader.AddLine('{'); | 1402 | const auto scope = shader.Scope(); |
| 1373 | ++shader.scope; | 1403 | |
| 1374 | shader.AddLine("flow_stack_top--;"); | 1404 | shader.AddLine("flow_stack_top--;"); |
| 1375 | shader.AddLine("jmp_to = flow_stack[flow_stack_top];"); | 1405 | shader.AddLine("jmp_to = flow_stack[flow_stack_top];"); |
| 1376 | shader.AddLine("break;"); | 1406 | shader.AddLine("break;"); |
| 1377 | --shader.scope; | ||
| 1378 | shader.AddLine('}'); | ||
| 1379 | } | 1407 | } |
| 1380 | 1408 | ||
| 1381 | /// Writes the output values from a fragment shader to the corresponding GLSL output variables. | 1409 | /// Writes the output values from a fragment shader to the corresponding GLSL output variables. |
| @@ -2287,8 +2315,7 @@ private: | |||
| 2287 | UNIMPLEMENTED_IF(instr.conversion.selector); | 2315 | UNIMPLEMENTED_IF(instr.conversion.selector); |
| 2288 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 2316 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 2289 | "Condition codes generation in I2F is not implemented"); | 2317 | "Condition codes generation in I2F is not implemented"); |
| 2290 | 2318 | std::string op_a; | |
| 2291 | std::string op_a{}; | ||
| 2292 | 2319 | ||
| 2293 | if (instr.is_b_gpr) { | 2320 | if (instr.is_b_gpr) { |
| 2294 | op_a = | 2321 | op_a = |
| @@ -2444,10 +2471,7 @@ private: | |||
| 2444 | case OpCode::Id::LD_C: { | 2471 | case OpCode::Id::LD_C: { |
| 2445 | UNIMPLEMENTED_IF(instr.ld_c.unknown != 0); | 2472 | UNIMPLEMENTED_IF(instr.ld_c.unknown != 0); |
| 2446 | 2473 | ||
| 2447 | // Add an extra scope and declare the index register inside to prevent | 2474 | const auto scope = shader.Scope(); |
| 2448 | // overwriting it in case it is used as an output of the LD instruction. | ||
| 2449 | shader.AddLine("{"); | ||
| 2450 | ++shader.scope; | ||
| 2451 | 2475 | ||
| 2452 | shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + | 2476 | shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + |
| 2453 | " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); | 2477 | " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); |
| @@ -2473,19 +2497,13 @@ private: | |||
| 2473 | UNIMPLEMENTED_MSG("Unhandled type: {}", | 2497 | UNIMPLEMENTED_MSG("Unhandled type: {}", |
| 2474 | static_cast<unsigned>(instr.ld_c.type.Value())); | 2498 | static_cast<unsigned>(instr.ld_c.type.Value())); |
| 2475 | } | 2499 | } |
| 2476 | |||
| 2477 | --shader.scope; | ||
| 2478 | shader.AddLine("}"); | ||
| 2479 | break; | 2500 | break; |
| 2480 | } | 2501 | } |
| 2481 | case OpCode::Id::LD_L: { | 2502 | case OpCode::Id::LD_L: { |
| 2482 | UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}", | 2503 | UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}", |
| 2483 | static_cast<unsigned>(instr.ld_l.unknown.Value())); | 2504 | static_cast<unsigned>(instr.ld_l.unknown.Value())); |
| 2484 | 2505 | ||
| 2485 | // Add an extra scope and declare the index register inside to prevent | 2506 | const auto scope = shader.Scope(); |
| 2486 | // overwriting it in case it is used as an output of the LD instruction. | ||
| 2487 | shader.AddLine('{'); | ||
| 2488 | ++shader.scope; | ||
| 2489 | 2507 | ||
| 2490 | std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + | 2508 | std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + |
| 2491 | std::to_string(instr.smem_imm.Value()) + ')'; | 2509 | std::to_string(instr.smem_imm.Value()) + ')'; |
| @@ -2502,9 +2520,6 @@ private: | |||
| 2502 | UNIMPLEMENTED_MSG("LD_L Unhandled type: {}", | 2520 | UNIMPLEMENTED_MSG("LD_L Unhandled type: {}", |
| 2503 | static_cast<unsigned>(instr.ldst_sl.type.Value())); | 2521 | static_cast<unsigned>(instr.ldst_sl.type.Value())); |
| 2504 | } | 2522 | } |
| 2505 | |||
| 2506 | --shader.scope; | ||
| 2507 | shader.AddLine('}'); | ||
| 2508 | break; | 2523 | break; |
| 2509 | } | 2524 | } |
| 2510 | case OpCode::Id::ST_A: { | 2525 | case OpCode::Id::ST_A: { |
| @@ -2539,10 +2554,7 @@ private: | |||
| 2539 | UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}", | 2554 | UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}", |
| 2540 | static_cast<unsigned>(instr.st_l.unknown.Value())); | 2555 | static_cast<unsigned>(instr.st_l.unknown.Value())); |
| 2541 | 2556 | ||
| 2542 | // Add an extra scope and declare the index register inside to prevent | 2557 | const auto scope = shader.Scope(); |
| 2543 | // overwriting it in case it is used as an output of the LD instruction. | ||
| 2544 | shader.AddLine('{'); | ||
| 2545 | ++shader.scope; | ||
| 2546 | 2558 | ||
| 2547 | std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + | 2559 | std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + |
| 2548 | std::to_string(instr.smem_imm.Value()) + ')'; | 2560 | std::to_string(instr.smem_imm.Value()) + ')'; |
| @@ -2557,14 +2569,10 @@ private: | |||
| 2557 | UNIMPLEMENTED_MSG("ST_L Unhandled type: {}", | 2569 | UNIMPLEMENTED_MSG("ST_L Unhandled type: {}", |
| 2558 | static_cast<unsigned>(instr.ldst_sl.type.Value())); | 2570 | static_cast<unsigned>(instr.ldst_sl.type.Value())); |
| 2559 | } | 2571 | } |
| 2560 | |||
| 2561 | --shader.scope; | ||
| 2562 | shader.AddLine('}'); | ||
| 2563 | break; | 2572 | break; |
| 2564 | } | 2573 | } |
| 2565 | case OpCode::Id::TEX: { | 2574 | case OpCode::Id::TEX: { |
| 2566 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; | 2575 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; |
| 2567 | std::string coord; | ||
| 2568 | const bool is_array = instr.tex.array != 0; | 2576 | const bool is_array = instr.tex.array != 0; |
| 2569 | 2577 | ||
| 2570 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 2578 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| @@ -2597,21 +2605,23 @@ private: | |||
| 2597 | 2605 | ||
| 2598 | bool depth_compare_extra = false; | 2606 | bool depth_compare_extra = false; |
| 2599 | 2607 | ||
| 2608 | const auto scope = shader.Scope(); | ||
| 2609 | |||
| 2600 | switch (num_coordinates) { | 2610 | switch (num_coordinates) { |
| 2601 | case 1: { | 2611 | case 1: { |
| 2602 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); | 2612 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); |
| 2603 | if (is_array) { | 2613 | if (is_array) { |
| 2604 | if (depth_compare) { | 2614 | if (depth_compare) { |
| 2605 | coord = "vec3 coords = vec3(" + x + ", " + depth_value + ", " + | 2615 | shader.AddLine("vec3 coords = vec3(" + x + ", " + depth_value + ", " + |
| 2606 | array_elem + ");"; | 2616 | array_elem + ");"); |
| 2607 | } else { | 2617 | } else { |
| 2608 | coord = "vec2 coords = vec2(" + x + ", " + array_elem + ");"; | 2618 | shader.AddLine("vec2 coords = vec2(" + x + ", " + array_elem + ");"); |
| 2609 | } | 2619 | } |
| 2610 | } else { | 2620 | } else { |
| 2611 | if (depth_compare) { | 2621 | if (depth_compare) { |
| 2612 | coord = "vec2 coords = vec2(" + x + ", " + depth_value + ");"; | 2622 | shader.AddLine("vec2 coords = vec2(" + x + ", " + depth_value + ");"); |
| 2613 | } else { | 2623 | } else { |
| 2614 | coord = "float coords = " + x + ';'; | 2624 | shader.AddLine("float coords = " + x + ';'); |
| 2615 | } | 2625 | } |
| 2616 | } | 2626 | } |
| 2617 | break; | 2627 | break; |
| @@ -2622,17 +2632,18 @@ private: | |||
| 2622 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1); | 2632 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1); |
| 2623 | if (is_array) { | 2633 | if (is_array) { |
| 2624 | if (depth_compare) { | 2634 | if (depth_compare) { |
| 2625 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + depth_value + | 2635 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + |
| 2626 | ", " + array_elem + ");"; | 2636 | depth_value + ", " + array_elem + ");"); |
| 2627 | } else { | 2637 | } else { |
| 2628 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + array_elem + ");"; | 2638 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + |
| 2639 | array_elem + ");"); | ||
| 2629 | } | 2640 | } |
| 2630 | } else { | 2641 | } else { |
| 2631 | if (depth_compare) { | 2642 | if (depth_compare) { |
| 2632 | coord = | 2643 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + |
| 2633 | "vec3 coords = vec3(" + x + ", " + y + ", " + depth_value + ");"; | 2644 | depth_value + ");"); |
| 2634 | } else { | 2645 | } else { |
| 2635 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2646 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 2636 | } | 2647 | } |
| 2637 | } | 2648 | } |
| 2638 | break; | 2649 | break; |
| @@ -2645,14 +2656,14 @@ private: | |||
| 2645 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2); | 2656 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2); |
| 2646 | if (is_array) { | 2657 | if (is_array) { |
| 2647 | depth_compare_extra = depth_compare; | 2658 | depth_compare_extra = depth_compare; |
| 2648 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + | 2659 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + |
| 2649 | array_elem + ");"; | 2660 | array_elem + ");"); |
| 2650 | } else { | 2661 | } else { |
| 2651 | if (depth_compare) { | 2662 | if (depth_compare) { |
| 2652 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + | 2663 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + |
| 2653 | depth_value + ");"; | 2664 | depth_value + ");"); |
| 2654 | } else { | 2665 | } else { |
| 2655 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | 2666 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"); |
| 2656 | } | 2667 | } |
| 2657 | } | 2668 | } |
| 2658 | break; | 2669 | break; |
| @@ -2664,7 +2675,7 @@ private: | |||
| 2664 | // Fallback to interpreting as a 2D texture for now | 2675 | // Fallback to interpreting as a 2D texture for now |
| 2665 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2676 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2666 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2677 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2667 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2678 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 2668 | texture_type = Tegra::Shader::TextureType::Texture2D; | 2679 | texture_type = Tegra::Shader::TextureType::Texture2D; |
| 2669 | } | 2680 | } |
| 2670 | 2681 | ||
| @@ -2673,79 +2684,61 @@ private: | |||
| 2673 | // Add an extra scope and declare the texture coords inside to prevent | 2684 | // Add an extra scope and declare the texture coords inside to prevent |
| 2674 | // overwriting them in case they are used as outputs of the texs instruction. | 2685 | // overwriting them in case they are used as outputs of the texs instruction. |
| 2675 | 2686 | ||
| 2676 | shader.AddLine('{'); | 2687 | const std::string texture = [&]() { |
| 2677 | ++shader.scope; | 2688 | switch (instr.tex.GetTextureProcessMode()) { |
| 2678 | shader.AddLine(coord); | 2689 | case Tegra::Shader::TextureProcessMode::None: |
| 2679 | std::string texture; | 2690 | if (depth_compare_extra) { |
| 2680 | 2691 | return "texture(" + sampler + ", coords, " + depth_value + ')'; | |
| 2681 | switch (instr.tex.GetTextureProcessMode()) { | 2692 | } |
| 2682 | case Tegra::Shader::TextureProcessMode::None: { | 2693 | return "texture(" + sampler + ", coords)"; |
| 2683 | if (!depth_compare_extra) { | 2694 | case Tegra::Shader::TextureProcessMode::LZ: |
| 2684 | texture = "texture(" + sampler + ", coords)"; | 2695 | if (depth_compare_extra) { |
| 2685 | } else { | 2696 | return "texture(" + sampler + ", coords, " + depth_value + ')'; |
| 2686 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | 2697 | } |
| 2687 | } | 2698 | return "textureLod(" + sampler + ", coords, 0.0)"; |
| 2688 | break; | 2699 | case Tegra::Shader::TextureProcessMode::LB: |
| 2689 | } | 2700 | case Tegra::Shader::TextureProcessMode::LBA: |
| 2690 | case Tegra::Shader::TextureProcessMode::LZ: { | 2701 | // TODO: Figure if A suffix changes the equation at all. |
| 2691 | if (!depth_compare_extra) { | 2702 | if (depth_compare_extra) { |
| 2692 | texture = "textureLod(" + sampler + ", coords, 0.0)"; | 2703 | LOG_WARNING( |
| 2693 | } else { | 2704 | HW_GPU, |
| 2694 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | 2705 | "OpenGL Limitation: can't set bias value along depth compare"); |
| 2695 | } | 2706 | return "texture(" + sampler + ", coords, " + depth_value + ')'; |
| 2696 | break; | 2707 | } |
| 2697 | } | 2708 | return "texture(" + sampler + ", coords, " + lod_value + ')'; |
| 2698 | case Tegra::Shader::TextureProcessMode::LB: | 2709 | case Tegra::Shader::TextureProcessMode::LL: |
| 2699 | case Tegra::Shader::TextureProcessMode::LBA: { | 2710 | case Tegra::Shader::TextureProcessMode::LLA: |
| 2700 | // TODO: Figure if A suffix changes the equation at all. | 2711 | // TODO: Figure if A suffix changes the equation at all. |
| 2701 | if (!depth_compare_extra) { | 2712 | if (depth_compare_extra) { |
| 2702 | texture = "texture(" + sampler + ", coords, " + lod_value + ')'; | 2713 | LOG_WARNING( |
| 2703 | } else { | 2714 | HW_GPU, |
| 2704 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | 2715 | "OpenGL Limitation: can't set lod value along depth compare"); |
| 2705 | LOG_WARNING(HW_GPU, | 2716 | return "texture(" + sampler + ", coords, " + depth_value + ')'; |
| 2706 | "OpenGL Limitation: can't set bias value along depth compare"); | 2717 | } |
| 2707 | } | 2718 | return "textureLod(" + sampler + ", coords, " + lod_value + ')'; |
| 2708 | break; | 2719 | default: |
| 2709 | } | 2720 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", |
| 2710 | case Tegra::Shader::TextureProcessMode::LL: | 2721 | static_cast<u32>(instr.tex.GetTextureProcessMode())); |
| 2711 | case Tegra::Shader::TextureProcessMode::LLA: { | 2722 | if (depth_compare_extra) { |
| 2712 | // TODO: Figure if A suffix changes the equation at all. | 2723 | return "texture(" + sampler + ", coords, " + depth_value + ')'; |
| 2713 | if (!depth_compare_extra) { | 2724 | } |
| 2714 | texture = "textureLod(" + sampler + ", coords, " + lod_value + ')'; | 2725 | return "texture(" + sampler + ", coords)"; |
| 2715 | } else { | ||
| 2716 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2717 | LOG_WARNING(HW_GPU, | ||
| 2718 | "OpenGL Limitation: can't set lod value along depth compare"); | ||
| 2719 | } | ||
| 2720 | break; | ||
| 2721 | } | ||
| 2722 | default: { | ||
| 2723 | if (!depth_compare_extra) { | ||
| 2724 | texture = "texture(" + sampler + ", coords)"; | ||
| 2725 | } else { | ||
| 2726 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2727 | } | 2726 | } |
| 2728 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", | 2727 | }(); |
| 2729 | static_cast<u32>(instr.tex.GetTextureProcessMode())); | 2728 | |
| 2730 | } | 2729 | if (depth_compare) { |
| 2731 | } | 2730 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); |
| 2732 | if (!depth_compare) { | 2731 | } else { |
| 2733 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); | ||
| 2734 | std::size_t dest_elem{}; | 2732 | std::size_t dest_elem{}; |
| 2735 | for (std::size_t elem = 0; elem < 4; ++elem) { | 2733 | for (std::size_t elem = 0; elem < 4; ++elem) { |
| 2736 | if (!instr.tex.IsComponentEnabled(elem)) { | 2734 | if (!instr.tex.IsComponentEnabled(elem)) { |
| 2737 | // Skip disabled components | 2735 | // Skip disabled components |
| 2738 | continue; | 2736 | continue; |
| 2739 | } | 2737 | } |
| 2740 | regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, | 2738 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); |
| 2741 | dest_elem); | ||
| 2742 | ++dest_elem; | 2739 | ++dest_elem; |
| 2743 | } | 2740 | } |
| 2744 | } else { | ||
| 2745 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); | ||
| 2746 | } | 2741 | } |
| 2747 | --shader.scope; | ||
| 2748 | shader.AddLine('}'); | ||
| 2749 | break; | 2742 | break; |
| 2750 | } | 2743 | } |
| 2751 | case OpCode::Id::TEXS: { | 2744 | case OpCode::Id::TEXS: { |
| @@ -2755,26 +2748,28 @@ private: | |||
| 2755 | UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 2748 | UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| 2756 | "NODEP is not implemented"); | 2749 | "NODEP is not implemented"); |
| 2757 | 2750 | ||
| 2751 | const auto scope = shader.Scope(); | ||
| 2752 | |||
| 2758 | const bool depth_compare = | 2753 | const bool depth_compare = |
| 2759 | instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | 2754 | instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| 2760 | u32 num_coordinates = TextureCoordinates(texture_type); | 2755 | u32 num_coordinates = TextureCoordinates(texture_type); |
| 2761 | const auto process_mode = instr.texs.GetTextureProcessMode(); | 2756 | const auto process_mode = instr.texs.GetTextureProcessMode(); |
| 2762 | std::string lod_value; | ||
| 2763 | std::string coord; | ||
| 2764 | u32 lod_offset = 0; | 2757 | u32 lod_offset = 0; |
| 2765 | if (process_mode == Tegra::Shader::TextureProcessMode::LL) { | 2758 | if (process_mode == Tegra::Shader::TextureProcessMode::LL) { |
| 2766 | if (num_coordinates > 2) { | 2759 | if (num_coordinates > 2) { |
| 2767 | lod_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | 2760 | shader.AddLine("float lod_value = " + |
| 2761 | regs.GetRegisterAsFloat(instr.gpr20.Value() + 1) + ';'); | ||
| 2768 | lod_offset = 2; | 2762 | lod_offset = 2; |
| 2769 | } else { | 2763 | } else { |
| 2770 | lod_value = regs.GetRegisterAsFloat(instr.gpr20); | 2764 | shader.AddLine("float lod_value = " + regs.GetRegisterAsFloat(instr.gpr20) + |
| 2765 | ';'); | ||
| 2771 | lod_offset = 1; | 2766 | lod_offset = 1; |
| 2772 | } | 2767 | } |
| 2773 | } | 2768 | } |
| 2774 | 2769 | ||
| 2775 | switch (num_coordinates) { | 2770 | switch (num_coordinates) { |
| 2776 | case 1: { | 2771 | case 1: { |
| 2777 | coord = "float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';'; | 2772 | shader.AddLine("float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';'); |
| 2778 | break; | 2773 | break; |
| 2779 | } | 2774 | } |
| 2780 | case 2: { | 2775 | case 2: { |
| @@ -2784,13 +2779,14 @@ private: | |||
| 2784 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2779 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2785 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | 2780 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); |
| 2786 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | 2781 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); |
| 2787 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + | 2782 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + |
| 2788 | ");"; | 2783 | index + ");"); |
| 2789 | } else { | 2784 | } else { |
| 2790 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2785 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); |
| 2791 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2786 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2792 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | 2787 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); |
| 2793 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; | 2788 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + index + |
| 2789 | ");"); | ||
| 2794 | } | 2790 | } |
| 2795 | } else { | 2791 | } else { |
| 2796 | if (lod_offset != 0) { | 2792 | if (lod_offset != 0) { |
| @@ -2800,12 +2796,13 @@ private: | |||
| 2800 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2796 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2801 | const std::string z = | 2797 | const std::string z = |
| 2802 | regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset); | 2798 | regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset); |
| 2803 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | 2799 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + |
| 2800 | ");"); | ||
| 2804 | } else { | 2801 | } else { |
| 2805 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2802 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2806 | const std::string y = | 2803 | const std::string y = |
| 2807 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2804 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2808 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2805 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 2809 | } | 2806 | } |
| 2810 | } else { | 2807 | } else { |
| 2811 | if (depth_compare) { | 2808 | if (depth_compare) { |
| @@ -2813,11 +2810,12 @@ private: | |||
| 2813 | const std::string y = | 2810 | const std::string y = |
| 2814 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2811 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2815 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | 2812 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); |
| 2816 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | 2813 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + |
| 2814 | ");"); | ||
| 2817 | } else { | 2815 | } else { |
| 2818 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2816 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2819 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | 2817 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); |
| 2820 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2818 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 2821 | } | 2819 | } |
| 2822 | } | 2820 | } |
| 2823 | } | 2821 | } |
| @@ -2827,7 +2825,7 @@ private: | |||
| 2827 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2825 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2828 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2826 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2829 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | 2827 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); |
| 2830 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | 2828 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"); |
| 2831 | break; | 2829 | break; |
| 2832 | } | 2830 | } |
| 2833 | default: | 2831 | default: |
| @@ -2837,42 +2835,37 @@ private: | |||
| 2837 | // Fallback to interpreting as a 2D texture for now | 2835 | // Fallback to interpreting as a 2D texture for now |
| 2838 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2836 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2839 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | 2837 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); |
| 2840 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2838 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 2841 | texture_type = Tegra::Shader::TextureType::Texture2D; | 2839 | texture_type = Tegra::Shader::TextureType::Texture2D; |
| 2842 | is_array = false; | 2840 | is_array = false; |
| 2843 | } | 2841 | } |
| 2844 | const std::string sampler = | 2842 | const std::string sampler = |
| 2845 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); | 2843 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); |
| 2846 | std::string texture; | 2844 | |
| 2847 | switch (process_mode) { | 2845 | std::string texture = [&]() { |
| 2848 | case Tegra::Shader::TextureProcessMode::None: { | 2846 | switch (process_mode) { |
| 2849 | texture = "texture(" + sampler + ", coords)"; | 2847 | case Tegra::Shader::TextureProcessMode::None: |
| 2850 | break; | 2848 | return "texture(" + sampler + ", coords)"; |
| 2851 | } | 2849 | case Tegra::Shader::TextureProcessMode::LZ: |
| 2852 | case Tegra::Shader::TextureProcessMode::LZ: { | 2850 | if (depth_compare && is_array) { |
| 2853 | if (depth_compare && is_array) { | 2851 | return "texture(" + sampler + ", coords)"; |
| 2854 | texture = "texture(" + sampler + ", coords)"; | 2852 | } else { |
| 2855 | } else { | 2853 | return "textureLod(" + sampler + ", coords, 0.0)"; |
| 2856 | texture = "textureLod(" + sampler + ", coords, 0.0)"; | 2854 | } |
| 2855 | break; | ||
| 2856 | case Tegra::Shader::TextureProcessMode::LL: | ||
| 2857 | return "textureLod(" + sampler + ", coords, lod_value)"; | ||
| 2858 | default: | ||
| 2859 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", | ||
| 2860 | static_cast<u32>(instr.texs.GetTextureProcessMode())); | ||
| 2861 | return "texture(" + sampler + ", coords)"; | ||
| 2857 | } | 2862 | } |
| 2858 | break; | 2863 | }(); |
| 2859 | } | 2864 | if (depth_compare) { |
| 2860 | case Tegra::Shader::TextureProcessMode::LL: { | 2865 | texture = "vec4(" + texture + ')'; |
| 2861 | texture = "textureLod(" + sampler + ", coords, " + lod_value + ')'; | ||
| 2862 | break; | ||
| 2863 | } | ||
| 2864 | default: { | ||
| 2865 | texture = "texture(" + sampler + ", coords)"; | ||
| 2866 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", | ||
| 2867 | static_cast<u32>(instr.texs.GetTextureProcessMode())); | ||
| 2868 | } | ||
| 2869 | } | ||
| 2870 | if (!depth_compare) { | ||
| 2871 | WriteTexsInstruction(instr, coord, texture); | ||
| 2872 | } else { | ||
| 2873 | WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); | ||
| 2874 | } | 2866 | } |
| 2875 | 2867 | ||
| 2868 | WriteTexsInstruction(instr, texture); | ||
| 2876 | break; | 2869 | break; |
| 2877 | } | 2870 | } |
| 2878 | case OpCode::Id::TLDS: { | 2871 | case OpCode::Id::TLDS: { |
| @@ -2891,15 +2884,12 @@ private: | |||
| 2891 | 2884 | ||
| 2892 | u32 extra_op_offset = 0; | 2885 | u32 extra_op_offset = 0; |
| 2893 | 2886 | ||
| 2894 | // Scope to avoid variable name overlaps. | 2887 | ShaderScopedScope scope = shader.Scope(); |
| 2895 | shader.AddLine('{'); | ||
| 2896 | ++shader.scope; | ||
| 2897 | std::string coords; | ||
| 2898 | 2888 | ||
| 2899 | switch (texture_type) { | 2889 | switch (texture_type) { |
| 2900 | case Tegra::Shader::TextureType::Texture1D: { | 2890 | case Tegra::Shader::TextureType::Texture1D: { |
| 2901 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); | 2891 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); |
| 2902 | coords = "float coords = " + x + ';'; | 2892 | shader.AddLine("float coords = " + x + ';'); |
| 2903 | break; | 2893 | break; |
| 2904 | } | 2894 | } |
| 2905 | case Tegra::Shader::TextureType::Texture2D: { | 2895 | case Tegra::Shader::TextureType::Texture2D: { |
| @@ -2908,7 +2898,7 @@ private: | |||
| 2908 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); | 2898 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); |
| 2909 | const std::string y = regs.GetRegisterAsInteger(instr.gpr20); | 2899 | const std::string y = regs.GetRegisterAsInteger(instr.gpr20); |
| 2910 | // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); | 2900 | // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); |
| 2911 | coords = "ivec2 coords = ivec2(" + x + ", " + y + ");"; | 2901 | shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); |
| 2912 | extra_op_offset = 1; | 2902 | extra_op_offset = 1; |
| 2913 | break; | 2903 | break; |
| 2914 | } | 2904 | } |
| @@ -2917,35 +2907,29 @@ private: | |||
| 2917 | } | 2907 | } |
| 2918 | const std::string sampler = | 2908 | const std::string sampler = |
| 2919 | GetSampler(instr.sampler, texture_type, is_array, false); | 2909 | GetSampler(instr.sampler, texture_type, is_array, false); |
| 2920 | std::string texture = "texelFetch(" + sampler + ", coords, 0)"; | ||
| 2921 | switch (instr.tlds.GetTextureProcessMode()) { | ||
| 2922 | case Tegra::Shader::TextureProcessMode::LZ: { | ||
| 2923 | texture = "texelFetch(" + sampler + ", coords, 0)"; | ||
| 2924 | break; | ||
| 2925 | } | ||
| 2926 | case Tegra::Shader::TextureProcessMode::LL: { | ||
| 2927 | shader.AddLine( | ||
| 2928 | "float lod = " + | ||
| 2929 | regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';'); | ||
| 2930 | texture = "texelFetch(" + sampler + ", coords, lod)"; | ||
| 2931 | break; | ||
| 2932 | } | ||
| 2933 | default: { | ||
| 2934 | texture = "texelFetch(" + sampler + ", coords, 0)"; | ||
| 2935 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", | ||
| 2936 | static_cast<u32>(instr.tlds.GetTextureProcessMode())); | ||
| 2937 | } | ||
| 2938 | } | ||
| 2939 | WriteTexsInstruction(instr, coords, texture); | ||
| 2940 | 2910 | ||
| 2941 | --shader.scope; | 2911 | const std::string texture = [&]() { |
| 2942 | shader.AddLine('}'); | 2912 | switch (instr.tlds.GetTextureProcessMode()) { |
| 2913 | case Tegra::Shader::TextureProcessMode::LZ: | ||
| 2914 | return "texelFetch(" + sampler + ", coords, 0)"; | ||
| 2915 | case Tegra::Shader::TextureProcessMode::LL: | ||
| 2916 | shader.AddLine( | ||
| 2917 | "float lod = " + | ||
| 2918 | regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';'); | ||
| 2919 | return "texelFetch(" + sampler + ", coords, lod)"; | ||
| 2920 | default: | ||
| 2921 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", | ||
| 2922 | static_cast<u32>(instr.tlds.GetTextureProcessMode())); | ||
| 2923 | return "texelFetch(" + sampler + ", coords, 0)"; | ||
| 2924 | } | ||
| 2925 | }(); | ||
| 2926 | |||
| 2927 | WriteTexsInstruction(instr, texture); | ||
| 2943 | break; | 2928 | break; |
| 2944 | } | 2929 | } |
| 2945 | case OpCode::Id::TLD4: { | 2930 | case OpCode::Id::TLD4: { |
| 2946 | ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); | 2931 | ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); |
| 2947 | ASSERT(instr.tld4.array == 0); | 2932 | ASSERT(instr.tld4.array == 0); |
| 2948 | std::string coord; | ||
| 2949 | 2933 | ||
| 2950 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 2934 | UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| 2951 | "NODEP is not implemented"); | 2935 | "NODEP is not implemented"); |
| @@ -2962,10 +2946,7 @@ private: | |||
| 2962 | if (depth_compare) | 2946 | if (depth_compare) |
| 2963 | num_coordinates += 1; | 2947 | num_coordinates += 1; |
| 2964 | 2948 | ||
| 2965 | // Add an extra scope and declare the texture coords inside to prevent | 2949 | const auto scope = shader.Scope(); |
| 2966 | // overwriting them in case they are used as outputs of the texs instruction. | ||
| 2967 | shader.AddLine('{'); | ||
| 2968 | ++shader.scope; | ||
| 2969 | 2950 | ||
| 2970 | switch (num_coordinates) { | 2951 | switch (num_coordinates) { |
| 2971 | case 2: { | 2952 | case 2: { |
| @@ -2996,23 +2977,19 @@ private: | |||
| 2996 | const std::string texture = "textureGather(" + sampler + ", coords, " + | 2977 | const std::string texture = "textureGather(" + sampler + ", coords, " + |
| 2997 | std::to_string(instr.tld4.component) + ')'; | 2978 | std::to_string(instr.tld4.component) + ')'; |
| 2998 | 2979 | ||
| 2999 | if (!depth_compare) { | 2980 | if (depth_compare) { |
| 3000 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); | 2981 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); |
| 2982 | } else { | ||
| 3001 | std::size_t dest_elem{}; | 2983 | std::size_t dest_elem{}; |
| 3002 | for (std::size_t elem = 0; elem < 4; ++elem) { | 2984 | for (std::size_t elem = 0; elem < 4; ++elem) { |
| 3003 | if (!instr.tex.IsComponentEnabled(elem)) { | 2985 | if (!instr.tex.IsComponentEnabled(elem)) { |
| 3004 | // Skip disabled components | 2986 | // Skip disabled components |
| 3005 | continue; | 2987 | continue; |
| 3006 | } | 2988 | } |
| 3007 | regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, | 2989 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); |
| 3008 | dest_elem); | ||
| 3009 | ++dest_elem; | 2990 | ++dest_elem; |
| 3010 | } | 2991 | } |
| 3011 | } else { | ||
| 3012 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); | ||
| 3013 | } | 2992 | } |
| 3014 | --shader.scope; | ||
| 3015 | shader.AddLine('}'); | ||
| 3016 | break; | 2993 | break; |
| 3017 | } | 2994 | } |
| 3018 | case OpCode::Id::TLD4S: { | 2995 | case OpCode::Id::TLD4S: { |
| @@ -3023,10 +3000,7 @@ private: | |||
| 3023 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | 3000 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), |
| 3024 | "AOFFI is not implemented"); | 3001 | "AOFFI is not implemented"); |
| 3025 | 3002 | ||
| 3026 | // Scope to avoid variable name overlaps. | 3003 | const auto scope = shader.Scope(); |
| 3027 | shader.AddLine('{'); | ||
| 3028 | ++shader.scope; | ||
| 3029 | std::string coords; | ||
| 3030 | 3004 | ||
| 3031 | const bool depth_compare = | 3005 | const bool depth_compare = |
| 3032 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | 3006 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| @@ -3035,33 +3009,29 @@ private: | |||
| 3035 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 3009 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| 3036 | const std::string sampler = GetSampler( | 3010 | const std::string sampler = GetSampler( |
| 3037 | instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); | 3011 | instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); |
| 3038 | if (!depth_compare) { | 3012 | if (depth_compare) { |
| 3039 | coords = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | ||
| 3040 | } else { | ||
| 3041 | // Note: TLD4S coordinate encoding works just like TEXS's | 3013 | // Note: TLD4S coordinate encoding works just like TEXS's |
| 3042 | const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 3014 | const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 3043 | coords = "vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");"; | 3015 | shader.AddLine("vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");"); |
| 3044 | } | ||
| 3045 | const std::string texture = "textureGather(" + sampler + ", coords, " + | ||
| 3046 | std::to_string(instr.tld4s.component) + ')'; | ||
| 3047 | |||
| 3048 | if (!depth_compare) { | ||
| 3049 | WriteTexsInstruction(instr, coords, texture); | ||
| 3050 | } else { | 3016 | } else { |
| 3051 | WriteTexsInstruction(instr, coords, "vec4(" + texture + ')'); | 3017 | shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");"); |
| 3052 | } | 3018 | } |
| 3053 | 3019 | ||
| 3054 | --shader.scope; | 3020 | std::string texture = "textureGather(" + sampler + ", coords, " + |
| 3055 | shader.AddLine('}'); | 3021 | std::to_string(instr.tld4s.component) + ')'; |
| 3022 | if (depth_compare) { | ||
| 3023 | texture = "vec4(" + texture + ')'; | ||
| 3024 | } | ||
| 3025 | WriteTexsInstruction(instr, texture); | ||
| 3056 | break; | 3026 | break; |
| 3057 | } | 3027 | } |
| 3058 | case OpCode::Id::TXQ: { | 3028 | case OpCode::Id::TXQ: { |
| 3059 | UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 3029 | UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| 3060 | "NODEP is not implemented"); | 3030 | "NODEP is not implemented"); |
| 3061 | 3031 | ||
| 3062 | ++shader.scope; | 3032 | const auto scope = shader.Scope(); |
| 3063 | shader.AddLine('{'); | 3033 | |
| 3064 | // TODO: the new commits on the texture refactor, change the way samplers work. | 3034 | // TODO: The new commits on the texture refactor, change the way samplers work. |
| 3065 | // Sadly, not all texture instructions specify the type of texture their sampler | 3035 | // Sadly, not all texture instructions specify the type of texture their sampler |
| 3066 | // uses. This must be fixed at a later instance. | 3036 | // uses. This must be fixed at a later instance. |
| 3067 | const std::string sampler = | 3037 | const std::string sampler = |
| @@ -3072,7 +3042,8 @@ private: | |||
| 3072 | regs.GetRegisterAsInteger(instr.gpr8) + ')'; | 3042 | regs.GetRegisterAsInteger(instr.gpr8) + ')'; |
| 3073 | const std::string mip_level = "textureQueryLevels(" + sampler + ')'; | 3043 | const std::string mip_level = "textureQueryLevels(" + sampler + ')'; |
| 3074 | shader.AddLine("ivec2 sizes = " + texture + ';'); | 3044 | shader.AddLine("ivec2 sizes = " + texture + ';'); |
| 3075 | regs.SetRegisterToInteger(instr.gpr0, true, 0, "sizes.x", 1, 1); | 3045 | |
| 3046 | regs.SetRegisterToInteger(instr.gpr0.Value() + 0, true, 0, "sizes.x", 1, 1); | ||
| 3076 | regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1); | 3047 | regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1); |
| 3077 | regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1); | 3048 | regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1); |
| 3078 | regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1); | 3049 | regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1); |
| @@ -3083,8 +3054,6 @@ private: | |||
| 3083 | static_cast<u32>(instr.txq.query_type.Value())); | 3054 | static_cast<u32>(instr.txq.query_type.Value())); |
| 3084 | } | 3055 | } |
| 3085 | } | 3056 | } |
| 3086 | --shader.scope; | ||
| 3087 | shader.AddLine('}'); | ||
| 3088 | break; | 3057 | break; |
| 3089 | } | 3058 | } |
| 3090 | case OpCode::Id::TMML: { | 3059 | case OpCode::Id::TMML: { |
| @@ -3099,17 +3068,18 @@ private: | |||
| 3099 | const std::string sampler = | 3068 | const std::string sampler = |
| 3100 | GetSampler(instr.sampler, texture_type, is_array, false); | 3069 | GetSampler(instr.sampler, texture_type, is_array, false); |
| 3101 | 3070 | ||
| 3102 | // TODO: add coordinates for different samplers once other texture types are | 3071 | const auto scope = shader.Scope(); |
| 3072 | |||
| 3073 | // TODO: Add coordinates for different samplers once other texture types are | ||
| 3103 | // implemented. | 3074 | // implemented. |
| 3104 | std::string coord; | ||
| 3105 | switch (texture_type) { | 3075 | switch (texture_type) { |
| 3106 | case Tegra::Shader::TextureType::Texture1D: { | 3076 | case Tegra::Shader::TextureType::Texture1D: { |
| 3107 | coord = "float coords = " + x + ';'; | 3077 | shader.AddLine("float coords = " + x + ';'); |
| 3108 | break; | 3078 | break; |
| 3109 | } | 3079 | } |
| 3110 | case Tegra::Shader::TextureType::Texture2D: { | 3080 | case Tegra::Shader::TextureType::Texture2D: { |
| 3111 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 3081 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 3112 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 3082 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 3113 | break; | 3083 | break; |
| 3114 | } | 3084 | } |
| 3115 | default: | 3085 | default: |
| @@ -3117,22 +3087,15 @@ private: | |||
| 3117 | 3087 | ||
| 3118 | // Fallback to interpreting as a 2D texture for now | 3088 | // Fallback to interpreting as a 2D texture for now |
| 3119 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 3089 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 3120 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 3090 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 3121 | texture_type = Tegra::Shader::TextureType::Texture2D; | 3091 | texture_type = Tegra::Shader::TextureType::Texture2D; |
| 3122 | } | 3092 | } |
| 3123 | // Add an extra scope and declare the texture coords inside to prevent | 3093 | |
| 3124 | // overwriting them in case they are used as outputs of the texs instruction. | ||
| 3125 | shader.AddLine('{'); | ||
| 3126 | ++shader.scope; | ||
| 3127 | shader.AddLine(coord); | ||
| 3128 | const std::string texture = "textureQueryLod(" + sampler + ", coords)"; | 3094 | const std::string texture = "textureQueryLod(" + sampler + ", coords)"; |
| 3129 | const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);"; | 3095 | shader.AddLine("vec2 tmp = " + texture + " * vec2(256.0, 256.0);"); |
| 3130 | shader.AddLine(tmp); | ||
| 3131 | 3096 | ||
| 3132 | regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1); | 3097 | regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1); |
| 3133 | regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1); | 3098 | regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1); |
| 3134 | --shader.scope; | ||
| 3135 | shader.AddLine('}'); | ||
| 3136 | break; | 3099 | break; |
| 3137 | } | 3100 | } |
| 3138 | default: { | 3101 | default: { |