diff options
| author | 2019-04-28 21:08:31 -0300 | |
|---|---|---|
| committer | 2019-06-20 21:38:33 -0300 | |
| commit | 007ffbef1c3bb6ae5fb85d24754a60d4eea87e45 (patch) | |
| tree | 1e82380947cab3bb4dc6d952acd600682e6d173f /src | |
| parent | video_core: Make ARB_buffer_storage a required extension (diff) | |
| download | yuzu-007ffbef1c3bb6ae5fb85d24754a60d4eea87e45.tar.gz yuzu-007ffbef1c3bb6ae5fb85d24754a60d4eea87e45.tar.xz yuzu-007ffbef1c3bb6ae5fb85d24754a60d4eea87e45.zip | |
gl_rasterizer: Track texture buffer usage
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 34 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 78 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.h | 17 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.h | 53 |
6 files changed, 119 insertions, 74 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 56f2d2972..4f7eeb22c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -29,8 +29,10 @@ | |||
| 29 | namespace OpenGL { | 29 | namespace OpenGL { |
| 30 | 30 | ||
| 31 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 31 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 32 | using PixelFormat = VideoCore::Surface::PixelFormat; | 32 | |
| 33 | using SurfaceType = VideoCore::Surface::SurfaceType; | 33 | using VideoCore::Surface::PixelFormat; |
| 34 | using VideoCore::Surface::SurfaceTarget; | ||
| 35 | using VideoCore::Surface::SurfaceType; | ||
| 34 | 36 | ||
| 35 | MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192)); | 37 | MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192)); |
| 36 | MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192)); | 38 | MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192)); |
| @@ -281,8 +283,14 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||
| 281 | static_cast<GLsizeiptr>(sizeof(ubo))); | 283 | static_cast<GLsizeiptr>(sizeof(ubo))); |
| 282 | 284 | ||
| 283 | Shader shader{shader_cache.GetStageProgram(program)}; | 285 | Shader shader{shader_cache.GetStageProgram(program)}; |
| 284 | const auto [program_handle, next_bindings] = | 286 | |
| 285 | shader->GetProgramHandle(primitive_mode, base_bindings); | 287 | const auto stage_enum{static_cast<Maxwell::ShaderStage>(stage)}; |
| 288 | SetupDrawConstBuffers(stage_enum, shader); | ||
| 289 | SetupGlobalRegions(stage_enum, shader); | ||
| 290 | const auto texture_buffer_usage{SetupTextures(stage_enum, shader, base_bindings)}; | ||
| 291 | |||
| 292 | const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage}; | ||
| 293 | const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant); | ||
| 286 | 294 | ||
| 287 | switch (program) { | 295 | switch (program) { |
| 288 | case Maxwell::ShaderProgram::VertexA: | 296 | case Maxwell::ShaderProgram::VertexA: |
| @@ -300,11 +308,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { | |||
| 300 | shader_config.enable.Value(), shader_config.offset); | 308 | shader_config.enable.Value(), shader_config.offset); |
| 301 | } | 309 | } |
| 302 | 310 | ||
| 303 | const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage); | ||
| 304 | SetupDrawConstBuffers(stage_enum, shader); | ||
| 305 | SetupGlobalRegions(stage_enum, shader); | ||
| 306 | SetupTextures(stage_enum, shader, base_bindings); | ||
| 307 | |||
| 308 | // Workaround for Intel drivers. | 311 | // Workaround for Intel drivers. |
| 309 | // When a clip distance is enabled but not set in the shader it crops parts of the screen | 312 | // When a clip distance is enabled but not set in the shader it crops parts of the screen |
| 310 | // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the | 313 | // (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 | |||
| 791 | } | 794 | } |
| 792 | } | 795 | } |
| 793 | 796 | ||
| 794 | void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, | 797 | TextureBufferUsage RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, |
| 795 | BaseBindings base_bindings) { | 798 | BaseBindings base_bindings) { |
| 796 | MICROPROFILE_SCOPE(OpenGL_Texture); | 799 | MICROPROFILE_SCOPE(OpenGL_Texture); |
| 797 | const auto& gpu = system.GPU(); | 800 | const auto& gpu = system.GPU(); |
| 798 | const auto& maxwell3d = gpu.Maxwell3D(); | 801 | const auto& maxwell3d = gpu.Maxwell3D(); |
| @@ -801,6 +804,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s | |||
| 801 | ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units), | 804 | ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units), |
| 802 | "Exceeded the number of active textures."); | 805 | "Exceeded the number of active textures."); |
| 803 | 806 | ||
| 807 | TextureBufferUsage texture_buffer_usage{0}; | ||
| 808 | |||
| 804 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { | 809 | for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { |
| 805 | const auto& entry = entries[bindpoint]; | 810 | const auto& entry = entries[bindpoint]; |
| 806 | Tegra::Texture::FullTextureInfo texture; | 811 | Tegra::Texture::FullTextureInfo texture; |
| @@ -814,7 +819,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s | |||
| 814 | } | 819 | } |
| 815 | const u32 current_bindpoint = base_bindings.sampler + bindpoint; | 820 | const u32 current_bindpoint = base_bindings.sampler + bindpoint; |
| 816 | 821 | ||
| 817 | state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc); | 822 | auto& unit{state.texture_units[current_bindpoint]}; |
| 823 | unit.sampler = sampler_cache.GetSampler(texture.tsc); | ||
| 818 | 824 | ||
| 819 | if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) { | 825 | if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) { |
| 820 | view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, | 826 | 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 | |||
| 822 | state.texture_units[current_bindpoint].texture = view->GetTexture(); | 828 | state.texture_units[current_bindpoint].texture = view->GetTexture(); |
| 823 | } else { | 829 | } else { |
| 824 | // Can occur when texture addr is null or its memory is unmapped/invalid | 830 | // Can occur when texture addr is null or its memory is unmapped/invalid |
| 825 | state.texture_units[current_bindpoint].texture = 0; | 831 | unit.texture = 0; |
| 826 | } | 832 | } |
| 827 | } | 833 | } |
| 834 | |||
| 835 | return texture_buffer_usage; | ||
| 828 | } | 836 | } |
| 829 | 837 | ||
| 830 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | 838 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 2f13d9758..64c27660f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -126,9 +126,10 @@ private: | |||
| 126 | void SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, | 126 | void SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, |
| 127 | const Shader& shader); | 127 | const Shader& shader); |
| 128 | 128 | ||
| 129 | /// Configures the current textures to use for the draw command. | 129 | /// Configures the current textures to use for the draw command. Returns shaders texture buffer |
| 130 | void SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader, | 130 | /// usage. |
| 131 | BaseBindings base_bindings); | 131 | TextureBufferUsage SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, |
| 132 | const Shader& shader, BaseBindings base_bindings); | ||
| 132 | 133 | ||
| 133 | /// Syncs the viewport and depth range to match the guest state | 134 | /// Syncs the viewport and depth range to match the guest state |
| 134 | void SyncViewport(OpenGLState& current_state); | 135 | void SyncViewport(OpenGLState& current_state); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index ac8a9e6b7..e859a900c 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -168,8 +168,12 @@ GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgr | |||
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries, | 170 | CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries, |
| 171 | Maxwell::ShaderProgram program_type, BaseBindings base_bindings, | 171 | Maxwell::ShaderProgram program_type, const ProgramVariant& variant, |
| 172 | GLenum primitive_mode, bool hint_retrievable = false) { | 172 | bool hint_retrievable = false) { |
| 173 | auto base_bindings{variant.base_bindings}; | ||
| 174 | const auto primitive_mode{variant.primitive_mode}; | ||
| 175 | const auto texture_buffer_usage{variant.texture_buffer_usage}; | ||
| 176 | |||
| 173 | std::string source = "#version 430 core\n" | 177 | std::string source = "#version 430 core\n" |
| 174 | "#extension GL_ARB_separate_shader_objects : enable\n\n"; | 178 | "#extension GL_ARB_separate_shader_objects : enable\n\n"; |
| 175 | source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); | 179 | source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); |
| @@ -187,6 +191,14 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn | |||
| 187 | base_bindings.sampler++); | 191 | base_bindings.sampler++); |
| 188 | } | 192 | } |
| 189 | 193 | ||
| 194 | // Transform 1D textures to texture samplers by declaring its preprocessor macros. | ||
| 195 | for (std::size_t i = 0; i < texture_buffer_usage.size(); ++i) { | ||
| 196 | if (!texture_buffer_usage.test(i)) { | ||
| 197 | continue; | ||
| 198 | } | ||
| 199 | source += fmt::format("#define SAMPLER_{}_IS_BUFFER", i); | ||
| 200 | } | ||
| 201 | |||
| 190 | if (program_type == Maxwell::ShaderProgram::Geometry) { | 202 | if (program_type == Maxwell::ShaderProgram::Geometry) { |
| 191 | const auto [glsl_topology, debug_name, max_vertices] = | 203 | const auto [glsl_topology, debug_name, max_vertices] = |
| 192 | GetPrimitiveDescription(primitive_mode); | 204 | GetPrimitiveDescription(primitive_mode); |
| @@ -261,20 +273,18 @@ CachedShader::CachedShader(VAddr cpu_addr, u64 unique_identifier, | |||
| 261 | shader_length = entries.shader_length; | 273 | shader_length = entries.shader_length; |
| 262 | } | 274 | } |
| 263 | 275 | ||
| 264 | std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive_mode, | 276 | std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) { |
| 265 | BaseBindings base_bindings) { | ||
| 266 | GLuint handle{}; | 277 | GLuint handle{}; |
| 267 | if (program_type == Maxwell::ShaderProgram::Geometry) { | 278 | if (program_type == Maxwell::ShaderProgram::Geometry) { |
| 268 | handle = GetGeometryShader(primitive_mode, base_bindings); | 279 | handle = GetGeometryShader(variant); |
| 269 | } else { | 280 | } else { |
| 270 | const auto [entry, is_cache_miss] = programs.try_emplace(base_bindings); | 281 | const auto [entry, is_cache_miss] = programs.try_emplace(variant); |
| 271 | auto& program = entry->second; | 282 | auto& program = entry->second; |
| 272 | if (is_cache_miss) { | 283 | if (is_cache_miss) { |
| 273 | program = TryLoadProgram(primitive_mode, base_bindings); | 284 | program = TryLoadProgram(variant); |
| 274 | if (!program) { | 285 | if (!program) { |
| 275 | program = | 286 | program = SpecializeShader(code, entries, program_type, variant); |
| 276 | SpecializeShader(code, entries, program_type, base_bindings, primitive_mode); | 287 | disk_cache.SaveUsage(GetUsage(variant)); |
| 277 | disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings)); | ||
| 278 | } | 288 | } |
| 279 | 289 | ||
| 280 | LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); | 290 | LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); |
| @@ -283,6 +293,7 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive | |||
| 283 | handle = program->handle; | 293 | handle = program->handle; |
| 284 | } | 294 | } |
| 285 | 295 | ||
| 296 | auto base_bindings{variant.base_bindings}; | ||
| 286 | base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + RESERVED_UBOS; | 297 | base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + RESERVED_UBOS; |
| 287 | base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size()); | 298 | base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size()); |
| 288 | base_bindings.sampler += static_cast<u32>(entries.samplers.size()); | 299 | base_bindings.sampler += static_cast<u32>(entries.samplers.size()); |
| @@ -290,43 +301,42 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive | |||
| 290 | return {handle, base_bindings}; | 301 | return {handle, base_bindings}; |
| 291 | } | 302 | } |
| 292 | 303 | ||
| 293 | GLuint CachedShader::GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings) { | 304 | GLuint CachedShader::GetGeometryShader(const ProgramVariant& variant) { |
| 294 | const auto [entry, is_cache_miss] = geometry_programs.try_emplace(base_bindings); | 305 | const auto [entry, is_cache_miss] = geometry_programs.try_emplace(variant); |
| 295 | auto& programs = entry->second; | 306 | auto& programs = entry->second; |
| 296 | 307 | ||
| 297 | switch (primitive_mode) { | 308 | switch (variant.primitive_mode) { |
| 298 | case GL_POINTS: | 309 | case GL_POINTS: |
| 299 | return LazyGeometryProgram(programs.points, base_bindings, primitive_mode); | 310 | return LazyGeometryProgram(programs.points, variant); |
| 300 | case GL_LINES: | 311 | case GL_LINES: |
| 301 | case GL_LINE_STRIP: | 312 | case GL_LINE_STRIP: |
| 302 | return LazyGeometryProgram(programs.lines, base_bindings, primitive_mode); | 313 | return LazyGeometryProgram(programs.lines, variant); |
| 303 | case GL_LINES_ADJACENCY: | 314 | case GL_LINES_ADJACENCY: |
| 304 | case GL_LINE_STRIP_ADJACENCY: | 315 | case GL_LINE_STRIP_ADJACENCY: |
| 305 | return LazyGeometryProgram(programs.lines_adjacency, base_bindings, primitive_mode); | 316 | return LazyGeometryProgram(programs.lines_adjacency, variant); |
| 306 | case GL_TRIANGLES: | 317 | case GL_TRIANGLES: |
| 307 | case GL_TRIANGLE_STRIP: | 318 | case GL_TRIANGLE_STRIP: |
| 308 | case GL_TRIANGLE_FAN: | 319 | case GL_TRIANGLE_FAN: |
| 309 | return LazyGeometryProgram(programs.triangles, base_bindings, primitive_mode); | 320 | return LazyGeometryProgram(programs.triangles, variant); |
| 310 | case GL_TRIANGLES_ADJACENCY: | 321 | case GL_TRIANGLES_ADJACENCY: |
| 311 | case GL_TRIANGLE_STRIP_ADJACENCY: | 322 | case GL_TRIANGLE_STRIP_ADJACENCY: |
| 312 | return LazyGeometryProgram(programs.triangles_adjacency, base_bindings, primitive_mode); | 323 | return LazyGeometryProgram(programs.triangles_adjacency, variant); |
| 313 | default: | 324 | default: |
| 314 | UNREACHABLE_MSG("Unknown primitive mode."); | 325 | UNREACHABLE_MSG("Unknown primitive mode."); |
| 315 | return LazyGeometryProgram(programs.points, base_bindings, primitive_mode); | 326 | return LazyGeometryProgram(programs.points, variant); |
| 316 | } | 327 | } |
| 317 | } | 328 | } |
| 318 | 329 | ||
| 319 | GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings, | 330 | GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, |
| 320 | GLenum primitive_mode) { | 331 | const ProgramVariant& variant) { |
| 321 | if (target_program) { | 332 | if (target_program) { |
| 322 | return target_program->handle; | 333 | return target_program->handle; |
| 323 | } | 334 | } |
| 324 | const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(primitive_mode); | 335 | const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(variant.primitive_mode); |
| 325 | target_program = TryLoadProgram(primitive_mode, base_bindings); | 336 | target_program = TryLoadProgram(variant); |
| 326 | if (!target_program) { | 337 | if (!target_program) { |
| 327 | target_program = | 338 | target_program = SpecializeShader(code, entries, program_type, variant); |
| 328 | SpecializeShader(code, entries, program_type, base_bindings, primitive_mode); | 339 | disk_cache.SaveUsage(GetUsage(variant)); |
| 329 | disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings)); | ||
| 330 | } | 340 | } |
| 331 | 341 | ||
| 332 | LabelGLObject(GL_PROGRAM, target_program->handle, cpu_addr, debug_name); | 342 | LabelGLObject(GL_PROGRAM, target_program->handle, cpu_addr, debug_name); |
| @@ -334,18 +344,19 @@ GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBind | |||
| 334 | return target_program->handle; | 344 | return target_program->handle; |
| 335 | }; | 345 | }; |
| 336 | 346 | ||
| 337 | CachedProgram CachedShader::TryLoadProgram(GLenum primitive_mode, | 347 | CachedProgram CachedShader::TryLoadProgram(const ProgramVariant& variant) const { |
| 338 | BaseBindings base_bindings) const { | 348 | const auto found = precompiled_programs.find(GetUsage(variant)); |
| 339 | const auto found = precompiled_programs.find(GetUsage(primitive_mode, base_bindings)); | ||
| 340 | if (found == precompiled_programs.end()) { | 349 | if (found == precompiled_programs.end()) { |
| 341 | return {}; | 350 | return {}; |
| 342 | } | 351 | } |
| 343 | return found->second; | 352 | return found->second; |
| 344 | } | 353 | } |
| 345 | 354 | ||
| 346 | ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode, | 355 | ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant) const { |
| 347 | BaseBindings base_bindings) const { | 356 | ShaderDiskCacheUsage usage; |
| 348 | return {unique_identifier, base_bindings, primitive_mode}; | 357 | usage.unique_identifier = unique_identifier; |
| 358 | usage.variant = variant; | ||
| 359 | return usage; | ||
| 349 | } | 360 | } |
| 350 | 361 | ||
| 351 | ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, | 362 | ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, |
| @@ -411,8 +422,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 411 | } | 422 | } |
| 412 | if (!shader) { | 423 | if (!shader) { |
| 413 | shader = SpecializeShader(unspecialized.code, unspecialized.entries, | 424 | shader = SpecializeShader(unspecialized.code, unspecialized.entries, |
| 414 | unspecialized.program_type, usage.bindings, | 425 | unspecialized.program_type, usage.variant, true); |
| 415 | usage.primitive, true); | ||
| 416 | } | 426 | } |
| 417 | 427 | ||
| 418 | std::scoped_lock lock(mutex); | 428 | std::scoped_lock lock(mutex); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 09bd0761d..59bcb14e8 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <atomic> | 8 | #include <atomic> |
| 9 | #include <bitset> | ||
| 9 | #include <memory> | 10 | #include <memory> |
| 10 | #include <set> | 11 | #include <set> |
| 11 | #include <tuple> | 12 | #include <tuple> |
| @@ -67,8 +68,7 @@ public: | |||
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | /// Gets the GL program handle for the shader | 70 | /// Gets the GL program handle for the shader |
| 70 | std::tuple<GLuint, BaseBindings> GetProgramHandle(GLenum primitive_mode, | 71 | std::tuple<GLuint, BaseBindings> GetProgramHandle(const ProgramVariant& variant); |
| 71 | BaseBindings base_bindings); | ||
| 72 | 72 | ||
| 73 | private: | 73 | private: |
| 74 | // Geometry programs. These are needed because GLSL needs an input topology but it's not | 74 | // Geometry programs. These are needed because GLSL needs an input topology but it's not |
| @@ -82,15 +82,14 @@ private: | |||
| 82 | CachedProgram triangles_adjacency; | 82 | CachedProgram triangles_adjacency; |
| 83 | }; | 83 | }; |
| 84 | 84 | ||
| 85 | GLuint GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings); | 85 | GLuint GetGeometryShader(const ProgramVariant& variant); |
| 86 | 86 | ||
| 87 | /// Generates a geometry shader or returns one that already exists. | 87 | /// Generates a geometry shader or returns one that already exists. |
| 88 | GLuint LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings, | 88 | GLuint LazyGeometryProgram(CachedProgram& target_program, const ProgramVariant& variant); |
| 89 | GLenum primitive_mode); | ||
| 90 | 89 | ||
| 91 | CachedProgram TryLoadProgram(GLenum primitive_mode, BaseBindings base_bindings) const; | 90 | CachedProgram TryLoadProgram(const ProgramVariant& variant) const; |
| 92 | 91 | ||
| 93 | ShaderDiskCacheUsage GetUsage(GLenum primitive_mode, BaseBindings base_bindings) const; | 92 | ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant) const; |
| 94 | 93 | ||
| 95 | u8* host_ptr{}; | 94 | u8* host_ptr{}; |
| 96 | VAddr cpu_addr{}; | 95 | VAddr cpu_addr{}; |
| @@ -104,8 +103,8 @@ private: | |||
| 104 | 103 | ||
| 105 | std::string code; | 104 | std::string code; |
| 106 | 105 | ||
| 107 | std::unordered_map<BaseBindings, CachedProgram> programs; | 106 | std::unordered_map<ProgramVariant, CachedProgram> programs; |
| 108 | std::unordered_map<BaseBindings, GeometryPrograms> geometry_programs; | 107 | std::unordered_map<ProgramVariant, GeometryPrograms> geometry_programs; |
| 109 | 108 | ||
| 110 | std::unordered_map<u32, GLuint> cbuf_resource_cache; | 109 | std::unordered_map<u32, GLuint> cbuf_resource_cache; |
| 111 | std::unordered_map<u32, GLuint> gmem_resource_cache; | 110 | std::unordered_map<u32, GLuint> gmem_resource_cache; |
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 ee4a45ca2..d338ece8e 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -34,11 +34,11 @@ enum class PrecompiledEntryKind : u32 { | |||
| 34 | Dump, | 34 | Dump, |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | constexpr u32 NativeVersion = 1; | 37 | constexpr u32 NativeVersion = 2; |
| 38 | 38 | ||
| 39 | // Making sure sizes doesn't change by accident | 39 | // Making sure sizes doesn't change by accident |
| 40 | static_assert(sizeof(BaseBindings) == 12); | 40 | static_assert(sizeof(BaseBindings) == 12); |
| 41 | static_assert(sizeof(ShaderDiskCacheUsage) == 24); | 41 | static_assert(sizeof(ShaderDiskCacheUsage) == 32); |
| 42 | 42 | ||
| 43 | namespace { | 43 | namespace { |
| 44 | 44 | ||
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 ecd72ba58..7c9f0cc75 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h | |||
| @@ -30,15 +30,17 @@ class IOFile; | |||
| 30 | 30 | ||
| 31 | namespace OpenGL { | 31 | namespace OpenGL { |
| 32 | 32 | ||
| 33 | using ProgramCode = std::vector<u64>; | ||
| 34 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 35 | |||
| 36 | struct ShaderDiskCacheUsage; | 33 | struct ShaderDiskCacheUsage; |
| 37 | struct ShaderDiskCacheDump; | 34 | struct ShaderDiskCacheDump; |
| 38 | 35 | ||
| 39 | using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>; | 36 | using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>; |
| 40 | 37 | ||
| 41 | /// Allocated bindings used by an OpenGL shader program | 38 | using ProgramCode = std::vector<u64>; |
| 39 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 40 | |||
| 41 | using TextureBufferUsage = std::bitset<64>; | ||
| 42 | |||
| 43 | /// Allocated bindings used by an OpenGL shader program. | ||
| 42 | struct BaseBindings { | 44 | struct BaseBindings { |
| 43 | u32 cbuf{}; | 45 | u32 cbuf{}; |
| 44 | u32 gmem{}; | 46 | u32 gmem{}; |
| @@ -53,15 +55,29 @@ struct BaseBindings { | |||
| 53 | } | 55 | } |
| 54 | }; | 56 | }; |
| 55 | 57 | ||
| 56 | /// Describes how a shader is used | 58 | /// Describes the different variants a single program can be compiled. |
| 59 | struct ProgramVariant { | ||
| 60 | BaseBindings base_bindings; | ||
| 61 | GLenum primitive_mode{}; | ||
| 62 | TextureBufferUsage texture_buffer_usage{}; | ||
| 63 | |||
| 64 | bool operator==(const ProgramVariant& rhs) const { | ||
| 65 | return std::tie(base_bindings, primitive_mode, texture_buffer_usage) == | ||
| 66 | std::tie(rhs.base_bindings, rhs.primitive_mode, rhs.texture_buffer_usage); | ||
| 67 | } | ||
| 68 | |||
| 69 | bool operator!=(const ProgramVariant& rhs) const { | ||
| 70 | return !operator==(rhs); | ||
| 71 | } | ||
| 72 | }; | ||
| 73 | |||
| 74 | /// Describes how a shader is used. | ||
| 57 | struct ShaderDiskCacheUsage { | 75 | struct ShaderDiskCacheUsage { |
| 58 | u64 unique_identifier{}; | 76 | u64 unique_identifier{}; |
| 59 | BaseBindings bindings; | 77 | ProgramVariant variant; |
| 60 | GLenum primitive{}; | ||
| 61 | 78 | ||
| 62 | bool operator==(const ShaderDiskCacheUsage& rhs) const { | 79 | bool operator==(const ShaderDiskCacheUsage& rhs) const { |
| 63 | return std::tie(unique_identifier, bindings, primitive) == | 80 | return std::tie(unique_identifier, variant) == std::tie(rhs.unique_identifier, rhs.variant); |
| 64 | std::tie(rhs.unique_identifier, rhs.bindings, rhs.primitive); | ||
| 65 | } | 81 | } |
| 66 | 82 | ||
| 67 | bool operator!=(const ShaderDiskCacheUsage& rhs) const { | 83 | bool operator!=(const ShaderDiskCacheUsage& rhs) const { |
| @@ -81,10 +97,19 @@ struct hash<OpenGL::BaseBindings> { | |||
| 81 | }; | 97 | }; |
| 82 | 98 | ||
| 83 | template <> | 99 | template <> |
| 100 | struct hash<OpenGL::ProgramVariant> { | ||
| 101 | std::size_t operator()(const OpenGL::ProgramVariant& variant) const { | ||
| 102 | return std::hash<OpenGL::BaseBindings>()(variant.base_bindings) ^ | ||
| 103 | std::hash<OpenGL::TextureBufferUsage>()(variant.texture_buffer_usage) ^ | ||
| 104 | (static_cast<std::size_t>(variant.primitive_mode) << 6); | ||
| 105 | } | ||
| 106 | }; | ||
| 107 | |||
| 108 | template <> | ||
| 84 | struct hash<OpenGL::ShaderDiskCacheUsage> { | 109 | struct hash<OpenGL::ShaderDiskCacheUsage> { |
| 85 | std::size_t operator()(const OpenGL::ShaderDiskCacheUsage& usage) const noexcept { | 110 | std::size_t operator()(const OpenGL::ShaderDiskCacheUsage& usage) const noexcept { |
| 86 | return static_cast<std::size_t>(usage.unique_identifier) ^ | 111 | return static_cast<std::size_t>(usage.unique_identifier) ^ |
| 87 | std::hash<OpenGL::BaseBindings>()(usage.bindings) ^ usage.primitive << 16; | 112 | std::hash<OpenGL::ProgramVariant>()(usage.variant); |
| 88 | } | 113 | } |
| 89 | }; | 114 | }; |
| 90 | 115 | ||
| @@ -288,13 +313,15 @@ private: | |||
| 288 | 313 | ||
| 289 | // Core system | 314 | // Core system |
| 290 | Core::System& system; | 315 | Core::System& system; |
| 291 | // Stored transferable shaders | 316 | // Stores whole precompiled cache which will be read from or saved to the precompiled chache |
| 292 | std::map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable; | 317 | // file |
| 293 | // Stores whole precompiled cache which will be read from/saved to the precompiled cache file | ||
| 294 | FileSys::VectorVfsFile precompiled_cache_virtual_file; | 318 | FileSys::VectorVfsFile precompiled_cache_virtual_file; |
| 295 | // Stores the current offset of the precompiled cache file for IO purposes | 319 | // Stores the current offset of the precompiled cache file for IO purposes |
| 296 | std::size_t precompiled_cache_virtual_file_offset = 0; | 320 | std::size_t precompiled_cache_virtual_file_offset = 0; |
| 297 | 321 | ||
| 322 | // Stored transferable shaders | ||
| 323 | std::unordered_map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable; | ||
| 324 | |||
| 298 | // The cache has been loaded at boot | 325 | // The cache has been loaded at boot |
| 299 | bool tried_to_load{}; | 326 | bool tried_to_load{}; |
| 300 | }; | 327 | }; |