summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-11-06 04:32:43 -0300
committerGravatar ReinUsesLisp2019-11-22 21:28:47 -0300
commit32c1bc6a67820f9df21c8f64f4df078b015aa7da (patch)
tree141df885726a01fbd7d999d6ee314b4d11c8ce56 /src
parentMerge pull request #3142 from ReinUsesLisp/depbar-log (diff)
downloadyuzu-32c1bc6a67820f9df21c8f64f4df078b015aa7da.tar.gz
yuzu-32c1bc6a67820f9df21c8f64f4df078b015aa7da.tar.xz
yuzu-32c1bc6a67820f9df21c8f64f4df078b015aa7da.zip
shader/texture: Deduce texture buffers from locker
Instead of specializing shaders to separate texture buffers from 1D textures, use the locker to deduce them while they are being decoded.
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);