Browse Source

gl_rasterizer: Track texture buffer usage

ReinUsesLisp 7 years ago
parent
commit
007ffbef1c

+ 21 - 13
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -29,8 +29,10 @@
 namespace OpenGL {
 
 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
-using PixelFormat = VideoCore::Surface::PixelFormat;
-using SurfaceType = VideoCore::Surface::SurfaceType;
+
+using VideoCore::Surface::PixelFormat;
+using VideoCore::Surface::SurfaceTarget;
+using VideoCore::Surface::SurfaceType;
 
 MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192));
 MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192));
@@ -281,8 +283,14 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
                                  static_cast<GLsizeiptr>(sizeof(ubo)));
 
         Shader shader{shader_cache.GetStageProgram(program)};
-        const auto [program_handle, next_bindings] =
-            shader->GetProgramHandle(primitive_mode, base_bindings);
+
+        const auto stage_enum{static_cast<Maxwell::ShaderStage>(stage)};
+        SetupDrawConstBuffers(stage_enum, shader);
+        SetupGlobalRegions(stage_enum, shader);
+        const auto texture_buffer_usage{SetupTextures(stage_enum, shader, base_bindings)};
+
+        const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage};
+        const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
 
         switch (program) {
         case Maxwell::ShaderProgram::VertexA:
@@ -300,11 +308,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
                               shader_config.enable.Value(), shader_config.offset);
         }
 
-        const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage);
-        SetupDrawConstBuffers(stage_enum, shader);
-        SetupGlobalRegions(stage_enum, shader);
-        SetupTextures(stage_enum, shader, base_bindings);
-
         // Workaround for Intel drivers.
         // When a clip distance is enabled but not set in the shader it crops parts of the screen
         // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
@@ -791,8 +794,8 @@ void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::Shade
     }
 }
 
-void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader,
-                                     BaseBindings base_bindings) {
+TextureBufferUsage RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader,
+                                                   BaseBindings base_bindings) {
     MICROPROFILE_SCOPE(OpenGL_Texture);
     const auto& gpu = system.GPU();
     const auto& maxwell3d = gpu.Maxwell3D();
@@ -801,6 +804,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
     ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units),
                "Exceeded the number of active textures.");
 
+    TextureBufferUsage texture_buffer_usage{0};
+
     for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
         const auto& entry = entries[bindpoint];
         Tegra::Texture::FullTextureInfo texture;
@@ -814,7 +819,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
         }
         const u32 current_bindpoint = base_bindings.sampler + bindpoint;
 
-        state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc);
+        auto& unit{state.texture_units[current_bindpoint]};
+        unit.sampler = sampler_cache.GetSampler(texture.tsc);
 
         if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) {
             view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
@@ -822,9 +828,11 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
             state.texture_units[current_bindpoint].texture = view->GetTexture();
         } else {
             // Can occur when texture addr is null or its memory is unmapped/invalid
-            state.texture_units[current_bindpoint].texture = 0;
+            unit.texture = 0;
         }
     }
+
+    return texture_buffer_usage;
 }
 
 void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {

+ 4 - 3
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -126,9 +126,10 @@ private:
     void SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
                             const Shader& shader);
 
-    /// Configures the current textures to use for the draw command.
-    void SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader,
-                       BaseBindings base_bindings);
+    /// Configures the current textures to use for the draw command. Returns shaders texture buffer
+    /// usage.
+    TextureBufferUsage SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
+                                     const Shader& shader, BaseBindings base_bindings);
 
     /// Syncs the viewport and depth range to match the guest state
     void SyncViewport(OpenGLState& current_state);

+ 44 - 34
src/video_core/renderer_opengl/gl_shader_cache.cpp

@@ -168,8 +168,12 @@ GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgr
 }
 
 CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries,
-                               Maxwell::ShaderProgram program_type, BaseBindings base_bindings,
-                               GLenum primitive_mode, bool hint_retrievable = false) {
+                               Maxwell::ShaderProgram program_type, const ProgramVariant& variant,
+                               bool hint_retrievable = false) {
+    auto base_bindings{variant.base_bindings};
+    const auto primitive_mode{variant.primitive_mode};
+    const auto texture_buffer_usage{variant.texture_buffer_usage};
+
     std::string source = "#version 430 core\n"
                          "#extension GL_ARB_separate_shader_objects : enable\n\n";
     source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++);
@@ -187,6 +191,14 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn
                               base_bindings.sampler++);
     }
 
+    // Transform 1D textures to texture samplers by declaring its preprocessor macros.
+    for (std::size_t i = 0; i < texture_buffer_usage.size(); ++i) {
+        if (!texture_buffer_usage.test(i)) {
+            continue;
+        }
+        source += fmt::format("#define SAMPLER_{}_IS_BUFFER", i);
+    }
+
     if (program_type == Maxwell::ShaderProgram::Geometry) {
         const auto [glsl_topology, debug_name, max_vertices] =
             GetPrimitiveDescription(primitive_mode);
@@ -261,20 +273,18 @@ CachedShader::CachedShader(VAddr cpu_addr, u64 unique_identifier,
     shader_length = entries.shader_length;
 }
 
-std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive_mode,
-                                                                BaseBindings base_bindings) {
+std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) {
     GLuint handle{};
     if (program_type == Maxwell::ShaderProgram::Geometry) {
-        handle = GetGeometryShader(primitive_mode, base_bindings);
+        handle = GetGeometryShader(variant);
     } else {
-        const auto [entry, is_cache_miss] = programs.try_emplace(base_bindings);
+        const auto [entry, is_cache_miss] = programs.try_emplace(variant);
         auto& program = entry->second;
         if (is_cache_miss) {
-            program = TryLoadProgram(primitive_mode, base_bindings);
+            program = TryLoadProgram(variant);
             if (!program) {
-                program =
-                    SpecializeShader(code, entries, program_type, base_bindings, primitive_mode);
-                disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings));
+                program = SpecializeShader(code, entries, program_type, variant);
+                disk_cache.SaveUsage(GetUsage(variant));
             }
 
             LabelGLObject(GL_PROGRAM, program->handle, cpu_addr);
@@ -283,6 +293,7 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive
         handle = program->handle;
     }
 
+    auto base_bindings{variant.base_bindings};
     base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + RESERVED_UBOS;
     base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size());
     base_bindings.sampler += static_cast<u32>(entries.samplers.size());
@@ -290,43 +301,42 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive
     return {handle, base_bindings};
 }
 
-GLuint CachedShader::GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings) {
-    const auto [entry, is_cache_miss] = geometry_programs.try_emplace(base_bindings);
+GLuint CachedShader::GetGeometryShader(const ProgramVariant& variant) {
+    const auto [entry, is_cache_miss] = geometry_programs.try_emplace(variant);
     auto& programs = entry->second;
 
-    switch (primitive_mode) {
+    switch (variant.primitive_mode) {
     case GL_POINTS:
-        return LazyGeometryProgram(programs.points, base_bindings, primitive_mode);
+        return LazyGeometryProgram(programs.points, variant);
     case GL_LINES:
     case GL_LINE_STRIP:
-        return LazyGeometryProgram(programs.lines, base_bindings, primitive_mode);
+        return LazyGeometryProgram(programs.lines, variant);
     case GL_LINES_ADJACENCY:
     case GL_LINE_STRIP_ADJACENCY:
-        return LazyGeometryProgram(programs.lines_adjacency, base_bindings, primitive_mode);
+        return LazyGeometryProgram(programs.lines_adjacency, variant);
     case GL_TRIANGLES:
     case GL_TRIANGLE_STRIP:
     case GL_TRIANGLE_FAN:
-        return LazyGeometryProgram(programs.triangles, base_bindings, primitive_mode);
+        return LazyGeometryProgram(programs.triangles, variant);
     case GL_TRIANGLES_ADJACENCY:
     case GL_TRIANGLE_STRIP_ADJACENCY:
-        return LazyGeometryProgram(programs.triangles_adjacency, base_bindings, primitive_mode);
+        return LazyGeometryProgram(programs.triangles_adjacency, variant);
     default:
         UNREACHABLE_MSG("Unknown primitive mode.");
-        return LazyGeometryProgram(programs.points, base_bindings, primitive_mode);
+        return LazyGeometryProgram(programs.points, variant);
     }
 }
 
-GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings,
-                                         GLenum primitive_mode) {
+GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program,
+                                         const ProgramVariant& variant) {
     if (target_program) {
         return target_program->handle;
     }
-    const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(primitive_mode);
-    target_program = TryLoadProgram(primitive_mode, base_bindings);
+    const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(variant.primitive_mode);
+    target_program = TryLoadProgram(variant);
     if (!target_program) {
-        target_program =
-            SpecializeShader(code, entries, program_type, base_bindings, primitive_mode);
-        disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings));
+        target_program = SpecializeShader(code, entries, program_type, variant);
+        disk_cache.SaveUsage(GetUsage(variant));
     }
 
     LabelGLObject(GL_PROGRAM, target_program->handle, cpu_addr, debug_name);
@@ -334,18 +344,19 @@ GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBind
     return target_program->handle;
 };
 
-CachedProgram CachedShader::TryLoadProgram(GLenum primitive_mode,
-                                           BaseBindings base_bindings) const {
-    const auto found = precompiled_programs.find(GetUsage(primitive_mode, base_bindings));
+CachedProgram CachedShader::TryLoadProgram(const ProgramVariant& variant) const {
+    const auto found = precompiled_programs.find(GetUsage(variant));
     if (found == precompiled_programs.end()) {
         return {};
     }
     return found->second;
 }
 
-ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode,
-                                            BaseBindings base_bindings) const {
-    return {unique_identifier, base_bindings, primitive_mode};
+ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant) const {
+    ShaderDiskCacheUsage usage;
+    usage.unique_identifier = unique_identifier;
+    usage.variant = variant;
+    return usage;
 }
 
 ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
@@ -411,8 +422,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
             }
             if (!shader) {
                 shader = SpecializeShader(unspecialized.code, unspecialized.entries,
-                                          unspecialized.program_type, usage.bindings,
-                                          usage.primitive, true);
+                                          unspecialized.program_type, usage.variant, true);
             }
 
             std::scoped_lock lock(mutex);

+ 8 - 9
src/video_core/renderer_opengl/gl_shader_cache.h

@@ -6,6 +6,7 @@
 
 #include <array>
 #include <atomic>
+#include <bitset>
 #include <memory>
 #include <set>
 #include <tuple>
@@ -67,8 +68,7 @@ public:
     }
 
     /// Gets the GL program handle for the shader
-    std::tuple<GLuint, BaseBindings> GetProgramHandle(GLenum primitive_mode,
-                                                      BaseBindings base_bindings);
+    std::tuple<GLuint, BaseBindings> GetProgramHandle(const ProgramVariant& variant);
 
 private:
     // Geometry programs. These are needed because GLSL needs an input topology but it's not
@@ -82,15 +82,14 @@ private:
         CachedProgram triangles_adjacency;
     };
 
-    GLuint GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings);
+    GLuint GetGeometryShader(const ProgramVariant& variant);
 
     /// Generates a geometry shader or returns one that already exists.
-    GLuint LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings,
-                               GLenum primitive_mode);
+    GLuint LazyGeometryProgram(CachedProgram& target_program, const ProgramVariant& variant);
 
-    CachedProgram TryLoadProgram(GLenum primitive_mode, BaseBindings base_bindings) const;
+    CachedProgram TryLoadProgram(const ProgramVariant& variant) const;
 
-    ShaderDiskCacheUsage GetUsage(GLenum primitive_mode, BaseBindings base_bindings) const;
+    ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant) const;
 
     u8* host_ptr{};
     VAddr cpu_addr{};
@@ -104,8 +103,8 @@ private:
 
     std::string code;
 
-    std::unordered_map<BaseBindings, CachedProgram> programs;
-    std::unordered_map<BaseBindings, GeometryPrograms> geometry_programs;
+    std::unordered_map<ProgramVariant, CachedProgram> programs;
+    std::unordered_map<ProgramVariant, GeometryPrograms> geometry_programs;
 
     std::unordered_map<u32, GLuint> cbuf_resource_cache;
     std::unordered_map<u32, GLuint> gmem_resource_cache;

+ 2 - 2
src/video_core/renderer_opengl/gl_shader_disk_cache.cpp

@@ -34,11 +34,11 @@ enum class PrecompiledEntryKind : u32 {
     Dump,
 };
 
-constexpr u32 NativeVersion = 1;
+constexpr u32 NativeVersion = 2;
 
 // Making sure sizes doesn't change by accident
 static_assert(sizeof(BaseBindings) == 12);
-static_assert(sizeof(ShaderDiskCacheUsage) == 24);
+static_assert(sizeof(ShaderDiskCacheUsage) == 32);
 
 namespace {
 

+ 40 - 13
src/video_core/renderer_opengl/gl_shader_disk_cache.h

@@ -30,15 +30,17 @@ class IOFile;
 
 namespace OpenGL {
 
-using ProgramCode = std::vector<u64>;
-using Maxwell = Tegra::Engines::Maxwell3D::Regs;
-
 struct ShaderDiskCacheUsage;
 struct ShaderDiskCacheDump;
 
 using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>;
 
-/// Allocated bindings used by an OpenGL shader program
+using ProgramCode = std::vector<u64>;
+using Maxwell = Tegra::Engines::Maxwell3D::Regs;
+
+using TextureBufferUsage = std::bitset<64>;
+
+/// Allocated bindings used by an OpenGL shader program.
 struct BaseBindings {
     u32 cbuf{};
     u32 gmem{};
@@ -53,15 +55,29 @@ struct BaseBindings {
     }
 };
 
-/// Describes how a shader is used
+/// Describes the different variants a single program can be compiled.
+struct ProgramVariant {
+    BaseBindings base_bindings;
+    GLenum primitive_mode{};
+    TextureBufferUsage texture_buffer_usage{};
+
+    bool operator==(const ProgramVariant& rhs) const {
+        return std::tie(base_bindings, primitive_mode, texture_buffer_usage) ==
+               std::tie(rhs.base_bindings, rhs.primitive_mode, rhs.texture_buffer_usage);
+    }
+
+    bool operator!=(const ProgramVariant& rhs) const {
+        return !operator==(rhs);
+    }
+};
+
+/// Describes how a shader is used.
 struct ShaderDiskCacheUsage {
     u64 unique_identifier{};
-    BaseBindings bindings;
-    GLenum primitive{};
+    ProgramVariant variant;
 
     bool operator==(const ShaderDiskCacheUsage& rhs) const {
-        return std::tie(unique_identifier, bindings, primitive) ==
-               std::tie(rhs.unique_identifier, rhs.bindings, rhs.primitive);
+        return std::tie(unique_identifier, variant) == std::tie(rhs.unique_identifier, rhs.variant);
     }
 
     bool operator!=(const ShaderDiskCacheUsage& rhs) const {
@@ -80,11 +96,20 @@ struct hash<OpenGL::BaseBindings> {
     }
 };
 
+template <>
+struct hash<OpenGL::ProgramVariant> {
+    std::size_t operator()(const OpenGL::ProgramVariant& variant) const {
+        return std::hash<OpenGL::BaseBindings>()(variant.base_bindings) ^
+               std::hash<OpenGL::TextureBufferUsage>()(variant.texture_buffer_usage) ^
+               (static_cast<std::size_t>(variant.primitive_mode) << 6);
+    }
+};
+
 template <>
 struct hash<OpenGL::ShaderDiskCacheUsage> {
     std::size_t operator()(const OpenGL::ShaderDiskCacheUsage& usage) const noexcept {
         return static_cast<std::size_t>(usage.unique_identifier) ^
-               std::hash<OpenGL::BaseBindings>()(usage.bindings) ^ usage.primitive << 16;
+               std::hash<OpenGL::ProgramVariant>()(usage.variant);
     }
 };
 
@@ -288,13 +313,15 @@ private:
 
     // Core system
     Core::System& system;
-    // Stored transferable shaders
-    std::map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable;
-    // Stores whole precompiled cache which will be read from/saved to the precompiled cache file
+    // Stores whole precompiled cache which will be read from or saved to the precompiled chache
+    // file
     FileSys::VectorVfsFile precompiled_cache_virtual_file;
     // Stores the current offset of the precompiled cache file for IO purposes
     std::size_t precompiled_cache_virtual_file_offset = 0;
 
+    // Stored transferable shaders
+    std::unordered_map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable;
+
     // The cache has been loaded at boot
     bool tried_to_load{};
 };