summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp34
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp78
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h17
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h53
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 @@
29namespace OpenGL { 29namespace OpenGL {
30 30
31using Maxwell = Tegra::Engines::Maxwell3D::Regs; 31using Maxwell = Tegra::Engines::Maxwell3D::Regs;
32using PixelFormat = VideoCore::Surface::PixelFormat; 32
33using SurfaceType = VideoCore::Surface::SurfaceType; 33using VideoCore::Surface::PixelFormat;
34using VideoCore::Surface::SurfaceTarget;
35using VideoCore::Surface::SurfaceType;
34 36
35MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192)); 37MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192));
36MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192)); 38MICROPROFILE_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
794void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, 797TextureBufferUsage 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
830void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { 838void 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
170CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries, 170CachedProgram 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
264std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive_mode, 276std::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
293GLuint CachedShader::GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings) { 304GLuint 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
319GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings, 330GLuint 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
337CachedProgram CachedShader::TryLoadProgram(GLenum primitive_mode, 347CachedProgram 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
346ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode, 355ShaderDiskCacheUsage 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
351ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, 362ShaderCacheOpenGL::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
73private: 73private:
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
37constexpr u32 NativeVersion = 1; 37constexpr u32 NativeVersion = 2;
38 38
39// Making sure sizes doesn't change by accident 39// Making sure sizes doesn't change by accident
40static_assert(sizeof(BaseBindings) == 12); 40static_assert(sizeof(BaseBindings) == 12);
41static_assert(sizeof(ShaderDiskCacheUsage) == 24); 41static_assert(sizeof(ShaderDiskCacheUsage) == 32);
42 42
43namespace { 43namespace {
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
31namespace OpenGL { 31namespace OpenGL {
32 32
33using ProgramCode = std::vector<u64>;
34using Maxwell = Tegra::Engines::Maxwell3D::Regs;
35
36struct ShaderDiskCacheUsage; 33struct ShaderDiskCacheUsage;
37struct ShaderDiskCacheDump; 34struct ShaderDiskCacheDump;
38 35
39using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>; 36using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>;
40 37
41/// Allocated bindings used by an OpenGL shader program 38using ProgramCode = std::vector<u64>;
39using Maxwell = Tegra::Engines::Maxwell3D::Regs;
40
41using TextureBufferUsage = std::bitset<64>;
42
43/// Allocated bindings used by an OpenGL shader program.
42struct BaseBindings { 44struct 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.
59struct 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.
57struct ShaderDiskCacheUsage { 75struct 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
83template <> 99template <>
100struct 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
108template <>
84struct hash<OpenGL::ShaderDiskCacheUsage> { 109struct 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};