summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp45
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h15
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp39
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp33
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h8
-rw-r--r--src/video_core/shader/decode/texture.cpp102
-rw-r--r--src/video_core/shader/node.h14
-rw-r--r--src/video_core/shader/shader_ir.h13
9 files changed, 107 insertions, 174 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 05f8e511b..b76de71ec 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -271,9 +271,9 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
271 const auto stage = static_cast<Maxwell::ShaderStage>(index == 0 ? 0 : index - 1); 271 const auto stage = static_cast<Maxwell::ShaderStage>(index == 0 ? 0 : index - 1);
272 SetupDrawConstBuffers(stage, shader); 272 SetupDrawConstBuffers(stage, shader);
273 SetupDrawGlobalMemory(stage, shader); 273 SetupDrawGlobalMemory(stage, shader);
274 const auto texture_buffer_usage{SetupDrawTextures(stage, shader, base_bindings)}; 274 SetupDrawTextures(stage, shader, base_bindings);
275 275
276 const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage}; 276 const ProgramVariant variant{base_bindings, primitive_mode};
277 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant); 277 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
278 278
279 switch (program) { 279 switch (program) {
@@ -303,7 +303,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
303 // When VertexA is enabled, we have dual vertex shaders 303 // When VertexA is enabled, we have dual vertex shaders
304 if (program == Maxwell::ShaderProgram::VertexA) { 304 if (program == Maxwell::ShaderProgram::VertexA) {
305 // VertexB was combined with VertexA, so we skip the VertexB iteration 305 // VertexB was combined with VertexA, so we skip the VertexB iteration
306 index++; 306 ++index;
307 } 307 }
308 308
309 base_bindings = next_bindings; 309 base_bindings = next_bindings;
@@ -732,11 +732,10 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
732 } 732 }
733 733
734 auto kernel = shader_cache.GetComputeKernel(code_addr); 734 auto kernel = shader_cache.GetComputeKernel(code_addr);
735 ProgramVariant variant; 735 SetupComputeTextures(kernel);
736 variant.texture_buffer_usage = SetupComputeTextures(kernel);
737 SetupComputeImages(kernel); 736 SetupComputeImages(kernel);
738 737
739 const auto [program, next_bindings] = kernel->GetProgramHandle(variant); 738 const auto [program, next_bindings] = kernel->GetProgramHandle({});
740 state.draw.shader_program = program; 739 state.draw.shader_program = program;
741 state.draw.program_pipeline = 0; 740 state.draw.program_pipeline = 0;
742 741
@@ -918,9 +917,8 @@ void RasterizerOpenGL::SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entr
918 bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size)); 917 bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size));
919} 918}
920 919
921TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage, 920void RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage, const Shader& shader,
922 const Shader& shader, 921 BaseBindings base_bindings) {
923 BaseBindings base_bindings) {
924 MICROPROFILE_SCOPE(OpenGL_Texture); 922 MICROPROFILE_SCOPE(OpenGL_Texture);
925 const auto& gpu = system.GPU(); 923 const auto& gpu = system.GPU();
926 const auto& maxwell3d = gpu.Maxwell3D(); 924 const auto& maxwell3d = gpu.Maxwell3D();
@@ -929,8 +927,6 @@ TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stag
929 ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.textures), 927 ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.textures),
930 "Exceeded the number of active textures."); 928 "Exceeded the number of active textures.");
931 929
932 TextureBufferUsage texture_buffer_usage{0};
933
934 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 930 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
935 const auto& entry = entries[bindpoint]; 931 const auto& entry = entries[bindpoint];
936 const auto texture = [&] { 932 const auto texture = [&] {
@@ -943,15 +939,11 @@ TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stag
943 return maxwell3d.GetTextureInfo(tex_handle); 939 return maxwell3d.GetTextureInfo(tex_handle);
944 }(); 940 }();
945 941
946 if (SetupTexture(base_bindings.sampler + bindpoint, texture, entry)) { 942 SetupTexture(base_bindings.sampler + bindpoint, texture, entry);
947 texture_buffer_usage.set(bindpoint);
948 }
949 } 943 }
950
951 return texture_buffer_usage;
952} 944}
953 945
954TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) { 946void RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
955 MICROPROFILE_SCOPE(OpenGL_Texture); 947 MICROPROFILE_SCOPE(OpenGL_Texture);
956 const auto& compute = system.GPU().KeplerCompute(); 948 const auto& compute = system.GPU().KeplerCompute();
957 const auto& entries = kernel->GetShaderEntries().samplers; 949 const auto& entries = kernel->GetShaderEntries().samplers;
@@ -959,8 +951,6 @@ TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel)
959 ASSERT_MSG(entries.size() <= std::size(state.textures), 951 ASSERT_MSG(entries.size() <= std::size(state.textures),
960 "Exceeded the number of active textures."); 952 "Exceeded the number of active textures.");
961 953
962 TextureBufferUsage texture_buffer_usage{0};
963
964 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 954 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
965 const auto& entry = entries[bindpoint]; 955 const auto& entry = entries[bindpoint];
966 const auto texture = [&] { 956 const auto texture = [&] {
@@ -972,34 +962,29 @@ TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel)
972 return compute.GetTextureInfo(tex_handle); 962 return compute.GetTextureInfo(tex_handle);
973 }(); 963 }();
974 964
975 if (SetupTexture(bindpoint, texture, entry)) { 965 SetupTexture(bindpoint, texture, entry);
976 texture_buffer_usage.set(bindpoint);
977 }
978 } 966 }
979
980 return texture_buffer_usage;
981} 967}
982 968
983bool RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture, 969void RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
984 const GLShader::SamplerEntry& entry) { 970 const GLShader::SamplerEntry& entry) {
985 state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
986
987 const auto view = texture_cache.GetTextureSurface(texture.tic, entry); 971 const auto view = texture_cache.GetTextureSurface(texture.tic, entry);
988 if (!view) { 972 if (!view) {
989 // Can occur when texture addr is null or its memory is unmapped/invalid 973 // Can occur when texture addr is null or its memory is unmapped/invalid
974 state.samplers[binding] = 0;
990 state.textures[binding] = 0; 975 state.textures[binding] = 0;
991 return false; 976 return;
992 } 977 }
993 state.textures[binding] = view->GetTexture(); 978 state.textures[binding] = view->GetTexture();
994 979
995 if (view->GetSurfaceParams().IsBuffer()) { 980 if (view->GetSurfaceParams().IsBuffer()) {
996 return true; 981 return;
997 } 982 }
983 state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
998 984
999 // Apply swizzle to textures that are not buffers. 985 // Apply swizzle to textures that are not buffers.
1000 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, 986 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
1001 texture.tic.w_source); 987 texture.tic.w_source);
1002 return false;
1003} 988}
1004 989
1005void RasterizerOpenGL::SetupComputeImages(const Shader& shader) { 990void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index bd6fe5c3a..0e0819d59 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -107,16 +107,15 @@ private:
107 /// Syncs all the state, shaders, render targets and textures setting before a draw call. 107 /// Syncs all the state, shaders, render targets and textures setting before a draw call.
108 void DrawPrelude(); 108 void DrawPrelude();
109 109
110 /// Configures the current textures to use for the draw command. Returns shaders texture buffer 110 /// Configures the current textures to use for the draw command.
111 /// usage. 111 void SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader,
112 TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, 112 BaseBindings base_bindings);
113 const Shader& shader, BaseBindings base_bindings);
114 113
115 /// Configures the textures used in a compute shader. Returns texture buffer usage. 114 /// Configures the textures used in a compute shader.
116 TextureBufferUsage SetupComputeTextures(const Shader& kernel); 115 void SetupComputeTextures(const Shader& kernel);
117 116
118 /// Configures a texture. Returns true when the texture is a texture buffer. 117 /// Configures a texture.
119 bool SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture, 118 void SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
120 const GLShader::SamplerEntry& entry); 119 const GLShader::SamplerEntry& entry);
121 120
122 /// Configures images in a compute shader. 121 /// Configures images in a compute shader.
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 04a239a39..7ce06a978 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -270,7 +270,6 @@ CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramTy
270 270
271 auto base_bindings{variant.base_bindings}; 271 auto base_bindings{variant.base_bindings};
272 const auto primitive_mode{variant.primitive_mode}; 272 const auto primitive_mode{variant.primitive_mode};
273 const auto texture_buffer_usage{variant.texture_buffer_usage};
274 273
275 std::string source = fmt::format(R"(// {} 274 std::string source = fmt::format(R"(// {}
276#version 430 core 275#version 430 core
@@ -317,17 +316,6 @@ CachedProgram BuildShader(const Device& device, u64 unique_identifier, ProgramTy
317 fmt::format("#define IMAGE_BINDING_{} {}\n", image.GetIndex(), base_bindings.image++); 316 fmt::format("#define IMAGE_BINDING_{} {}\n", image.GetIndex(), base_bindings.image++);
318 } 317 }
319 318
320 // Transform 1D textures to texture samplers by declaring its preprocessor macros.
321 for (std::size_t i = 0; i < texture_buffer_usage.size(); ++i) {
322 if (!texture_buffer_usage.test(i)) {
323 continue;
324 }
325 source += fmt::format("#define SAMPLER_{}_IS_BUFFER\n", i);
326 }
327 if (texture_buffer_usage.any()) {
328 source += '\n';
329 }
330
331 if (program_type == ProgramType::Geometry) { 319 if (program_type == ProgramType::Geometry) {
332 const auto [glsl_topology, debug_name, max_vertices] = 320 const auto [glsl_topology, debug_name, max_vertices] =
333 GetPrimitiveDescription(primitive_mode); 321 GetPrimitiveDescription(primitive_mode);
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 4f2b49170..51c80bf32 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -658,9 +658,11 @@ private:
658 const std::string description{"layout (binding = SAMPLER_BINDING_" + 658 const std::string description{"layout (binding = SAMPLER_BINDING_" +
659 std::to_string(sampler.GetIndex()) + ") uniform"}; 659 std::to_string(sampler.GetIndex()) + ") uniform"};
660 std::string sampler_type = [&]() { 660 std::string sampler_type = [&]() {
661 if (sampler.IsBuffer()) {
662 return "samplerBuffer";
663 }
661 switch (sampler.GetType()) { 664 switch (sampler.GetType()) {
662 case Tegra::Shader::TextureType::Texture1D: 665 case Tegra::Shader::TextureType::Texture1D:
663 // Special cased, read below.
664 return "sampler1D"; 666 return "sampler1D";
665 case Tegra::Shader::TextureType::Texture2D: 667 case Tegra::Shader::TextureType::Texture2D:
666 return "sampler2D"; 668 return "sampler2D";
@@ -680,19 +682,7 @@ private:
680 sampler_type += "Shadow"; 682 sampler_type += "Shadow";
681 } 683 }
682 684
683 if (sampler.GetType() == Tegra::Shader::TextureType::Texture1D) { 685 code.AddLine("{} {} {};", description, sampler_type, name);
684 // 1D textures can be aliased to texture buffers, hide the declarations behind a
685 // preprocessor flag and use one or the other from the GPU state. This has to be
686 // done because shaders don't have enough information to determine the texture type.
687 EmitIfdefIsBuffer(sampler);
688 code.AddLine("{} samplerBuffer {};", description, name);
689 code.AddLine("#else");
690 code.AddLine("{} {} {};", description, sampler_type, name);
691 code.AddLine("#endif");
692 } else {
693 // The other texture types (2D, 3D and cubes) don't have this issue.
694 code.AddLine("{} {} {};", description, sampler_type, name);
695 }
696 } 686 }
697 if (!samplers.empty()) { 687 if (!samplers.empty()) {
698 code.AddNewLine(); 688 code.AddNewLine();
@@ -1749,27 +1739,14 @@ private:
1749 expr += ", "; 1739 expr += ", ";
1750 } 1740 }
1751 1741
1752 // Store a copy of the expression without the lod to be used with texture buffers 1742 if (meta->lod && !meta->sampler.IsBuffer()) {
1753 std::string expr_buffer = expr;
1754
1755 if (meta->lod) {
1756 expr += ", "; 1743 expr += ", ";
1757 expr += Visit(meta->lod).AsInt(); 1744 expr += Visit(meta->lod).AsInt();
1758 } 1745 }
1759 expr += ')'; 1746 expr += ')';
1760 expr += GetSwizzle(meta->element); 1747 expr += GetSwizzle(meta->element);
1761 1748
1762 expr_buffer += ')'; 1749 return {std::move(expr), Type::Float};
1763 expr_buffer += GetSwizzle(meta->element);
1764
1765 const std::string tmp{code.GenerateTemporary()};
1766 EmitIfdefIsBuffer(meta->sampler);
1767 code.AddLine("float {} = {};", tmp, expr_buffer);
1768 code.AddLine("#else");
1769 code.AddLine("float {} = {};", tmp, expr);
1770 code.AddLine("#endif");
1771
1772 return {tmp, Type::Float};
1773 } 1750 }
1774 1751
1775 Expression ImageLoad(Operation operation) { 1752 Expression ImageLoad(Operation operation) {
@@ -2214,10 +2191,6 @@ private:
2214 return GetDeclarationWithSuffix(static_cast<u32>(image.GetIndex()), "image"); 2191 return GetDeclarationWithSuffix(static_cast<u32>(image.GetIndex()), "image");
2215 } 2192 }
2216 2193
2217 void EmitIfdefIsBuffer(const Sampler& sampler) {
2218 code.AddLine("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex());
2219 }
2220
2221 std::string GetDeclarationWithSuffix(u32 index, std::string_view name) const { 2194 std::string GetDeclarationWithSuffix(u32 index, std::string_view name) const {
2222 return fmt::format("{}_{}_{}", name, index, suffix); 2195 return fmt::format("{}_{}_{}", name, index, suffix);
2223 } 2196 }
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 184a565e6..3f4daf28d 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -28,34 +28,35 @@ using VideoCommon::Shader::KeyMap;
28 28
29namespace { 29namespace {
30 30
31using ShaderCacheVersionHash = std::array<u8, 64>;
32
33enum class TransferableEntryKind : u32 {
34 Raw,
35 Usage,
36};
37
31struct ConstBufferKey { 38struct ConstBufferKey {
32 u32 cbuf; 39 u32 cbuf{};
33 u32 offset; 40 u32 offset{};
34 u32 value; 41 u32 value{};
35}; 42};
36 43
37struct BoundSamplerKey { 44struct BoundSamplerKey {
38 u32 offset; 45 u32 offset{};
39 Tegra::Engines::SamplerDescriptor sampler; 46 Tegra::Engines::SamplerDescriptor sampler{};
40}; 47};
41 48
42struct BindlessSamplerKey { 49struct BindlessSamplerKey {
43 u32 cbuf; 50 u32 cbuf{};
44 u32 offset; 51 u32 offset{};
45 Tegra::Engines::SamplerDescriptor sampler; 52 Tegra::Engines::SamplerDescriptor sampler{};
46};
47
48using ShaderCacheVersionHash = std::array<u8, 64>;
49
50enum class TransferableEntryKind : u32 {
51 Raw,
52 Usage,
53}; 53};
54 54
55constexpr u32 NativeVersion = 5; 55constexpr u32 NativeVersion = 6;
56 56
57// Making sure sizes doesn't change by accident 57// Making sure sizes doesn't change by accident
58static_assert(sizeof(BaseBindings) == 16); 58static_assert(sizeof(BaseBindings) == 16);
59static_assert(sizeof(ProgramVariant) == 20);
59 60
60ShaderCacheVersionHash GetShaderCacheVersionHash() { 61ShaderCacheVersionHash GetShaderCacheVersionHash() {
61 ShaderCacheVersionHash hash{}; 62 ShaderCacheVersionHash hash{};
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
index db23ada93..55311dc6d 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <bitset>
8#include <optional> 7#include <optional>
9#include <string> 8#include <string>
10#include <tuple> 9#include <tuple>
@@ -37,7 +36,6 @@ struct ShaderDiskCacheDump;
37 36
38using ProgramCode = std::vector<u64>; 37using ProgramCode = std::vector<u64>;
39using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>; 38using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>;
40using TextureBufferUsage = std::bitset<64>;
41 39
42/// Allocated bindings used by an OpenGL shader program 40/// Allocated bindings used by an OpenGL shader program
43struct BaseBindings { 41struct BaseBindings {
@@ -61,11 +59,10 @@ static_assert(std::is_trivially_copyable_v<BaseBindings>);
61struct ProgramVariant { 59struct ProgramVariant {
62 BaseBindings base_bindings; 60 BaseBindings base_bindings;
63 GLenum primitive_mode{}; 61 GLenum primitive_mode{};
64 TextureBufferUsage texture_buffer_usage{};
65 62
66 bool operator==(const ProgramVariant& rhs) const { 63 bool operator==(const ProgramVariant& rhs) const {
67 return std::tie(base_bindings, primitive_mode, texture_buffer_usage) == 64 return std::tie(base_bindings, primitive_mode) ==
68 std::tie(rhs.base_bindings, rhs.primitive_mode, rhs.texture_buffer_usage); 65 std::tie(rhs.base_bindings, rhs.primitive_mode);
69 } 66 }
70 67
71 bool operator!=(const ProgramVariant& rhs) const { 68 bool operator!=(const ProgramVariant& rhs) const {
@@ -112,7 +109,6 @@ template <>
112struct hash<OpenGL::ProgramVariant> { 109struct hash<OpenGL::ProgramVariant> {
113 std::size_t operator()(const OpenGL::ProgramVariant& variant) const noexcept { 110 std::size_t operator()(const OpenGL::ProgramVariant& variant) const noexcept {
114 return std::hash<OpenGL::BaseBindings>()(variant.base_bindings) ^ 111 return std::hash<OpenGL::BaseBindings>()(variant.base_bindings) ^
115 std::hash<OpenGL::TextureBufferUsage>()(variant.texture_buffer_usage) ^
116 (static_cast<std::size_t>(variant.primitive_mode) << 6); 112 (static_cast<std::size_t>(variant.primitive_mode) << 6);
117 } 113 }
118}; 114};
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index bb926a132..695fdbd24 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -128,8 +128,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
128 } 128 }
129 const Node component = Immediate(static_cast<u32>(instr.tld4s.component)); 129 const Node component = Immediate(static_cast<u32>(instr.tld4s.component));
130 130
131 const auto& sampler = 131 const SamplerInfo info{TextureType::Texture2D, false, depth_compare};
132 GetSampler(instr.sampler, {{TextureType::Texture2D, false, depth_compare}}); 132 const auto& sampler = GetSampler(instr.sampler, info);
133 133
134 Node4 values; 134 Node4 values;
135 for (u32 element = 0; element < values.size(); ++element) { 135 for (u32 element = 0; element < values.size(); ++element) {
@@ -149,7 +149,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
149 // Sadly, not all texture instructions specify the type of texture their sampler 149 // Sadly, not all texture instructions specify the type of texture their sampler
150 // uses. This must be fixed at a later instance. 150 // uses. This must be fixed at a later instance.
151 const auto& sampler = 151 const auto& sampler =
152 is_bindless ? GetBindlessSampler(instr.gpr8, {}) : GetSampler(instr.sampler, {}); 152 is_bindless ? GetBindlessSampler(instr.gpr8) : GetSampler(instr.sampler);
153 153
154 u32 indexer = 0; 154 u32 indexer = 0;
155 switch (instr.txq.query_type) { 155 switch (instr.txq.query_type) {
@@ -185,8 +185,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
185 auto texture_type = instr.tmml.texture_type.Value(); 185 auto texture_type = instr.tmml.texture_type.Value();
186 const bool is_array = instr.tmml.array != 0; 186 const bool is_array = instr.tmml.array != 0;
187 const auto& sampler = 187 const auto& sampler =
188 is_bindless ? GetBindlessSampler(instr.gpr20, {{texture_type, is_array, false}}) 188 is_bindless ? GetBindlessSampler(instr.gpr20) : GetSampler(instr.sampler);
189 : GetSampler(instr.sampler, {{texture_type, is_array, false}});
190 189
191 std::vector<Node> coords; 190 std::vector<Node> coords;
192 191
@@ -254,67 +253,50 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
254 return pc; 253 return pc;
255} 254}
256 255
257const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, 256ShaderIR::SamplerInfo ShaderIR::GetSamplerInfo(std::optional<SamplerInfo> sampler_info, u32 offset,
258 std::optional<SamplerInfo> sampler_info) { 257 std::optional<u32> buffer) {
259 const auto offset = static_cast<u32>(sampler.index.Value());
260
261 TextureType type;
262 bool is_array;
263 bool is_shadow;
264 if (sampler_info) { 258 if (sampler_info) {
265 type = sampler_info->type; 259 return *sampler_info;
266 is_array = sampler_info->is_array; 260 }
267 is_shadow = sampler_info->is_shadow; 261 const auto sampler =
268 } else if (const auto sampler = locker.ObtainBoundSampler(offset)) { 262 buffer ? locker.ObtainBindlessSampler(*buffer, offset) : locker.ObtainBoundSampler(offset);
269 type = sampler->texture_type.Value(); 263 if (!sampler) {
270 is_array = sampler->is_array.Value() != 0;
271 is_shadow = sampler->is_shadow.Value() != 0;
272 } else {
273 LOG_WARNING(HW_GPU, "Unknown sampler info"); 264 LOG_WARNING(HW_GPU, "Unknown sampler info");
274 type = TextureType::Texture2D; 265 return SamplerInfo{TextureType::Texture2D, false, false, false};
275 is_array = false;
276 is_shadow = false;
277 } 266 }
267 return SamplerInfo{sampler->texture_type, sampler->is_array != 0, sampler->is_shadow != 0,
268 sampler->is_buffer != 0};
269}
270
271const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
272 std::optional<SamplerInfo> sampler_info) {
273 const auto offset = static_cast<u32>(sampler.index.Value());
274 const auto info = GetSamplerInfo(sampler_info, offset);
278 275
279 // If this sampler has already been used, return the existing mapping. 276 // If this sampler has already been used, return the existing mapping.
280 const auto it = 277 const auto it =
281 std::find_if(used_samplers.begin(), used_samplers.end(), 278 std::find_if(used_samplers.begin(), used_samplers.end(),
282 [offset](const Sampler& entry) { return entry.GetOffset() == offset; }); 279 [offset](const Sampler& entry) { return entry.GetOffset() == offset; });
283 if (it != used_samplers.end()) { 280 if (it != used_samplers.end()) {
284 ASSERT(!it->IsBindless() && it->GetType() == type && it->IsArray() == is_array && 281 ASSERT(!it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array &&
285 it->IsShadow() == is_shadow); 282 it->IsShadow() == info.is_shadow && it->IsBuffer() == info.is_buffer);
286 return *it; 283 return *it;
287 } 284 }
288 285
289 // Otherwise create a new mapping for this sampler 286 // Otherwise create a new mapping for this sampler
290 const auto next_index = static_cast<u32>(used_samplers.size()); 287 const auto next_index = static_cast<u32>(used_samplers.size());
291 return used_samplers.emplace_back(Sampler(next_index, offset, type, is_array, is_shadow)); 288 return used_samplers.emplace_back(next_index, offset, info.type, info.is_array, info.is_shadow,
289 info.is_buffer);
292} 290}
293 291
294const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, 292const Sampler& ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg,
295 std::optional<SamplerInfo> sampler_info) { 293 std::optional<SamplerInfo> sampler_info) {
296 const Node sampler_register = GetRegister(reg); 294 const Node sampler_register = GetRegister(reg);
297 const auto [base_sampler, buffer, offset] = 295 const auto [base_sampler, buffer, offset] =
298 TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size())); 296 TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
299 ASSERT(base_sampler != nullptr); 297 ASSERT(base_sampler != nullptr);
300 298
301 TextureType type; 299 const auto info = GetSamplerInfo(sampler_info, offset, buffer);
302 bool is_array;
303 bool is_shadow;
304 if (sampler_info) {
305 type = sampler_info->type;
306 is_array = sampler_info->is_array;
307 is_shadow = sampler_info->is_shadow;
308 } else if (const auto sampler = locker.ObtainBindlessSampler(buffer, offset)) {
309 type = sampler->texture_type.Value();
310 is_array = sampler->is_array.Value() != 0;
311 is_shadow = sampler->is_shadow.Value() != 0;
312 } else {
313 LOG_WARNING(HW_GPU, "Unknown sampler info");
314 type = TextureType::Texture2D;
315 is_array = false;
316 is_shadow = false;
317 }
318 300
319 // If this sampler has already been used, return the existing mapping. 301 // If this sampler has already been used, return the existing mapping.
320 const auto it = 302 const auto it =
@@ -323,15 +305,15 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg,
323 return entry.GetBuffer() == buffer && entry.GetOffset() == offset; 305 return entry.GetBuffer() == buffer && entry.GetOffset() == offset;
324 }); 306 });
325 if (it != used_samplers.end()) { 307 if (it != used_samplers.end()) {
326 ASSERT(it->IsBindless() && it->GetType() == type && it->IsArray() == is_array && 308 ASSERT(it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array &&
327 it->IsShadow() == is_shadow); 309 it->IsShadow() == info.is_shadow);
328 return *it; 310 return *it;
329 } 311 }
330 312
331 // Otherwise create a new mapping for this sampler 313 // Otherwise create a new mapping for this sampler
332 const auto next_index = static_cast<u32>(used_samplers.size()); 314 const auto next_index = static_cast<u32>(used_samplers.size());
333 return used_samplers.emplace_back( 315 return used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array,
334 Sampler(next_index, offset, buffer, type, is_array, is_shadow)); 316 info.is_shadow, info.is_buffer);
335} 317}
336 318
337void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) { 319void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) {
@@ -416,17 +398,16 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
416 (texture_type == TextureType::TextureCube && is_array && is_shadow), 398 (texture_type == TextureType::TextureCube && is_array && is_shadow),
417 "This method is not supported."); 399 "This method is not supported.");
418 400
401 const SamplerInfo info{texture_type, is_array, is_shadow, false};
419 const auto& sampler = 402 const auto& sampler =
420 is_bindless ? GetBindlessSampler(*bindless_reg, {{texture_type, is_array, is_shadow}}) 403 is_bindless ? GetBindlessSampler(*bindless_reg, info) : GetSampler(instr.sampler, info);
421 : GetSampler(instr.sampler, {{texture_type, is_array, is_shadow}});
422 404
423 const bool lod_needed = process_mode == TextureProcessMode::LZ || 405 const bool lod_needed = process_mode == TextureProcessMode::LZ ||
424 process_mode == TextureProcessMode::LL || 406 process_mode == TextureProcessMode::LL ||
425 process_mode == TextureProcessMode::LLA; 407 process_mode == TextureProcessMode::LLA;
426 408
427 // LOD selection (either via bias or explicit textureLod) not 409 // LOD selection (either via bias or explicit textureLod) not supported in GL for
428 // supported in GL for sampler2DArrayShadow and 410 // sampler2DArrayShadow and samplerCubeArrayShadow.
429 // samplerCubeArrayShadow.
430 const bool gl_lod_supported = 411 const bool gl_lod_supported =
431 !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) || 412 !((texture_type == Tegra::Shader::TextureType::Texture2D && is_array && is_shadow) ||
432 (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow)); 413 (texture_type == Tegra::Shader::TextureType::TextureCube && is_array && is_shadow));
@@ -436,8 +417,8 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
436 417
437 UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported); 418 UNIMPLEMENTED_IF(process_mode != TextureProcessMode::None && !gl_lod_supported);
438 419
439 Node bias = {}; 420 Node bias;
440 Node lod = {}; 421 Node lod;
441 if (process_mode != TextureProcessMode::None && gl_lod_supported) { 422 if (process_mode != TextureProcessMode::None && gl_lod_supported) {
442 switch (process_mode) { 423 switch (process_mode) {
443 case TextureProcessMode::LZ: 424 case TextureProcessMode::LZ:
@@ -573,10 +554,9 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
573 554
574 u64 parameter_register = instr.gpr20.Value(); 555 u64 parameter_register = instr.gpr20.Value();
575 556
576 const auto& sampler = 557 const SamplerInfo info{texture_type, is_array, depth_compare, false};
577 is_bindless 558 const auto& sampler = is_bindless ? GetBindlessSampler(parameter_register++, info)
578 ? GetBindlessSampler(parameter_register++, {{texture_type, is_array, depth_compare}}) 559 : GetSampler(instr.sampler, info);
579 : GetSampler(instr.sampler, {{texture_type, is_array, depth_compare}});
580 560
581 std::vector<Node> aoffi; 561 std::vector<Node> aoffi;
582 if (is_aoffi) { 562 if (is_aoffi) {
@@ -623,7 +603,7 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
623 // const Node aoffi_register{is_aoffi ? GetRegister(gpr20_cursor++) : nullptr}; 603 // const Node aoffi_register{is_aoffi ? GetRegister(gpr20_cursor++) : nullptr};
624 // const Node multisample{is_multisample ? GetRegister(gpr20_cursor++) : nullptr}; 604 // const Node multisample{is_multisample ? GetRegister(gpr20_cursor++) : nullptr};
625 605
626 const auto& sampler = GetSampler(instr.sampler, {{texture_type, is_array, false}}); 606 const auto& sampler = GetSampler(instr.sampler);
627 607
628 Node4 values; 608 Node4 values;
629 for (u32 element = 0; element < values.size(); ++element) { 609 for (u32 element = 0; element < values.size(); ++element) {
@@ -659,7 +639,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
659 // When lod is used always is in gpr20 639 // When lod is used always is in gpr20
660 const Node lod = lod_enabled ? GetRegister(instr.gpr20) : Immediate(0); 640 const Node lod = lod_enabled ? GetRegister(instr.gpr20) : Immediate(0);
661 641
662 const auto& sampler = GetSampler(instr.sampler, {{texture_type, is_array, false}}); 642 const auto& sampler = GetSampler(instr.sampler);
663 643
664 Node4 values; 644 Node4 values;
665 for (u32 element = 0; element < values.size(); ++element) { 645 for (u32 element = 0; element < values.size(); ++element) {
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 54217e6a4..44d85d434 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -225,14 +225,15 @@ class Sampler {
225public: 225public:
226 /// This constructor is for bound samplers 226 /// This constructor is for bound samplers
227 constexpr explicit Sampler(u32 index, u32 offset, Tegra::Shader::TextureType type, 227 constexpr explicit Sampler(u32 index, u32 offset, Tegra::Shader::TextureType type,
228 bool is_array, bool is_shadow) 228 bool is_array, bool is_shadow, bool is_buffer)
229 : index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow} {} 229 : index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow},
230 is_buffer{is_buffer} {}
230 231
231 /// This constructor is for bindless samplers 232 /// This constructor is for bindless samplers
232 constexpr explicit Sampler(u32 index, u32 offset, u32 buffer, Tegra::Shader::TextureType type, 233 constexpr explicit Sampler(u32 index, u32 offset, u32 buffer, Tegra::Shader::TextureType type,
233 bool is_array, bool is_shadow) 234 bool is_array, bool is_shadow, bool is_buffer)
234 : index{index}, offset{offset}, buffer{buffer}, type{type}, is_array{is_array}, 235 : index{index}, offset{offset}, buffer{buffer}, type{type}, is_array{is_array},
235 is_shadow{is_shadow}, is_bindless{true} {} 236 is_shadow{is_shadow}, is_buffer{is_buffer}, is_bindless{true} {}
236 237
237 constexpr u32 GetIndex() const { 238 constexpr u32 GetIndex() const {
238 return index; 239 return index;
@@ -258,6 +259,10 @@ public:
258 return is_shadow; 259 return is_shadow;
259 } 260 }
260 261
262 constexpr bool IsBuffer() const {
263 return is_buffer;
264 }
265
261 constexpr bool IsBindless() const { 266 constexpr bool IsBindless() const {
262 return is_bindless; 267 return is_bindless;
263 } 268 }
@@ -270,6 +275,7 @@ private:
270 Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc) 275 Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc)
271 bool is_array{}; ///< Whether the texture is being sampled as an array texture or not. 276 bool is_array{}; ///< Whether the texture is being sampled as an array texture or not.
272 bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not. 277 bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not.
278 bool is_buffer{}; ///< Whether the texture is a texture buffer without sampler.
273 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. 279 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
274}; 280};
275 281
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 76a849818..2f71a50d2 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -179,6 +179,7 @@ private:
179 Tegra::Shader::TextureType type; 179 Tegra::Shader::TextureType type;
180 bool is_array; 180 bool is_array;
181 bool is_shadow; 181 bool is_shadow;
182 bool is_buffer;
182 }; 183 };
183 184
184 void Decode(); 185 void Decode();
@@ -303,13 +304,17 @@ private:
303 /// Returns a predicate combiner operation 304 /// Returns a predicate combiner operation
304 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); 305 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation);
305 306
307 /// Queries the missing sampler info from the execution context.
308 SamplerInfo GetSamplerInfo(std::optional<SamplerInfo> sampler_info, u32 offset,
309 std::optional<u32> buffer = std::nullopt);
310
306 /// Accesses a texture sampler 311 /// Accesses a texture sampler
307 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, 312 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler,
308 std::optional<SamplerInfo> sampler_info); 313 std::optional<SamplerInfo> sampler_info = std::nullopt);
309 314
310 // Accesses a texture sampler for a bindless texture. 315 /// Accesses a texture sampler for a bindless texture.
311 const Sampler& GetBindlessSampler(const Tegra::Shader::Register& reg, 316 const Sampler& GetBindlessSampler(Tegra::Shader::Register reg,
312 std::optional<SamplerInfo> sampler_info); 317 std::optional<SamplerInfo> sampler_info = std::nullopt);
313 318
314 /// Accesses an image. 319 /// Accesses an image.
315 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); 320 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);