diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 436 |
1 files changed, 177 insertions, 259 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index d235bfcd4..8d68156bf 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -1515,6 +1515,161 @@ private: | |||
| 1515 | } | 1515 | } |
| 1516 | } | 1516 | } |
| 1517 | 1517 | ||
| 1518 | std::pair<size_t, std::string> ValidateAndGetCoordinateElement( | ||
| 1519 | const Tegra::Shader::TextureType texture_type, const bool depth_compare, | ||
| 1520 | const bool is_array, const bool lod_bias_enabled, size_t max_coords, size_t max_inputs) { | ||
| 1521 | const size_t coord_count = TextureCoordinates(texture_type); | ||
| 1522 | |||
| 1523 | size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0); | ||
| 1524 | const size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0); | ||
| 1525 | if (total_coord_count > max_coords || total_reg_count > max_inputs) { | ||
| 1526 | UNIMPLEMENTED_MSG("Unsupported Texture operation"); | ||
| 1527 | total_coord_count = std::min(total_coord_count, max_coords); | ||
| 1528 | } | ||
| 1529 | // 1D.DC opengl is using a vec3 but 2nd component is ignored later. | ||
| 1530 | total_coord_count += | ||
| 1531 | (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) | ||
| 1532 | ? 1 | ||
| 1533 | : 0; | ||
| 1534 | |||
| 1535 | constexpr std::array<const char*, 5> coord_container{ | ||
| 1536 | {"", "float coord = (", "vec2 coord = vec2(", "vec3 coord = vec3(", | ||
| 1537 | "vec4 coord = vec4("}}; | ||
| 1538 | |||
| 1539 | return std::pair<size_t, std::string>(coord_count, coord_container[total_coord_count]); | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | std::string GetTextureCode(const Tegra::Shader::Instruction& instr, | ||
| 1543 | const Tegra::Shader::TextureType texture_type, | ||
| 1544 | const Tegra::Shader::TextureProcessMode process_mode, | ||
| 1545 | const bool depth_compare, const bool is_array, | ||
| 1546 | const size_t bias_offset) { | ||
| 1547 | |||
| 1548 | if ((texture_type == Tegra::Shader::TextureType::Texture3D && | ||
| 1549 | (is_array || depth_compare)) || | ||
| 1550 | (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && | ||
| 1551 | depth_compare)) { | ||
| 1552 | UNIMPLEMENTED_MSG("This method is not supported."); | ||
| 1553 | } | ||
| 1554 | |||
| 1555 | const std::string sampler = | ||
| 1556 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); | ||
| 1557 | |||
| 1558 | const bool lod_needed = process_mode == Tegra::Shader::TextureProcessMode::LZ || | ||
| 1559 | process_mode == Tegra::Shader::TextureProcessMode::LL || | ||
| 1560 | process_mode == Tegra::Shader::TextureProcessMode::LLA; | ||
| 1561 | |||
| 1562 | const bool gl_lod_supported = !( | ||
| 1563 | (texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) || | ||
| 1564 | (texture_type == Tegra::Shader::TextureType::TextureCube && !is_array && | ||
| 1565 | depth_compare)); | ||
| 1566 | |||
| 1567 | const std::string read_method = lod_needed && gl_lod_supported ? "textureLod(" : "texture("; | ||
| 1568 | std::string texture = read_method + sampler + ", coord"; | ||
| 1569 | |||
| 1570 | if (process_mode != Tegra::Shader::TextureProcessMode::None) { | ||
| 1571 | if (process_mode == Tegra::Shader::TextureProcessMode::LZ) { | ||
| 1572 | if (gl_lod_supported) { | ||
| 1573 | texture += ", 0"; | ||
| 1574 | } else { | ||
| 1575 | // Lod 0 is emulated by a big negative bias | ||
| 1576 | // in scenarios that are not supported by glsl | ||
| 1577 | texture += ", -1000"; | ||
| 1578 | } | ||
| 1579 | } else { | ||
| 1580 | // If present, lod or bias are always stored in the register indexed by the | ||
| 1581 | // gpr20 | ||
| 1582 | // field with an offset depending on the usage of the other registers | ||
| 1583 | texture += ',' + regs.GetRegisterAsFloat(instr.gpr20.Value() + bias_offset); | ||
| 1584 | } | ||
| 1585 | } | ||
| 1586 | texture += ")"; | ||
| 1587 | return texture; | ||
| 1588 | } | ||
| 1589 | |||
| 1590 | std::pair<std::string, std::string> GetTEXCode( | ||
| 1591 | const Instruction& instr, const Tegra::Shader::TextureType texture_type, | ||
| 1592 | const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare, | ||
| 1593 | const bool is_array) { | ||
| 1594 | const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None && | ||
| 1595 | process_mode != Tegra::Shader::TextureProcessMode::LZ); | ||
| 1596 | |||
| 1597 | const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement( | ||
| 1598 | texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5); | ||
| 1599 | // If enabled arrays index is always stored in the gpr8 field | ||
| 1600 | const u64 array_register = instr.gpr8.Value(); | ||
| 1601 | // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used | ||
| 1602 | const u64 coord_register = array_register + (is_array ? 1 : 0); | ||
| 1603 | |||
| 1604 | std::string coord = coord_dcl; | ||
| 1605 | for (size_t i = 0; i < coord_count;) { | ||
| 1606 | coord += regs.GetRegisterAsFloat(coord_register + i); | ||
| 1607 | ++i; | ||
| 1608 | if (i != coord_count) { | ||
| 1609 | coord += ','; | ||
| 1610 | } | ||
| 1611 | } | ||
| 1612 | // 1D.DC in opengl the 2nd component is ignored. | ||
| 1613 | if (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) { | ||
| 1614 | coord += ",0.0"; | ||
| 1615 | } | ||
| 1616 | if (depth_compare) { | ||
| 1617 | // Depth is always stored in the register signaled by gpr20 | ||
| 1618 | // or in the next register if lod or bias are used | ||
| 1619 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); | ||
| 1620 | coord += ',' + regs.GetRegisterAsFloat(depth_register); | ||
| 1621 | } | ||
| 1622 | if (is_array) { | ||
| 1623 | coord += ',' + regs.GetRegisterAsInteger(array_register); | ||
| 1624 | } | ||
| 1625 | coord += ");"; | ||
| 1626 | return std::make_pair( | ||
| 1627 | coord, GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0)); | ||
| 1628 | } | ||
| 1629 | |||
| 1630 | std::pair<std::string, std::string> GetTEXSCode( | ||
| 1631 | const Instruction& instr, const Tegra::Shader::TextureType texture_type, | ||
| 1632 | const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare, | ||
| 1633 | const bool is_array) { | ||
| 1634 | const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None && | ||
| 1635 | process_mode != Tegra::Shader::TextureProcessMode::LZ); | ||
| 1636 | |||
| 1637 | const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement( | ||
| 1638 | texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4); | ||
| 1639 | // If enabled arrays index is always stored in the gpr8 field | ||
| 1640 | const u64 array_register = instr.gpr8.Value(); | ||
| 1641 | // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used | ||
| 1642 | const u64 coord_register = array_register + (is_array ? 1 : 0); | ||
| 1643 | const u64 last_coord_register = | ||
| 1644 | (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2)) | ||
| 1645 | ? static_cast<u64>(instr.gpr20.Value()) | ||
| 1646 | : coord_register + 1; | ||
| 1647 | |||
| 1648 | std::string coord = coord_dcl; | ||
| 1649 | for (size_t i = 0; i < coord_count; ++i) { | ||
| 1650 | const bool last = (i == (coord_count - 1)) && (coord_count > 1); | ||
| 1651 | coord += regs.GetRegisterAsFloat(last ? last_coord_register : coord_register + i); | ||
| 1652 | if (!last) { | ||
| 1653 | coord += ','; | ||
| 1654 | } | ||
| 1655 | } | ||
| 1656 | |||
| 1657 | if (depth_compare) { | ||
| 1658 | // Depth is always stored in the register signaled by gpr20 | ||
| 1659 | // or in the next register if lod or bias are used | ||
| 1660 | const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0); | ||
| 1661 | coord += ',' + regs.GetRegisterAsFloat(depth_register); | ||
| 1662 | } | ||
| 1663 | if (is_array) { | ||
| 1664 | coord += ',' + regs.GetRegisterAsInteger(array_register); | ||
| 1665 | } | ||
| 1666 | coord += ");"; | ||
| 1667 | |||
| 1668 | return std::make_pair(coord, | ||
| 1669 | GetTextureCode(instr, texture_type, process_mode, depth_compare, | ||
| 1670 | is_array, (coord_count > 2 ? 1 : 0))); | ||
| 1671 | } | ||
| 1672 | |||
| 1518 | /** | 1673 | /** |
| 1519 | * Compiles a single instruction from Tegra to GLSL. | 1674 | * Compiles a single instruction from Tegra to GLSL. |
| 1520 | * @param offset the offset of the Tegra shader instruction. | 1675 | * @param offset the offset of the Tegra shader instruction. |
| @@ -2574,168 +2729,32 @@ private: | |||
| 2574 | case OpCode::Id::TEX: { | 2729 | case OpCode::Id::TEX: { |
| 2575 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; | 2730 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; |
| 2576 | const bool is_array = instr.tex.array != 0; | 2731 | const bool is_array = instr.tex.array != 0; |
| 2577 | 2732 | const bool depth_compare = | |
| 2733 | instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | ||
| 2734 | const auto process_mode = instr.tex.GetTextureProcessMode(); | ||
| 2578 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 2735 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| 2579 | "NODEP is not implemented"); | 2736 | "NODEP is not implemented"); |
| 2580 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | 2737 | UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), |
| 2581 | "AOFFI is not implemented"); | 2738 | "AOFFI is not implemented"); |
| 2582 | 2739 | ||
| 2583 | const bool depth_compare = | 2740 | const auto [coord, texture] = |
| 2584 | instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | 2741 | GetTEXCode(instr, texture_type, process_mode, depth_compare, is_array); |
| 2585 | u32 num_coordinates = TextureCoordinates(texture_type); | ||
| 2586 | u32 start_index = 0; | ||
| 2587 | std::string array_elem; | ||
| 2588 | if (is_array) { | ||
| 2589 | array_elem = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 2590 | start_index = 1; | ||
| 2591 | } | ||
| 2592 | const auto process_mode = instr.tex.GetTextureProcessMode(); | ||
| 2593 | u32 start_index_b = 0; | ||
| 2594 | std::string lod_value; | ||
| 2595 | if (process_mode != Tegra::Shader::TextureProcessMode::LZ && | ||
| 2596 | process_mode != Tegra::Shader::TextureProcessMode::None) { | ||
| 2597 | start_index_b = 1; | ||
| 2598 | lod_value = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2599 | } | ||
| 2600 | |||
| 2601 | std::string depth_value; | ||
| 2602 | if (depth_compare) { | ||
| 2603 | depth_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + start_index_b); | ||
| 2604 | } | ||
| 2605 | |||
| 2606 | bool depth_compare_extra = false; | ||
| 2607 | 2742 | ||
| 2608 | const auto scope = shader.Scope(); | 2743 | const auto scope = shader.Scope(); |
| 2609 | 2744 | shader.AddLine(coord); | |
| 2610 | switch (num_coordinates) { | ||
| 2611 | case 1: { | ||
| 2612 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); | ||
| 2613 | if (is_array) { | ||
| 2614 | if (depth_compare) { | ||
| 2615 | shader.AddLine("vec3 coords = vec3(" + x + ", " + depth_value + ", " + | ||
| 2616 | array_elem + ");"); | ||
| 2617 | } else { | ||
| 2618 | shader.AddLine("vec2 coords = vec2(" + x + ", " + array_elem + ");"); | ||
| 2619 | } | ||
| 2620 | } else { | ||
| 2621 | if (depth_compare) { | ||
| 2622 | shader.AddLine("vec2 coords = vec2(" + x + ", " + depth_value + ");"); | ||
| 2623 | } else { | ||
| 2624 | shader.AddLine("float coords = " + x + ';'); | ||
| 2625 | } | ||
| 2626 | } | ||
| 2627 | break; | ||
| 2628 | } | ||
| 2629 | case 2: { | ||
| 2630 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); | ||
| 2631 | const std::string y = | ||
| 2632 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1); | ||
| 2633 | if (is_array) { | ||
| 2634 | if (depth_compare) { | ||
| 2635 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + | ||
| 2636 | depth_value + ", " + array_elem + ");"); | ||
| 2637 | } else { | ||
| 2638 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + | ||
| 2639 | array_elem + ");"); | ||
| 2640 | } | ||
| 2641 | } else { | ||
| 2642 | if (depth_compare) { | ||
| 2643 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + | ||
| 2644 | depth_value + ");"); | ||
| 2645 | } else { | ||
| 2646 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); | ||
| 2647 | } | ||
| 2648 | } | ||
| 2649 | break; | ||
| 2650 | } | ||
| 2651 | case 3: { | ||
| 2652 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); | ||
| 2653 | const std::string y = | ||
| 2654 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1); | ||
| 2655 | const std::string z = | ||
| 2656 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2); | ||
| 2657 | if (is_array) { | ||
| 2658 | depth_compare_extra = depth_compare; | ||
| 2659 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + | ||
| 2660 | array_elem + ");"); | ||
| 2661 | } else { | ||
| 2662 | if (depth_compare) { | ||
| 2663 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + | ||
| 2664 | depth_value + ");"); | ||
| 2665 | } else { | ||
| 2666 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"); | ||
| 2667 | } | ||
| 2668 | } | ||
| 2669 | break; | ||
| 2670 | } | ||
| 2671 | default: | ||
| 2672 | UNIMPLEMENTED_MSG("Unhandled coordinates number {}", | ||
| 2673 | static_cast<u32>(num_coordinates)); | ||
| 2674 | |||
| 2675 | // Fallback to interpreting as a 2D texture for now | ||
| 2676 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2677 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2678 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); | ||
| 2679 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 2680 | } | ||
| 2681 | |||
| 2682 | const std::string sampler = | ||
| 2683 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); | ||
| 2684 | // Add an extra scope and declare the texture coords inside to prevent | ||
| 2685 | // overwriting them in case they are used as outputs of the texs instruction. | ||
| 2686 | |||
| 2687 | const std::string texture = [&]() { | ||
| 2688 | switch (instr.tex.GetTextureProcessMode()) { | ||
| 2689 | case Tegra::Shader::TextureProcessMode::None: | ||
| 2690 | if (depth_compare_extra) { | ||
| 2691 | return "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2692 | } | ||
| 2693 | return "texture(" + sampler + ", coords)"; | ||
| 2694 | case Tegra::Shader::TextureProcessMode::LZ: | ||
| 2695 | if (depth_compare_extra) { | ||
| 2696 | return "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2697 | } | ||
| 2698 | return "textureLod(" + sampler + ", coords, 0.0)"; | ||
| 2699 | case Tegra::Shader::TextureProcessMode::LB: | ||
| 2700 | case Tegra::Shader::TextureProcessMode::LBA: | ||
| 2701 | // TODO: Figure if A suffix changes the equation at all. | ||
| 2702 | if (depth_compare_extra) { | ||
| 2703 | LOG_WARNING( | ||
| 2704 | HW_GPU, | ||
| 2705 | "OpenGL Limitation: can't set bias value along depth compare"); | ||
| 2706 | return "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2707 | } | ||
| 2708 | return "texture(" + sampler + ", coords, " + lod_value + ')'; | ||
| 2709 | case Tegra::Shader::TextureProcessMode::LL: | ||
| 2710 | case Tegra::Shader::TextureProcessMode::LLA: | ||
| 2711 | // TODO: Figure if A suffix changes the equation at all. | ||
| 2712 | if (depth_compare_extra) { | ||
| 2713 | LOG_WARNING( | ||
| 2714 | HW_GPU, | ||
| 2715 | "OpenGL Limitation: can't set lod value along depth compare"); | ||
| 2716 | return "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2717 | } | ||
| 2718 | return "textureLod(" + sampler + ", coords, " + lod_value + ')'; | ||
| 2719 | default: | ||
| 2720 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", | ||
| 2721 | static_cast<u32>(instr.tex.GetTextureProcessMode())); | ||
| 2722 | if (depth_compare_extra) { | ||
| 2723 | return "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2724 | } | ||
| 2725 | return "texture(" + sampler + ", coords)"; | ||
| 2726 | } | ||
| 2727 | }(); | ||
| 2728 | 2745 | ||
| 2729 | if (depth_compare) { | 2746 | if (depth_compare) { |
| 2730 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); | 2747 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); |
| 2731 | } else { | 2748 | } else { |
| 2749 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); | ||
| 2732 | std::size_t dest_elem{}; | 2750 | std::size_t dest_elem{}; |
| 2733 | for (std::size_t elem = 0; elem < 4; ++elem) { | 2751 | for (std::size_t elem = 0; elem < 4; ++elem) { |
| 2734 | if (!instr.tex.IsComponentEnabled(elem)) { | 2752 | if (!instr.tex.IsComponentEnabled(elem)) { |
| 2735 | // Skip disabled components | 2753 | // Skip disabled components |
| 2736 | continue; | 2754 | continue; |
| 2737 | } | 2755 | } |
| 2738 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); | 2756 | regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, |
| 2757 | dest_elem); | ||
| 2739 | ++dest_elem; | 2758 | ++dest_elem; |
| 2740 | } | 2759 | } |
| 2741 | } | 2760 | } |
| @@ -2743,129 +2762,28 @@ private: | |||
| 2743 | } | 2762 | } |
| 2744 | case OpCode::Id::TEXS: { | 2763 | case OpCode::Id::TEXS: { |
| 2745 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; | 2764 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; |
| 2746 | bool is_array{instr.texs.IsArrayTexture()}; | 2765 | const bool is_array{instr.texs.IsArrayTexture()}; |
| 2747 | 2766 | const bool depth_compare = | |
| 2767 | instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | ||
| 2768 | const auto process_mode = instr.texs.GetTextureProcessMode(); | ||
| 2748 | UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 2769 | UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| 2749 | "NODEP is not implemented"); | 2770 | "NODEP is not implemented"); |
| 2750 | 2771 | ||
| 2751 | const auto scope = shader.Scope(); | 2772 | const auto scope = shader.Scope(); |
| 2752 | 2773 | ||
| 2753 | const bool depth_compare = | 2774 | const auto [coord, texture] = |
| 2754 | instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | 2775 | GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array); |
| 2755 | u32 num_coordinates = TextureCoordinates(texture_type); | ||
| 2756 | const auto process_mode = instr.texs.GetTextureProcessMode(); | ||
| 2757 | u32 lod_offset = 0; | ||
| 2758 | if (process_mode == Tegra::Shader::TextureProcessMode::LL) { | ||
| 2759 | if (num_coordinates > 2) { | ||
| 2760 | shader.AddLine("float lod_value = " + | ||
| 2761 | regs.GetRegisterAsFloat(instr.gpr20.Value() + 1) + ';'); | ||
| 2762 | lod_offset = 2; | ||
| 2763 | } else { | ||
| 2764 | shader.AddLine("float lod_value = " + regs.GetRegisterAsFloat(instr.gpr20) + | ||
| 2765 | ';'); | ||
| 2766 | lod_offset = 1; | ||
| 2767 | } | ||
| 2768 | } | ||
| 2769 | 2776 | ||
| 2770 | switch (num_coordinates) { | 2777 | shader.AddLine(coord); |
| 2771 | case 1: { | ||
| 2772 | shader.AddLine("float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';'); | ||
| 2773 | break; | ||
| 2774 | } | ||
| 2775 | case 2: { | ||
| 2776 | if (is_array) { | ||
| 2777 | if (depth_compare) { | ||
| 2778 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 2779 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2780 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2781 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | ||
| 2782 | shader.AddLine("vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + | ||
| 2783 | index + ");"); | ||
| 2784 | } else { | ||
| 2785 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 2786 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2787 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2788 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + index + | ||
| 2789 | ");"); | ||
| 2790 | } | ||
| 2791 | } else { | ||
| 2792 | if (lod_offset != 0) { | ||
| 2793 | if (depth_compare) { | ||
| 2794 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2795 | const std::string y = | ||
| 2796 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2797 | const std::string z = | ||
| 2798 | regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset); | ||
| 2799 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + | ||
| 2800 | ");"); | ||
| 2801 | } else { | ||
| 2802 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2803 | const std::string y = | ||
| 2804 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2805 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); | ||
| 2806 | } | ||
| 2807 | } else { | ||
| 2808 | if (depth_compare) { | ||
| 2809 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2810 | const std::string y = | ||
| 2811 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2812 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2813 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + | ||
| 2814 | ");"); | ||
| 2815 | } else { | ||
| 2816 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2817 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2818 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); | ||
| 2819 | } | ||
| 2820 | } | ||
| 2821 | } | ||
| 2822 | break; | ||
| 2823 | } | ||
| 2824 | case 3: { | ||
| 2825 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2826 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2827 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2828 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"); | ||
| 2829 | break; | ||
| 2830 | } | ||
| 2831 | default: | ||
| 2832 | UNIMPLEMENTED_MSG("Unhandled coordinates number {}", | ||
| 2833 | static_cast<u32>(num_coordinates)); | ||
| 2834 | 2778 | ||
| 2835 | // Fallback to interpreting as a 2D texture for now | 2779 | if (!depth_compare) { |
| 2836 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2780 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); |
| 2837 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2838 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); | ||
| 2839 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 2840 | is_array = false; | ||
| 2841 | } | ||
| 2842 | const std::string sampler = | ||
| 2843 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); | ||
| 2844 | 2781 | ||
| 2845 | std::string texture = [&]() { | 2782 | } else { |
| 2846 | switch (process_mode) { | 2783 | shader.AddLine("vec4 texture_tmp = vec4(" + texture + ");"); |
| 2847 | case Tegra::Shader::TextureProcessMode::None: | ||
| 2848 | return "texture(" + sampler + ", coords)"; | ||
| 2849 | case Tegra::Shader::TextureProcessMode::LZ: | ||
| 2850 | if (depth_compare && is_array) { | ||
| 2851 | return "texture(" + sampler + ", coords)"; | ||
| 2852 | } else { | ||
| 2853 | return "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)"; | ||
| 2862 | } | ||
| 2863 | }(); | ||
| 2864 | if (depth_compare) { | ||
| 2865 | texture = "vec4(" + texture + ')'; | ||
| 2866 | } | 2784 | } |
| 2867 | 2785 | ||
| 2868 | WriteTexsInstruction(instr, texture); | 2786 | WriteTexsInstruction(instr, "texture_tmp"); |
| 2869 | break; | 2787 | break; |
| 2870 | } | 2788 | } |
| 2871 | case OpCode::Id::TLDS: { | 2789 | case OpCode::Id::TLDS: { |
| @@ -3934,4 +3852,4 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u | |||
| 3934 | return {}; | 3852 | return {}; |
| 3935 | } | 3853 | } |
| 3936 | 3854 | ||
| 3937 | } // namespace OpenGL::GLShader::Decompiler | 3855 | } // namespace OpenGL::GLShader::Decompiler \ No newline at end of file |