diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 45 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 15 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 39 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | 33 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.h | 8 | ||||
| -rw-r--r-- | src/video_core/shader/decode/texture.cpp | 102 | ||||
| -rw-r--r-- | src/video_core/shader/node.h | 14 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 13 |
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 | ||
| 921 | TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage, | 920 | void 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 | ||
| 954 | TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) { | 946 | void 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 | ||
| 983 | bool RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture, | 969 | void 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 | ||
| 1005 | void RasterizerOpenGL::SetupComputeImages(const Shader& shader) { | 990 | void 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 | ||
| 29 | namespace { | 29 | namespace { |
| 30 | 30 | ||
| 31 | using ShaderCacheVersionHash = std::array<u8, 64>; | ||
| 32 | |||
| 33 | enum class TransferableEntryKind : u32 { | ||
| 34 | Raw, | ||
| 35 | Usage, | ||
| 36 | }; | ||
| 37 | |||
| 31 | struct ConstBufferKey { | 38 | struct ConstBufferKey { |
| 32 | u32 cbuf; | 39 | u32 cbuf{}; |
| 33 | u32 offset; | 40 | u32 offset{}; |
| 34 | u32 value; | 41 | u32 value{}; |
| 35 | }; | 42 | }; |
| 36 | 43 | ||
| 37 | struct BoundSamplerKey { | 44 | struct BoundSamplerKey { |
| 38 | u32 offset; | 45 | u32 offset{}; |
| 39 | Tegra::Engines::SamplerDescriptor sampler; | 46 | Tegra::Engines::SamplerDescriptor sampler{}; |
| 40 | }; | 47 | }; |
| 41 | 48 | ||
| 42 | struct BindlessSamplerKey { | 49 | struct 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 | |||
| 48 | using ShaderCacheVersionHash = std::array<u8, 64>; | ||
| 49 | |||
| 50 | enum class TransferableEntryKind : u32 { | ||
| 51 | Raw, | ||
| 52 | Usage, | ||
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | constexpr u32 NativeVersion = 5; | 55 | constexpr u32 NativeVersion = 6; |
| 56 | 56 | ||
| 57 | // Making sure sizes doesn't change by accident | 57 | // Making sure sizes doesn't change by accident |
| 58 | static_assert(sizeof(BaseBindings) == 16); | 58 | static_assert(sizeof(BaseBindings) == 16); |
| 59 | static_assert(sizeof(ProgramVariant) == 20); | ||
| 59 | 60 | ||
| 60 | ShaderCacheVersionHash GetShaderCacheVersionHash() { | 61 | ShaderCacheVersionHash 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 | ||
| 38 | using ProgramCode = std::vector<u64>; | 37 | using ProgramCode = std::vector<u64>; |
| 39 | using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>; | 38 | using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>; |
| 40 | using TextureBufferUsage = std::bitset<64>; | ||
| 41 | 39 | ||
| 42 | /// Allocated bindings used by an OpenGL shader program | 40 | /// Allocated bindings used by an OpenGL shader program |
| 43 | struct BaseBindings { | 41 | struct BaseBindings { |
| @@ -61,11 +59,10 @@ static_assert(std::is_trivially_copyable_v<BaseBindings>); | |||
| 61 | struct ProgramVariant { | 59 | struct 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 <> | |||
| 112 | struct hash<OpenGL::ProgramVariant> { | 109 | struct 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 | ||
| 257 | const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, | 256 | ShaderIR::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 | |||
| 271 | const 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 | ||
| 294 | const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, | 292 | const 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 | ||
| 337 | void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) { | 319 | void 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 { | |||
| 225 | public: | 225 | public: |
| 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); |