diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 125 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 50 |
2 files changed, 143 insertions, 32 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 841647ebe..172ba8335 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -443,13 +443,12 @@ public: | |||
| 443 | } | 443 | } |
| 444 | declarations.AddNewLine(); | 444 | declarations.AddNewLine(); |
| 445 | 445 | ||
| 446 | // Append the sampler2D array for the used textures. | 446 | const auto& samplers = GetSamplers(); |
| 447 | const size_t num_samplers = used_samplers.size(); | 447 | for (const auto& sampler : samplers) { |
| 448 | if (num_samplers > 0) { | 448 | declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() + |
| 449 | declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' + | 449 | ';'); |
| 450 | std::to_string(num_samplers) + "];"); | ||
| 451 | declarations.AddNewLine(); | ||
| 452 | } | 450 | } |
| 451 | declarations.AddNewLine(); | ||
| 453 | } | 452 | } |
| 454 | 453 | ||
| 455 | /// Returns a list of constant buffer declarations | 454 | /// Returns a list of constant buffer declarations |
| @@ -461,13 +460,14 @@ public: | |||
| 461 | } | 460 | } |
| 462 | 461 | ||
| 463 | /// Returns a list of samplers used in the shader | 462 | /// Returns a list of samplers used in the shader |
| 464 | std::vector<SamplerEntry> GetSamplers() const { | 463 | const std::vector<SamplerEntry>& GetSamplers() const { |
| 465 | return used_samplers; | 464 | return used_samplers; |
| 466 | } | 465 | } |
| 467 | 466 | ||
| 468 | /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if | 467 | /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if |
| 469 | /// necessary. | 468 | /// necessary. |
| 470 | std::string AccessSampler(const Sampler& sampler) { | 469 | std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, |
| 470 | bool is_array) { | ||
| 471 | size_t offset = static_cast<size_t>(sampler.index.Value()); | 471 | size_t offset = static_cast<size_t>(sampler.index.Value()); |
| 472 | 472 | ||
| 473 | // If this sampler has already been used, return the existing mapping. | 473 | // If this sampler has already been used, return the existing mapping. |
| @@ -476,12 +476,13 @@ public: | |||
| 476 | [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); | 476 | [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); |
| 477 | 477 | ||
| 478 | if (itr != used_samplers.end()) { | 478 | if (itr != used_samplers.end()) { |
| 479 | ASSERT(itr->GetType() == type && itr->IsArray() == is_array); | ||
| 479 | return itr->GetName(); | 480 | return itr->GetName(); |
| 480 | } | 481 | } |
| 481 | 482 | ||
| 482 | // Otherwise create a new mapping for this sampler | 483 | // Otherwise create a new mapping for this sampler |
| 483 | size_t next_index = used_samplers.size(); | 484 | size_t next_index = used_samplers.size(); |
| 484 | SamplerEntry entry{stage, offset, next_index}; | 485 | SamplerEntry entry{stage, offset, next_index, type, is_array}; |
| 485 | used_samplers.emplace_back(entry); | 486 | used_samplers.emplace_back(entry); |
| 486 | return entry.GetName(); | 487 | return entry.GetName(); |
| 487 | } | 488 | } |
| @@ -722,8 +723,8 @@ private: | |||
| 722 | } | 723 | } |
| 723 | 724 | ||
| 724 | /// Generates code representing a texture sampler. | 725 | /// Generates code representing a texture sampler. |
| 725 | std::string GetSampler(const Sampler& sampler) { | 726 | std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) { |
| 726 | return regs.AccessSampler(sampler); | 727 | return regs.AccessSampler(sampler, type, is_array); |
| 727 | } | 728 | } |
| 728 | 729 | ||
| 729 | /** | 730 | /** |
| @@ -1753,10 +1754,35 @@ private: | |||
| 1753 | break; | 1754 | break; |
| 1754 | } | 1755 | } |
| 1755 | case OpCode::Id::TEX: { | 1756 | case OpCode::Id::TEX: { |
| 1756 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1757 | ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented"); |
| 1757 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 1758 | Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; |
| 1758 | const std::string sampler = GetSampler(instr.sampler); | 1759 | std::string coord; |
| 1759 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 1760 | |
| 1761 | switch (texture_type) { | ||
| 1762 | case Tegra::Shader::TextureType::Texture1D: { | ||
| 1763 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1764 | coord = "float coords = " + x + ';'; | ||
| 1765 | break; | ||
| 1766 | } | ||
| 1767 | case Tegra::Shader::TextureType::Texture2D: { | ||
| 1768 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1769 | std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 1770 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1771 | break; | ||
| 1772 | } | ||
| 1773 | default: | ||
| 1774 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | ||
| 1775 | static_cast<u32>(texture_type)); | ||
| 1776 | UNREACHABLE(); | ||
| 1777 | |||
| 1778 | // Fallback to interpreting as a 2D texture for now | ||
| 1779 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1780 | std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 1781 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1782 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 1783 | } | ||
| 1784 | |||
| 1785 | const std::string sampler = GetSampler(instr.sampler, texture_type, false); | ||
| 1760 | // Add an extra scope and declare the texture coords inside to prevent | 1786 | // Add an extra scope and declare the texture coords inside to prevent |
| 1761 | // overwriting them in case they are used as outputs of the texs instruction. | 1787 | // overwriting them in case they are used as outputs of the texs instruction. |
| 1762 | shader.AddLine("{"); | 1788 | shader.AddLine("{"); |
| @@ -1778,20 +1804,65 @@ private: | |||
| 1778 | break; | 1804 | break; |
| 1779 | } | 1805 | } |
| 1780 | case OpCode::Id::TEXS: { | 1806 | case OpCode::Id::TEXS: { |
| 1781 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1807 | std::string coord; |
| 1782 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); | 1808 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; |
| 1783 | const std::string sampler = GetSampler(instr.sampler); | 1809 | bool is_array{instr.texs.IsArrayTexture()}; |
| 1784 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 1810 | |
| 1811 | switch (texture_type) { | ||
| 1812 | case Tegra::Shader::TextureType::Texture2D: { | ||
| 1813 | if (is_array) { | ||
| 1814 | std::string index = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 1815 | std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 1816 | std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1817 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; | ||
| 1818 | } else { | ||
| 1819 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1820 | std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1821 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1822 | } | ||
| 1823 | break; | ||
| 1824 | } | ||
| 1825 | default: | ||
| 1826 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | ||
| 1827 | static_cast<u32>(texture_type)); | ||
| 1828 | UNREACHABLE(); | ||
| 1785 | 1829 | ||
| 1830 | // Fallback to interpreting as a 2D texture for now | ||
| 1831 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1832 | std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1833 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 1834 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 1835 | is_array = false; | ||
| 1836 | } | ||
| 1837 | const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); | ||
| 1786 | const std::string texture = "texture(" + sampler + ", coords)"; | 1838 | const std::string texture = "texture(" + sampler + ", coords)"; |
| 1787 | WriteTexsInstruction(instr, coord, texture); | 1839 | WriteTexsInstruction(instr, coord, texture); |
| 1788 | break; | 1840 | break; |
| 1789 | } | 1841 | } |
| 1790 | case OpCode::Id::TLDS: { | 1842 | case OpCode::Id::TLDS: { |
| 1791 | const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); | 1843 | ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D); |
| 1792 | const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20); | 1844 | ASSERT(instr.tlds.IsArrayTexture() == false); |
| 1793 | const std::string sampler = GetSampler(instr.sampler); | 1845 | std::string coord; |
| 1794 | const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");"; | 1846 | |
| 1847 | switch (instr.tlds.GetTextureType()) { | ||
| 1848 | case Tegra::Shader::TextureType::Texture2D: { | ||
| 1849 | if (instr.tlds.IsArrayTexture()) { | ||
| 1850 | LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture"); | ||
| 1851 | UNREACHABLE(); | ||
| 1852 | } else { | ||
| 1853 | std::string x = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 1854 | std::string y = regs.GetRegisterAsInteger(instr.gpr20); | ||
| 1855 | coord = "ivec2 coords = ivec2(" + x + ", " + y + ");"; | ||
| 1856 | } | ||
| 1857 | break; | ||
| 1858 | } | ||
| 1859 | default: | ||
| 1860 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | ||
| 1861 | static_cast<u32>(instr.tlds.GetTextureType())); | ||
| 1862 | UNREACHABLE(); | ||
| 1863 | } | ||
| 1864 | const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(), | ||
| 1865 | instr.tlds.IsArrayTexture()); | ||
| 1795 | const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; | 1866 | const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; |
| 1796 | WriteTexsInstruction(instr, coord, texture); | 1867 | WriteTexsInstruction(instr, coord, texture); |
| 1797 | break; | 1868 | break; |
| @@ -1799,7 +1870,7 @@ private: | |||
| 1799 | case OpCode::Id::TLD4: { | 1870 | case OpCode::Id::TLD4: { |
| 1800 | ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); | 1871 | ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); |
| 1801 | ASSERT(instr.tld4.array == 0); | 1872 | ASSERT(instr.tld4.array == 0); |
| 1802 | std::string coord{}; | 1873 | std::string coord; |
| 1803 | 1874 | ||
| 1804 | switch (instr.tld4.texture_type) { | 1875 | switch (instr.tld4.texture_type) { |
| 1805 | case Tegra::Shader::TextureType::Texture2D: { | 1876 | case Tegra::Shader::TextureType::Texture2D: { |
| @@ -1814,7 +1885,8 @@ private: | |||
| 1814 | UNREACHABLE(); | 1885 | UNREACHABLE(); |
| 1815 | } | 1886 | } |
| 1816 | 1887 | ||
| 1817 | const std::string sampler = GetSampler(instr.sampler); | 1888 | const std::string sampler = |
| 1889 | GetSampler(instr.sampler, instr.tld4.texture_type, false); | ||
| 1818 | // Add an extra scope and declare the texture coords inside to prevent | 1890 | // Add an extra scope and declare the texture coords inside to prevent |
| 1819 | // overwriting them in case they are used as outputs of the texs instruction. | 1891 | // overwriting them in case they are used as outputs of the texs instruction. |
| 1820 | shader.AddLine("{"); | 1892 | shader.AddLine("{"); |
| @@ -1840,7 +1912,8 @@ private: | |||
| 1840 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1912 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 1841 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); | 1913 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); |
| 1842 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 1914 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| 1843 | const std::string sampler = GetSampler(instr.sampler); | 1915 | const std::string sampler = |
| 1916 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); | ||
| 1844 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 1917 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; |
| 1845 | const std::string texture = "textureGather(" + sampler + ", coords, " + | 1918 | const std::string texture = "textureGather(" + sampler + ", coords, " + |
| 1846 | std::to_string(instr.tld4s.component) + ')'; | 1919 | std::to_string(instr.tld4s.component) + ')'; |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index cbb2090ea..a43e2997b 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/engines/shader_bytecode.h" | ||
| 12 | 13 | ||
| 13 | namespace OpenGL::GLShader { | 14 | namespace OpenGL::GLShader { |
| 14 | 15 | ||
| @@ -73,8 +74,9 @@ class SamplerEntry { | |||
| 73 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 74 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 74 | 75 | ||
| 75 | public: | 76 | public: |
| 76 | SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index) | 77 | SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index, |
| 77 | : offset(offset), stage(stage), sampler_index(index) {} | 78 | Tegra::Shader::TextureType type, bool is_array) |
| 79 | : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {} | ||
| 78 | 80 | ||
| 79 | size_t GetOffset() const { | 81 | size_t GetOffset() const { |
| 80 | return offset; | 82 | return offset; |
| @@ -89,8 +91,41 @@ public: | |||
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | std::string GetName() const { | 93 | std::string GetName() const { |
| 92 | return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' + | 94 | return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' + |
| 93 | std::to_string(sampler_index) + ']'; | 95 | std::to_string(sampler_index); |
| 96 | } | ||
| 97 | |||
| 98 | std::string GetTypeString() const { | ||
| 99 | using Tegra::Shader::TextureType; | ||
| 100 | std::string glsl_type; | ||
| 101 | |||
| 102 | switch (type) { | ||
| 103 | case TextureType::Texture1D: | ||
| 104 | glsl_type = "sampler1D"; | ||
| 105 | break; | ||
| 106 | case TextureType::Texture2D: | ||
| 107 | glsl_type = "sampler2D"; | ||
| 108 | break; | ||
| 109 | case TextureType::Texture3D: | ||
| 110 | glsl_type = "sampler3D"; | ||
| 111 | break; | ||
| 112 | case TextureType::TextureCube: | ||
| 113 | glsl_type = "samplerCube"; | ||
| 114 | break; | ||
| 115 | default: | ||
| 116 | UNIMPLEMENTED(); | ||
| 117 | } | ||
| 118 | if (is_array) | ||
| 119 | glsl_type += "Array"; | ||
| 120 | return glsl_type; | ||
| 121 | } | ||
| 122 | |||
| 123 | Tegra::Shader::TextureType GetType() const { | ||
| 124 | return type; | ||
| 125 | } | ||
| 126 | |||
| 127 | bool IsArray() const { | ||
| 128 | return is_array; | ||
| 94 | } | 129 | } |
| 95 | 130 | ||
| 96 | u32 GetHash() const { | 131 | u32 GetHash() const { |
| @@ -105,11 +140,14 @@ private: | |||
| 105 | static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { | 140 | static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { |
| 106 | "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", | 141 | "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", |
| 107 | }; | 142 | }; |
| 143 | |||
| 108 | /// Offset in TSC memory from which to read the sampler object, as specified by the sampling | 144 | /// Offset in TSC memory from which to read the sampler object, as specified by the sampling |
| 109 | /// instruction. | 145 | /// instruction. |
| 110 | size_t offset; | 146 | size_t offset; |
| 111 | Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. | 147 | Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. |
| 112 | size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. | 148 | size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. |
| 149 | Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc) | ||
| 150 | bool is_array; ///< Whether the texture is being sampled as an array texture or not. | ||
| 113 | }; | 151 | }; |
| 114 | 152 | ||
| 115 | struct ShaderEntries { | 153 | struct ShaderEntries { |