diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 18 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 262 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 14 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 25 | ||||
| -rw-r--r-- | src/video_core/textures/texture.h | 13 |
6 files changed, 265 insertions, 69 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a91bc6dee..edcd5e451 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -662,10 +662,13 @@ void RasterizerOpenGL::SamplerInfo::Create() { | |||
| 662 | sampler.Create(); | 662 | sampler.Create(); |
| 663 | mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; | 663 | mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; |
| 664 | wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap; | 664 | wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap; |
| 665 | uses_depth_compare = false; | ||
| 666 | depth_compare_func = Tegra::Texture::DepthCompareFunc::Never; | ||
| 665 | 667 | ||
| 666 | // default is GL_LINEAR_MIPMAP_LINEAR | 668 | // default is GL_LINEAR_MIPMAP_LINEAR |
| 667 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 669 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 668 | // Other attributes have correct defaults | 670 | // Other attributes have correct defaults |
| 671 | glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); | ||
| 669 | } | 672 | } |
| 670 | 673 | ||
| 671 | void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { | 674 | void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { |
| @@ -693,6 +696,21 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | |||
| 693 | glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p)); | 696 | glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p)); |
| 694 | } | 697 | } |
| 695 | 698 | ||
| 699 | if (uses_depth_compare != (config.depth_compare_enabled == 1)) { | ||
| 700 | uses_depth_compare = (config.depth_compare_enabled == 1); | ||
| 701 | if (uses_depth_compare) { | ||
| 702 | glSamplerParameteri(s, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); | ||
| 703 | } else { | ||
| 704 | glSamplerParameteri(s, GL_TEXTURE_COMPARE_MODE, GL_NONE); | ||
| 705 | } | ||
| 706 | } | ||
| 707 | |||
| 708 | if (depth_compare_func != config.depth_compare_func) { | ||
| 709 | depth_compare_func = config.depth_compare_func; | ||
| 710 | glSamplerParameteri(s, GL_TEXTURE_COMPARE_FUNC, | ||
| 711 | MaxwellToGL::DepthCompareFunc(depth_compare_func)); | ||
| 712 | } | ||
| 713 | |||
| 696 | if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || | 714 | if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || |
| 697 | wrap_p == Tegra::Texture::WrapMode::Border) { | 715 | wrap_p == Tegra::Texture::WrapMode::Border) { |
| 698 | const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, | 716 | const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index bf954bb5d..dc31a2dbc 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -96,6 +96,8 @@ private: | |||
| 96 | Tegra::Texture::WrapMode wrap_u; | 96 | Tegra::Texture::WrapMode wrap_u; |
| 97 | Tegra::Texture::WrapMode wrap_v; | 97 | Tegra::Texture::WrapMode wrap_v; |
| 98 | Tegra::Texture::WrapMode wrap_p; | 98 | Tegra::Texture::WrapMode wrap_p; |
| 99 | bool uses_depth_compare; | ||
| 100 | Tegra::Texture::DepthCompareFunc depth_compare_func; | ||
| 99 | GLvec4 border_color; | 101 | GLvec4 border_color; |
| 100 | }; | 102 | }; |
| 101 | 103 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 579a78702..7e57de78a 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -508,7 +508,7 @@ public: | |||
| 508 | /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if | 508 | /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if |
| 509 | /// necessary. | 509 | /// necessary. |
| 510 | std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, | 510 | std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, |
| 511 | bool is_array) { | 511 | bool is_array, bool is_shadow) { |
| 512 | const std::size_t offset = static_cast<std::size_t>(sampler.index.Value()); | 512 | const std::size_t offset = static_cast<std::size_t>(sampler.index.Value()); |
| 513 | 513 | ||
| 514 | // If this sampler has already been used, return the existing mapping. | 514 | // If this sampler has already been used, return the existing mapping. |
| @@ -517,13 +517,14 @@ public: | |||
| 517 | [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); | 517 | [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); |
| 518 | 518 | ||
| 519 | if (itr != used_samplers.end()) { | 519 | if (itr != used_samplers.end()) { |
| 520 | ASSERT(itr->GetType() == type && itr->IsArray() == is_array); | 520 | ASSERT(itr->GetType() == type && itr->IsArray() == is_array && |
| 521 | itr->IsShadow() == is_shadow); | ||
| 521 | return itr->GetName(); | 522 | return itr->GetName(); |
| 522 | } | 523 | } |
| 523 | 524 | ||
| 524 | // Otherwise create a new mapping for this sampler | 525 | // Otherwise create a new mapping for this sampler |
| 525 | const std::size_t next_index = used_samplers.size(); | 526 | const std::size_t next_index = used_samplers.size(); |
| 526 | const SamplerEntry entry{stage, offset, next_index, type, is_array}; | 527 | const SamplerEntry entry{stage, offset, next_index, type, is_array, is_shadow}; |
| 527 | used_samplers.emplace_back(entry); | 528 | used_samplers.emplace_back(entry); |
| 528 | return entry.GetName(); | 529 | return entry.GetName(); |
| 529 | } | 530 | } |
| @@ -747,8 +748,9 @@ private: | |||
| 747 | } | 748 | } |
| 748 | 749 | ||
| 749 | /// Generates code representing a texture sampler. | 750 | /// Generates code representing a texture sampler. |
| 750 | std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) { | 751 | std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array, |
| 751 | return regs.AccessSampler(sampler, type, is_array); | 752 | bool is_shadow) { |
| 753 | return regs.AccessSampler(sampler, type, is_array, is_shadow); | ||
| 752 | } | 754 | } |
| 753 | 755 | ||
| 754 | /** | 756 | /** |
| @@ -1002,6 +1004,24 @@ private: | |||
| 1002 | shader.AddLine('}'); | 1004 | shader.AddLine('}'); |
| 1003 | } | 1005 | } |
| 1004 | 1006 | ||
| 1007 | static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { | ||
| 1008 | switch (texture_type) { | ||
| 1009 | case Tegra::Shader::TextureType::Texture1D: { | ||
| 1010 | return 1; | ||
| 1011 | } | ||
| 1012 | case Tegra::Shader::TextureType::Texture2D: { | ||
| 1013 | return 2; | ||
| 1014 | } | ||
| 1015 | case Tegra::Shader::TextureType::TextureCube: { | ||
| 1016 | return 3; | ||
| 1017 | } | ||
| 1018 | default: | ||
| 1019 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", static_cast<u32>(texture_type)); | ||
| 1020 | UNREACHABLE(); | ||
| 1021 | return 0; | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1005 | /* | 1025 | /* |
| 1006 | * Emits code to push the input target address to the SSY address stack, incrementing the stack | 1026 | * Emits code to push the input target address to the SSY address stack, incrementing the stack |
| 1007 | * top. | 1027 | * top. |
| @@ -1896,24 +1916,35 @@ private: | |||
| 1896 | "NODEP is not implemented"); | 1916 | "NODEP is not implemented"); |
| 1897 | ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | 1917 | ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), |
| 1898 | "AOFFI is not implemented"); | 1918 | "AOFFI is not implemented"); |
| 1899 | ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 1900 | "DC is not implemented"); | ||
| 1901 | 1919 | ||
| 1902 | switch (texture_type) { | 1920 | const bool depth_compare = |
| 1903 | case Tegra::Shader::TextureType::Texture1D: { | 1921 | instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| 1922 | u32 num_coordinates = TextureCoordinates(texture_type); | ||
| 1923 | if (depth_compare) | ||
| 1924 | num_coordinates += 1; | ||
| 1925 | |||
| 1926 | switch (num_coordinates) { | ||
| 1927 | case 1: { | ||
| 1904 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 1928 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 1905 | coord = "float coords = " + x + ';'; | 1929 | coord = "float coords = " + x + ';'; |
| 1906 | break; | 1930 | break; |
| 1907 | } | 1931 | } |
| 1908 | case Tegra::Shader::TextureType::Texture2D: { | 1932 | case 2: { |
| 1909 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 1933 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 1910 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 1934 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 1911 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 1935 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; |
| 1912 | break; | 1936 | break; |
| 1913 | } | 1937 | } |
| 1938 | case 3: { | ||
| 1939 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 1940 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 1941 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1942 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 1943 | break; | ||
| 1944 | } | ||
| 1914 | default: | 1945 | default: |
| 1915 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | 1946 | LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}", |
| 1916 | static_cast<u32>(texture_type)); | 1947 | static_cast<u32>(num_coordinates)); |
| 1917 | UNREACHABLE(); | 1948 | UNREACHABLE(); |
| 1918 | 1949 | ||
| 1919 | // Fallback to interpreting as a 2D texture for now | 1950 | // Fallback to interpreting as a 2D texture for now |
| @@ -1924,9 +1955,10 @@ private: | |||
| 1924 | } | 1955 | } |
| 1925 | // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias | 1956 | // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias |
| 1926 | // or lod. | 1957 | // or lod. |
| 1927 | const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20); | 1958 | std::string op_c; |
| 1928 | 1959 | ||
| 1929 | const std::string sampler = GetSampler(instr.sampler, texture_type, false); | 1960 | const std::string sampler = |
| 1961 | GetSampler(instr.sampler, texture_type, false, depth_compare); | ||
| 1930 | // Add an extra scope and declare the texture coords inside to prevent | 1962 | // Add an extra scope and declare the texture coords inside to prevent |
| 1931 | // overwriting them in case they are used as outputs of the texs instruction. | 1963 | // overwriting them in case they are used as outputs of the texs instruction. |
| 1932 | 1964 | ||
| @@ -1935,7 +1967,7 @@ private: | |||
| 1935 | shader.AddLine(coord); | 1967 | shader.AddLine(coord); |
| 1936 | std::string texture; | 1968 | std::string texture; |
| 1937 | 1969 | ||
| 1938 | switch (instr.tex.process_mode) { | 1970 | switch (instr.tex.GetTextureProcessMode()) { |
| 1939 | case Tegra::Shader::TextureProcessMode::None: { | 1971 | case Tegra::Shader::TextureProcessMode::None: { |
| 1940 | texture = "texture(" + sampler + ", coords)"; | 1972 | texture = "texture(" + sampler + ", coords)"; |
| 1941 | break; | 1973 | break; |
| @@ -1946,12 +1978,22 @@ private: | |||
| 1946 | } | 1978 | } |
| 1947 | case Tegra::Shader::TextureProcessMode::LB: | 1979 | case Tegra::Shader::TextureProcessMode::LB: |
| 1948 | case Tegra::Shader::TextureProcessMode::LBA: { | 1980 | case Tegra::Shader::TextureProcessMode::LBA: { |
| 1981 | if (num_coordinates <= 2) { | ||
| 1982 | op_c = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1983 | } else { | ||
| 1984 | op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | ||
| 1985 | } | ||
| 1949 | // TODO: Figure if A suffix changes the equation at all. | 1986 | // TODO: Figure if A suffix changes the equation at all. |
| 1950 | texture = "texture(" + sampler + ", coords, " + op_c + ')'; | 1987 | texture = "texture(" + sampler + ", coords, " + op_c + ')'; |
| 1951 | break; | 1988 | break; |
| 1952 | } | 1989 | } |
| 1953 | case Tegra::Shader::TextureProcessMode::LL: | 1990 | case Tegra::Shader::TextureProcessMode::LL: |
| 1954 | case Tegra::Shader::TextureProcessMode::LLA: { | 1991 | case Tegra::Shader::TextureProcessMode::LLA: { |
| 1992 | if (num_coordinates <= 2) { | ||
| 1993 | op_c = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 1994 | } else { | ||
| 1995 | op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | ||
| 1996 | } | ||
| 1955 | // TODO: Figure if A suffix changes the equation at all. | 1997 | // TODO: Figure if A suffix changes the equation at all. |
| 1956 | texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; | 1998 | texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; |
| 1957 | break; | 1999 | break; |
| @@ -1959,18 +2001,22 @@ private: | |||
| 1959 | default: { | 2001 | default: { |
| 1960 | texture = "texture(" + sampler + ", coords)"; | 2002 | texture = "texture(" + sampler + ", coords)"; |
| 1961 | LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", | 2003 | LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", |
| 1962 | static_cast<u32>(instr.tex.process_mode.Value())); | 2004 | static_cast<u32>(instr.tex.GetTextureProcessMode())); |
| 1963 | UNREACHABLE(); | 2005 | UNREACHABLE(); |
| 1964 | } | 2006 | } |
| 1965 | } | 2007 | } |
| 1966 | std::size_t dest_elem{}; | 2008 | if (!depth_compare) { |
| 1967 | for (std::size_t elem = 0; elem < 4; ++elem) { | 2009 | std::size_t dest_elem{}; |
| 1968 | if (!instr.tex.IsComponentEnabled(elem)) { | 2010 | for (std::size_t elem = 0; elem < 4; ++elem) { |
| 1969 | // Skip disabled components | 2011 | if (!instr.tex.IsComponentEnabled(elem)) { |
| 1970 | continue; | 2012 | // Skip disabled components |
| 2013 | continue; | ||
| 2014 | } | ||
| 2015 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); | ||
| 2016 | ++dest_elem; | ||
| 1971 | } | 2017 | } |
| 1972 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); | 2018 | } else { |
| 1973 | ++dest_elem; | 2019 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); |
| 1974 | } | 2020 | } |
| 1975 | --shader.scope; | 2021 | --shader.scope; |
| 1976 | shader.AddLine("}"); | 2022 | shader.AddLine("}"); |
| @@ -1983,11 +2029,15 @@ private: | |||
| 1983 | 2029 | ||
| 1984 | ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 2030 | ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| 1985 | "NODEP is not implemented"); | 2031 | "NODEP is not implemented"); |
| 1986 | ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 1987 | "DC is not implemented"); | ||
| 1988 | 2032 | ||
| 1989 | switch (texture_type) { | 2033 | const bool depth_compare = |
| 1990 | case Tegra::Shader::TextureType::Texture2D: { | 2034 | instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| 2035 | u32 num_coordinates = TextureCoordinates(texture_type); | ||
| 2036 | if (depth_compare) | ||
| 2037 | num_coordinates += 1; | ||
| 2038 | |||
| 2039 | switch (num_coordinates) { | ||
| 2040 | case 2: { | ||
| 1991 | if (is_array) { | 2041 | if (is_array) { |
| 1992 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2042 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); |
| 1993 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2043 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| @@ -2000,17 +2050,25 @@ private: | |||
| 2000 | } | 2050 | } |
| 2001 | break; | 2051 | break; |
| 2002 | } | 2052 | } |
| 2003 | case Tegra::Shader::TextureType::TextureCube: { | 2053 | case 3: { |
| 2004 | ASSERT_MSG(!is_array, "Unimplemented"); | 2054 | if (is_array) { |
| 2005 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2055 | UNIMPLEMENTED_MSG("3-coordinate arrays not fully implemented"); |
| 2006 | std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2056 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2007 | std::string z = regs.GetRegisterAsFloat(instr.gpr20); | 2057 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); |
| 2008 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | 2058 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; |
| 2059 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 2060 | is_array = false; | ||
| 2061 | } else { | ||
| 2062 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2063 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2064 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2065 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 2066 | } | ||
| 2009 | break; | 2067 | break; |
| 2010 | } | 2068 | } |
| 2011 | default: | 2069 | default: |
| 2012 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | 2070 | LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}", |
| 2013 | static_cast<u32>(texture_type)); | 2071 | static_cast<u32>(num_coordinates)); |
| 2014 | UNREACHABLE(); | 2072 | UNREACHABLE(); |
| 2015 | 2073 | ||
| 2016 | // Fallback to interpreting as a 2D texture for now | 2074 | // Fallback to interpreting as a 2D texture for now |
| @@ -2020,9 +2078,35 @@ private: | |||
| 2020 | texture_type = Tegra::Shader::TextureType::Texture2D; | 2078 | texture_type = Tegra::Shader::TextureType::Texture2D; |
| 2021 | is_array = false; | 2079 | is_array = false; |
| 2022 | } | 2080 | } |
| 2023 | const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); | 2081 | const std::string sampler = |
| 2024 | const std::string texture = "texture(" + sampler + ", coords)"; | 2082 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); |
| 2025 | WriteTexsInstruction(instr, coord, texture); | 2083 | std::string texture; |
| 2084 | switch (instr.texs.GetTextureProcessMode()) { | ||
| 2085 | case Tegra::Shader::TextureProcessMode::None: { | ||
| 2086 | texture = "texture(" + sampler + ", coords)"; | ||
| 2087 | break; | ||
| 2088 | } | ||
| 2089 | case Tegra::Shader::TextureProcessMode::LZ: { | ||
| 2090 | texture = "textureLod(" + sampler + ", coords, 0.0)"; | ||
| 2091 | break; | ||
| 2092 | } | ||
| 2093 | case Tegra::Shader::TextureProcessMode::LL: { | ||
| 2094 | const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | ||
| 2095 | texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; | ||
| 2096 | break; | ||
| 2097 | } | ||
| 2098 | default: { | ||
| 2099 | texture = "texture(" + sampler + ", coords)"; | ||
| 2100 | LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", | ||
| 2101 | static_cast<u32>(instr.texs.GetTextureProcessMode())); | ||
| 2102 | UNREACHABLE(); | ||
| 2103 | } | ||
| 2104 | } | ||
| 2105 | if (!depth_compare) { | ||
| 2106 | WriteTexsInstruction(instr, coord, texture); | ||
| 2107 | } else { | ||
| 2108 | WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); | ||
| 2109 | } | ||
| 2026 | break; | 2110 | break; |
| 2027 | } | 2111 | } |
| 2028 | case OpCode::Id::TLDS: { | 2112 | case OpCode::Id::TLDS: { |
| @@ -2062,9 +2146,26 @@ private: | |||
| 2062 | static_cast<u32>(texture_type)); | 2146 | static_cast<u32>(texture_type)); |
| 2063 | UNREACHABLE(); | 2147 | UNREACHABLE(); |
| 2064 | } | 2148 | } |
| 2065 | 2149 | const std::string sampler = | |
| 2066 | const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); | 2150 | GetSampler(instr.sampler, texture_type, is_array, false); |
| 2067 | const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; | 2151 | std::string texture = "texelFetch(" + sampler + ", coords, 0)"; |
| 2152 | const std::string op_c = regs.GetRegisterAsInteger(instr.gpr20.Value() + 1); | ||
| 2153 | switch (instr.tlds.GetTextureProcessMode()) { | ||
| 2154 | case Tegra::Shader::TextureProcessMode::LZ: { | ||
| 2155 | texture = "texelFetch(" + sampler + ", coords, 0)"; | ||
| 2156 | break; | ||
| 2157 | } | ||
| 2158 | case Tegra::Shader::TextureProcessMode::LL: { | ||
| 2159 | texture = "texelFetch(" + sampler + ", coords, " + op_c + ')'; | ||
| 2160 | break; | ||
| 2161 | } | ||
| 2162 | default: { | ||
| 2163 | texture = "texelFetch(" + sampler + ", coords, 0)"; | ||
| 2164 | LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", | ||
| 2165 | static_cast<u32>(instr.tlds.GetTextureProcessMode())); | ||
| 2166 | UNREACHABLE(); | ||
| 2167 | } | ||
| 2168 | } | ||
| 2068 | WriteTexsInstruction(instr, coord, texture); | 2169 | WriteTexsInstruction(instr, coord, texture); |
| 2069 | break; | 2170 | break; |
| 2070 | } | 2171 | } |
| @@ -2077,28 +2178,43 @@ private: | |||
| 2077 | "NODEP is not implemented"); | 2178 | "NODEP is not implemented"); |
| 2078 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | 2179 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), |
| 2079 | "AOFFI is not implemented"); | 2180 | "AOFFI is not implemented"); |
| 2080 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 2081 | "DC is not implemented"); | ||
| 2082 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), | 2181 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), |
| 2083 | "NDV is not implemented"); | 2182 | "NDV is not implemented"); |
| 2084 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP), | 2183 | ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP), |
| 2085 | "PTP is not implemented"); | 2184 | "PTP is not implemented"); |
| 2086 | 2185 | const bool depth_compare = | |
| 2087 | switch (instr.tld4.texture_type) { | 2186 | instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| 2088 | case Tegra::Shader::TextureType::Texture2D: { | 2187 | auto texture_type = instr.tld4.texture_type.Value(); |
| 2188 | u32 num_coordinates = TextureCoordinates(texture_type); | ||
| 2189 | if (depth_compare) | ||
| 2190 | num_coordinates += 1; | ||
| 2191 | |||
| 2192 | switch (num_coordinates) { | ||
| 2193 | case 2: { | ||
| 2089 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2194 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2090 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2195 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2091 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2196 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; |
| 2092 | break; | 2197 | break; |
| 2093 | } | 2198 | } |
| 2199 | case 3: { | ||
| 2200 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2201 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2202 | const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); | ||
| 2203 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 2204 | break; | ||
| 2205 | } | ||
| 2094 | default: | 2206 | default: |
| 2095 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | 2207 | LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}", |
| 2096 | static_cast<u32>(instr.tld4.texture_type.Value())); | 2208 | static_cast<u32>(num_coordinates)); |
| 2097 | UNREACHABLE(); | 2209 | UNREACHABLE(); |
| 2210 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2211 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2212 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 2213 | texture_type = Tegra::Shader::TextureType::Texture2D; | ||
| 2098 | } | 2214 | } |
| 2099 | 2215 | ||
| 2100 | const std::string sampler = | 2216 | const std::string sampler = |
| 2101 | GetSampler(instr.sampler, instr.tld4.texture_type, false); | 2217 | GetSampler(instr.sampler, texture_type, false, depth_compare); |
| 2102 | // Add an extra scope and declare the texture coords inside to prevent | 2218 | // Add an extra scope and declare the texture coords inside to prevent |
| 2103 | // overwriting them in case they are used as outputs of the texs instruction. | 2219 | // overwriting them in case they are used as outputs of the texs instruction. |
| 2104 | shader.AddLine("{"); | 2220 | shader.AddLine("{"); |
| @@ -2106,15 +2222,18 @@ private: | |||
| 2106 | shader.AddLine(coord); | 2222 | shader.AddLine(coord); |
| 2107 | const std::string texture = "textureGather(" + sampler + ", coords, " + | 2223 | const std::string texture = "textureGather(" + sampler + ", coords, " + |
| 2108 | std::to_string(instr.tld4.component) + ')'; | 2224 | std::to_string(instr.tld4.component) + ')'; |
| 2109 | 2225 | if (!depth_compare) { | |
| 2110 | std::size_t dest_elem{}; | 2226 | std::size_t dest_elem{}; |
| 2111 | for (std::size_t elem = 0; elem < 4; ++elem) { | 2227 | for (std::size_t elem = 0; elem < 4; ++elem) { |
| 2112 | if (!instr.tex.IsComponentEnabled(elem)) { | 2228 | if (!instr.tex.IsComponentEnabled(elem)) { |
| 2113 | // Skip disabled components | 2229 | // Skip disabled components |
| 2114 | continue; | 2230 | continue; |
| 2231 | } | ||
| 2232 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); | ||
| 2233 | ++dest_elem; | ||
| 2115 | } | 2234 | } |
| 2116 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); | 2235 | } else { |
| 2117 | ++dest_elem; | 2236 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); |
| 2118 | } | 2237 | } |
| 2119 | --shader.scope; | 2238 | --shader.scope; |
| 2120 | shader.AddLine("}"); | 2239 | shader.AddLine("}"); |
| @@ -2125,18 +2244,30 @@ private: | |||
| 2125 | "NODEP is not implemented"); | 2244 | "NODEP is not implemented"); |
| 2126 | ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | 2245 | ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), |
| 2127 | "AOFFI is not implemented"); | 2246 | "AOFFI is not implemented"); |
| 2128 | ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), | ||
| 2129 | "DC is not implemented"); | ||
| 2130 | 2247 | ||
| 2248 | const bool depth_compare = | ||
| 2249 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | ||
| 2131 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 2250 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 2132 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); | 2251 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); |
| 2133 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 2252 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| 2134 | const std::string sampler = | 2253 | const std::string sampler = GetSampler( |
| 2135 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); | 2254 | instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); |
| 2136 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 2255 | std::string coord; |
| 2256 | if (!depth_compare) { | ||
| 2257 | coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | ||
| 2258 | } else { | ||
| 2259 | // Note: TLD4S coordinate encoding works just like TEXS's | ||
| 2260 | const std::string op_c = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2261 | coord = "vec3 coords = vec3(" + op_a + ", " + op_c + ", " + op_b + ");"; | ||
| 2262 | } | ||
| 2137 | const std::string texture = "textureGather(" + sampler + ", coords, " + | 2263 | const std::string texture = "textureGather(" + sampler + ", coords, " + |
| 2138 | std::to_string(instr.tld4s.component) + ')'; | 2264 | std::to_string(instr.tld4s.component) + ')'; |
| 2139 | WriteTexsInstruction(instr, coord, texture); | 2265 | |
| 2266 | if (!depth_compare) { | ||
| 2267 | WriteTexsInstruction(instr, coord, texture); | ||
| 2268 | } else { | ||
| 2269 | WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); | ||
| 2270 | } | ||
| 2140 | break; | 2271 | break; |
| 2141 | } | 2272 | } |
| 2142 | case OpCode::Id::TXQ: { | 2273 | case OpCode::Id::TXQ: { |
| @@ -2147,7 +2278,7 @@ private: | |||
| 2147 | // Sadly, not all texture instructions specify the type of texture their sampler | 2278 | // Sadly, not all texture instructions specify the type of texture their sampler |
| 2148 | // uses. This must be fixed at a later instance. | 2279 | // uses. This must be fixed at a later instance. |
| 2149 | const std::string sampler = | 2280 | const std::string sampler = |
| 2150 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); | 2281 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); |
| 2151 | switch (instr.txq.query_type) { | 2282 | switch (instr.txq.query_type) { |
| 2152 | case Tegra::Shader::TextureQueryType::Dimension: { | 2283 | case Tegra::Shader::TextureQueryType::Dimension: { |
| 2153 | const std::string texture = "textureQueryLevels(" + sampler + ')'; | 2284 | const std::string texture = "textureQueryLevels(" + sampler + ')'; |
| @@ -2172,7 +2303,8 @@ private: | |||
| 2172 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2303 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2173 | const bool is_array = instr.tmml.array != 0; | 2304 | const bool is_array = instr.tmml.array != 0; |
| 2174 | auto texture_type = instr.tmml.texture_type.Value(); | 2305 | auto texture_type = instr.tmml.texture_type.Value(); |
| 2175 | const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); | 2306 | const std::string sampler = |
| 2307 | GetSampler(instr.sampler, texture_type, is_array, false); | ||
| 2176 | 2308 | ||
| 2177 | // TODO: add coordinates for different samplers once other texture types are | 2309 | // TODO: add coordinates for different samplers once other texture types are |
| 2178 | // implemented. | 2310 | // implemented. |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index d53b93ad5..e56f39e78 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -75,8 +75,9 @@ class SamplerEntry { | |||
| 75 | 75 | ||
| 76 | public: | 76 | public: |
| 77 | SamplerEntry(Maxwell::ShaderStage stage, std::size_t offset, std::size_t index, | 77 | SamplerEntry(Maxwell::ShaderStage stage, std::size_t offset, std::size_t index, |
| 78 | Tegra::Shader::TextureType type, bool is_array) | 78 | Tegra::Shader::TextureType type, bool is_array, bool is_shadow) |
| 79 | : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {} | 79 | : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array), |
| 80 | is_shadow(is_shadow) {} | ||
| 80 | 81 | ||
| 81 | std::size_t GetOffset() const { | 82 | std::size_t GetOffset() const { |
| 82 | return offset; | 83 | return offset; |
| @@ -117,6 +118,8 @@ public: | |||
| 117 | } | 118 | } |
| 118 | if (is_array) | 119 | if (is_array) |
| 119 | glsl_type += "Array"; | 120 | glsl_type += "Array"; |
| 121 | if (is_shadow) | ||
| 122 | glsl_type += "Shadow"; | ||
| 120 | return glsl_type; | 123 | return glsl_type; |
| 121 | } | 124 | } |
| 122 | 125 | ||
| @@ -128,6 +131,10 @@ public: | |||
| 128 | return is_array; | 131 | return is_array; |
| 129 | } | 132 | } |
| 130 | 133 | ||
| 134 | bool IsShadow() const { | ||
| 135 | return is_shadow; | ||
| 136 | } | ||
| 137 | |||
| 131 | u32 GetHash() const { | 138 | u32 GetHash() const { |
| 132 | return (static_cast<u32>(stage) << 16) | static_cast<u32>(sampler_index); | 139 | return (static_cast<u32>(stage) << 16) | static_cast<u32>(sampler_index); |
| 133 | } | 140 | } |
| @@ -147,7 +154,8 @@ private: | |||
| 147 | Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. | 154 | Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. |
| 148 | std::size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. | 155 | std::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) | 156 | 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. | 157 | bool is_array; ///< Whether the texture is being sampled as an array texture or not. |
| 158 | bool is_shadow; ///< Whether the texture is being sampled as a depth texture or not. | ||
| 151 | }; | 159 | }; |
| 152 | 160 | ||
| 153 | struct ShaderEntries { | 161 | struct ShaderEntries { |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 67273e164..3c3bcaae4 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -159,6 +159,31 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | |||
| 159 | return {}; | 159 | return {}; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { | ||
| 163 | switch (func) { | ||
| 164 | case Tegra::Texture::DepthCompareFunc::Never: | ||
| 165 | return GL_NEVER; | ||
| 166 | case Tegra::Texture::DepthCompareFunc::Less: | ||
| 167 | return GL_LESS; | ||
| 168 | case Tegra::Texture::DepthCompareFunc::LessEqual: | ||
| 169 | return GL_LEQUAL; | ||
| 170 | case Tegra::Texture::DepthCompareFunc::Equal: | ||
| 171 | return GL_EQUAL; | ||
| 172 | case Tegra::Texture::DepthCompareFunc::NotEqual: | ||
| 173 | return GL_NOTEQUAL; | ||
| 174 | case Tegra::Texture::DepthCompareFunc::Greater: | ||
| 175 | return GL_GREATER; | ||
| 176 | case Tegra::Texture::DepthCompareFunc::GreaterEqual: | ||
| 177 | return GL_GEQUAL; | ||
| 178 | case Tegra::Texture::DepthCompareFunc::Always: | ||
| 179 | return GL_ALWAYS; | ||
| 180 | } | ||
| 181 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture depth compare function ={}", | ||
| 182 | static_cast<u32>(func)); | ||
| 183 | UNREACHABLE(); | ||
| 184 | return {}; | ||
| 185 | } | ||
| 186 | |||
| 162 | inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { | 187 | inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { |
| 163 | switch (equation) { | 188 | switch (equation) { |
| 164 | case Maxwell::Blend::Equation::Add: | 189 | case Maxwell::Blend::Equation::Add: |
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 14aea4838..8f31d825a 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -227,6 +227,17 @@ enum class WrapMode : u32 { | |||
| 227 | MirrorOnceClampOGL = 7, | 227 | MirrorOnceClampOGL = 7, |
| 228 | }; | 228 | }; |
| 229 | 229 | ||
| 230 | enum class DepthCompareFunc : u32 { | ||
| 231 | Never = 0, | ||
| 232 | Less = 1, | ||
| 233 | Equal = 2, | ||
| 234 | LessEqual = 3, | ||
| 235 | Greater = 4, | ||
| 236 | NotEqual = 5, | ||
| 237 | GreaterEqual = 6, | ||
| 238 | Always = 7, | ||
| 239 | }; | ||
| 240 | |||
| 230 | enum class TextureFilter : u32 { | 241 | enum class TextureFilter : u32 { |
| 231 | Nearest = 1, | 242 | Nearest = 1, |
| 232 | Linear = 2, | 243 | Linear = 2, |
| @@ -244,7 +255,7 @@ struct TSCEntry { | |||
| 244 | BitField<3, 3, WrapMode> wrap_v; | 255 | BitField<3, 3, WrapMode> wrap_v; |
| 245 | BitField<6, 3, WrapMode> wrap_p; | 256 | BitField<6, 3, WrapMode> wrap_p; |
| 246 | BitField<9, 1, u32> depth_compare_enabled; | 257 | BitField<9, 1, u32> depth_compare_enabled; |
| 247 | BitField<10, 3, u32> depth_compare_func; | 258 | BitField<10, 3, DepthCompareFunc> depth_compare_func; |
| 248 | }; | 259 | }; |
| 249 | union { | 260 | union { |
| 250 | BitField<0, 2, TextureFilter> mag_filter; | 261 | BitField<0, 2, TextureFilter> mag_filter; |