summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-01-15 01:07:57 -0300
committerGravatar ReinUsesLisp2019-02-06 22:23:39 -0300
commitcfb20c4c9d863698b938aaad3d27cfe8e4eedb2b (patch)
tree1ba7045068bc52438b1e40548597c4f4cec62120 /src
parentsettings: Hide shader cache behind a setting (diff)
downloadyuzu-cfb20c4c9d863698b938aaad3d27cfe8e4eedb2b.tar.gz
yuzu-cfb20c4c9d863698b938aaad3d27cfe8e4eedb2b.tar.xz
yuzu-cfb20c4c9d863698b938aaad3d27cfe8e4eedb2b.zip
gl_shader_disk_cache: Save GLSL and entries into the precompiled file
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp71
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h9
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h65
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp177
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h21
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h2
-rw-r--r--src/video_core/shader/shader_ir.h9
9 files changed, 234 insertions, 135 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 18aafe767..48e003fa1 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1009,22 +1009,20 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
1009 1009
1010 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 1010 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
1011 const auto& entry = entries[bindpoint]; 1011 const auto& entry = entries[bindpoint];
1012 const auto texture = maxwell3d.GetStageTexture(stage, entry.GetOffset());
1012 const u32 current_bindpoint = base_bindings.sampler + bindpoint; 1013 const u32 current_bindpoint = base_bindings.sampler + bindpoint;
1013 auto& unit = state.texture_units[current_bindpoint];
1014
1015 const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
1016 1014
1017 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); 1015 texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
1018 1016
1019 Surface surface = res_cache.GetTextureSurface(texture, entry); 1017 Surface surface = res_cache.GetTextureSurface(texture, entry);
1020 if (surface != nullptr) { 1018 if (surface != nullptr) {
1021 unit.texture = 1019 state.texture_units[current_bindpoint].texture =
1022 entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle; 1020 entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle;
1023 surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, 1021 surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
1024 texture.tic.w_source); 1022 texture.tic.w_source);
1025 } else { 1023 } else {
1026 // Can occur when texture addr is null or its memory is unmapped/invalid 1024 // Can occur when texture addr is null or its memory is unmapped/invalid
1027 unit.texture = 0; 1025 state.texture_units[current_bindpoint].texture = 0;
1028 } 1026 }
1029 } 1027 }
1030} 1028}
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index a70ff79d0..761b355e4 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -143,6 +143,8 @@ GLShader::ProgramResult CreateProgram(Maxwell::ShaderProgram program_type, Progr
143 // stage here. 143 // stage here.
144 setup.SetProgramB(std::move(program_code_b)); 144 setup.SetProgramB(std::move(program_code_b));
145 } 145 }
146 setup.program.unique_identifier =
147 GetUniqueIdentifier(program_type, program_code, program_code_b);
146 148
147 switch (program_type) { 149 switch (program_type) {
148 case Maxwell::ShaderProgram::VertexA: 150 case Maxwell::ShaderProgram::VertexA:
@@ -348,15 +350,12 @@ void ShaderCacheOpenGL::LoadDiskCache() {
348 return; 350 return;
349 } 351 }
350 352
351 std::vector<ShaderDiskCachePrecompiledEntry> precompiled = disk_cache.LoadPrecompiled(); 353 std::map<u64, ShaderDiskCacheDecompiled> decompiled;
352 const auto SearchPrecompiled = [&precompiled](const ShaderDiskCacheUsage& usage) { 354 std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump> dumps;
353 return std::find_if( 355 disk_cache.LoadPrecompiled(decompiled, dumps);
354 precompiled.begin(), precompiled.end(),
355 [&usage](const auto& precompiled_entry) { return precompiled_entry.usage == usage; });
356 };
357 356
358 const std::set<GLenum> supported_formats{GetSupportedFormats()}; 357 const std::set<GLenum> supported_formats{GetSupportedFormats()};
359 const auto unspecialized{GenerateUnspecializedShaders(raws)}; 358 const auto unspecialized{GenerateUnspecializedShaders(raws, decompiled)};
360 359
361 // Build shaders 360 // Build shaders
362 for (std::size_t i = 0; i < usages.size(); ++i) { 361 for (std::size_t i = 0; i < usages.size(); ++i) {
@@ -365,13 +364,17 @@ void ShaderCacheOpenGL::LoadDiskCache() {
365 i + 1, usages.size()); 364 i + 1, usages.size());
366 365
367 const auto& unspec{unspecialized.at(usage.unique_identifier)}; 366 const auto& unspec{unspecialized.at(usage.unique_identifier)};
368 367 const auto dump_it = dumps.find(usage);
369 const auto precompiled_it = SearchPrecompiled(usage);
370 const bool is_precompiled = precompiled_it != precompiled.end();
371 368
372 CachedProgram shader; 369 CachedProgram shader;
373 if (is_precompiled) { 370 if (dump_it != dumps.end()) {
374 shader = GeneratePrecompiledProgram(precompiled, *precompiled_it, supported_formats); 371 // If the shader is dumped, attempt to load it with
372 shader = GeneratePrecompiledProgram(dump_it->second, supported_formats);
373 if (!shader) {
374 // Invalidate the precompiled cache if a shader dumped shader was rejected
375 disk_cache.InvalidatePrecompiled();
376 dumps.clear();
377 }
375 } 378 }
376 if (!shader) { 379 if (!shader) {
377 shader = SpecializeShader(unspec.code, unspec.entries, unspec.program_type, 380 shader = SpecializeShader(unspec.code, unspec.entries, unspec.program_type,
@@ -385,52 +388,47 @@ void ShaderCacheOpenGL::LoadDiskCache() {
385 388
386 for (std::size_t i = 0; i < usages.size(); ++i) { 389 for (std::size_t i = 0; i < usages.size(); ++i) {
387 const auto& usage{usages[i]}; 390 const auto& usage{usages[i]};
388 if (SearchPrecompiled(usage) == precompiled.end()) { 391 if (dumps.find(usage) == dumps.end()) {
389 const auto& program = precompiled_programs.at(usage); 392 const auto& program = precompiled_programs.at(usage);
390 disk_cache.SavePrecompiled(usage, program->handle); 393 disk_cache.SaveDump(usage, program->handle);
391 } 394 }
392 } 395 }
393} 396}
394 397
395CachedProgram ShaderCacheOpenGL::GeneratePrecompiledProgram( 398CachedProgram ShaderCacheOpenGL::GeneratePrecompiledProgram(
396 std::vector<ShaderDiskCachePrecompiledEntry>& precompiled, 399 const ShaderDiskCacheDump& dump, const std::set<GLenum>& supported_formats) {
397 const ShaderDiskCachePrecompiledEntry& precompiled_entry,
398 const std::set<GLenum>& supported_formats) {
399 400
400 if (supported_formats.find(precompiled_entry.binary_format) == supported_formats.end()) { 401 if (supported_formats.find(dump.binary_format) == supported_formats.end()) {
401 LOG_INFO(Render_OpenGL, "Precompiled cache entry with unsupported format - removing"); 402 LOG_INFO(Render_OpenGL, "Precompiled cache entry with unsupported format - removing");
402 disk_cache.InvalidatePrecompiled();
403 precompiled.clear();
404 return {}; 403 return {};
405 } 404 }
406 405
407 CachedProgram shader = std::make_shared<OGLProgram>(); 406 CachedProgram shader = std::make_shared<OGLProgram>();
408 shader->handle = glCreateProgram(); 407 shader->handle = glCreateProgram();
409 glProgramBinary(shader->handle, precompiled_entry.binary_format, 408 glProgramBinary(shader->handle, dump.binary_format, dump.binary.data(),
410 precompiled_entry.binary.data(), 409 static_cast<GLsizei>(dump.binary.size()));
411 static_cast<GLsizei>(precompiled_entry.binary.size()));
412 410
413 GLint link_status{}; 411 GLint link_status{};
414 glGetProgramiv(shader->handle, GL_LINK_STATUS, &link_status); 412 glGetProgramiv(shader->handle, GL_LINK_STATUS, &link_status);
415 if (link_status == GL_FALSE) { 413 if (link_status == GL_FALSE) {
416 LOG_INFO(Render_OpenGL, "Precompiled cache rejected by the driver - removing"); 414 LOG_INFO(Render_OpenGL, "Precompiled cache rejected by the driver - removing");
417 disk_cache.InvalidatePrecompiled(); 415 return {};
418 precompiled.clear();
419
420 shader.reset();
421 } 416 }
422 417
423 return shader; 418 return shader;
424} 419}
425 420
426std::map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecializedShaders( 421std::map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecializedShaders(
427 const std::vector<ShaderDiskCacheRaw>& raws) { 422 const std::vector<ShaderDiskCacheRaw>& raws,
423 const std::map<u64, ShaderDiskCacheDecompiled>& decompiled) {
428 424
429 std::map<u64, UnspecializedShader> unspecialized; 425 std::map<u64, UnspecializedShader> unspecialized;
426
430 for (const auto& raw : raws) { 427 for (const auto& raw : raws) {
428 const u64 unique_identifier = raw.GetUniqueIdentifier();
431 const u64 calculated_hash = 429 const u64 calculated_hash =
432 GetUniqueIdentifier(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); 430 GetUniqueIdentifier(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB());
433 if (raw.GetUniqueIdentifier() != calculated_hash) { 431 if (unique_identifier != calculated_hash) {
434 LOG_ERROR( 432 LOG_ERROR(
435 Render_OpenGL, 433 Render_OpenGL,
436 "Invalid hash in entry={:016x} (obtained hash={:016x}) - removing shader cache", 434 "Invalid hash in entry={:016x} (obtained hash={:016x}) - removing shader cache",
@@ -439,10 +437,19 @@ std::map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecializedShade
439 return {}; 437 return {};
440 } 438 }
441 439
442 auto result = 440 GLShader::ProgramResult result;
443 CreateProgram(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB()); 441 if (const auto it = decompiled.find(unique_identifier); it != decompiled.end()) {
442 // If it's stored in the precompiled file, avoid decompiling it here
443 const auto& stored_decompiled{it->second};
444 result = {stored_decompiled.code, stored_decompiled.entries};
445 } else {
446 // Otherwise decompile the shader at boot and save the result to the decompiled file
447 result =
448 CreateProgram(raw.GetProgramType(), raw.GetProgramCode(), raw.GetProgramCodeB());
449 disk_cache.SaveDecompiled(unique_identifier, result.first, result.second);
450 }
444 451
445 precompiled_shaders.insert({raw.GetUniqueIdentifier(), result}); 452 precompiled_shaders.insert({unique_identifier, result});
446 453
447 unspecialized.insert( 454 unspecialized.insert(
448 {raw.GetUniqueIdentifier(), 455 {raw.GetUniqueIdentifier(),
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 763a47bce..3b5a82f8a 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -117,12 +117,11 @@ public:
117 117
118private: 118private:
119 std::map<u64, UnspecializedShader> GenerateUnspecializedShaders( 119 std::map<u64, UnspecializedShader> GenerateUnspecializedShaders(
120 const std::vector<ShaderDiskCacheRaw>& raws); 120 const std::vector<ShaderDiskCacheRaw>& raws,
121 const std::map<u64, ShaderDiskCacheDecompiled>& decompiled);
121 122
122 CachedProgram GeneratePrecompiledProgram( 123 CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump,
123 std::vector<ShaderDiskCachePrecompiledEntry>& precompiled, 124 const std::set<GLenum>& supported_formats);
124 const ShaderDiskCachePrecompiledEntry& precompiled_entry,
125 const std::set<GLenum>& supported_formats);
126 125
127 std::array<Shader, Maxwell::MaxShaderProgram> last_shaders; 126 std::array<Shader, Maxwell::MaxShaderProgram> last_shaders;
128 127
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 9184a1287..d84caa6db 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -193,13 +193,14 @@ public:
193 ShaderEntries GetShaderEntries() const { 193 ShaderEntries GetShaderEntries() const {
194 ShaderEntries entries; 194 ShaderEntries entries;
195 for (const auto& cbuf : ir.GetConstantBuffers()) { 195 for (const auto& cbuf : ir.GetConstantBuffers()) {
196 entries.const_buffers.emplace_back(cbuf.second, stage, cbuf.first); 196 entries.const_buffers.emplace_back(cbuf.second.GetMaxOffset(), cbuf.second.IsIndirect(),
197 cbuf.first);
197 } 198 }
198 for (const auto& sampler : ir.GetSamplers()) { 199 for (const auto& sampler : ir.GetSamplers()) {
199 entries.samplers.emplace_back(sampler, stage); 200 entries.samplers.emplace_back(sampler);
200 } 201 }
201 for (const auto& gmem : ir.GetGlobalMemoryBases()) { 202 for (const auto& gmem : ir.GetGlobalMemoryBases()) {
202 entries.global_memory_entries.emplace_back(gmem.cbuf_index, gmem.cbuf_offset, stage); 203 entries.global_memory_entries.emplace_back(gmem.cbuf_index, gmem.cbuf_offset);
203 } 204 }
204 entries.clip_distances = ir.GetClipDistances(); 205 entries.clip_distances = ir.GetClipDistances();
205 entries.shader_length = ir.GetLength(); 206 entries.shader_length = ir.GetLength();
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index 398be13d6..0031cb614 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -23,65 +23,23 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
23 23
24class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer { 24class ConstBufferEntry : public VideoCommon::Shader::ConstBuffer {
25public: 25public:
26 explicit ConstBufferEntry(const VideoCommon::Shader::ConstBuffer& entry, 26 explicit ConstBufferEntry(u32 max_offset, bool is_indirect, u32 index)
27 Maxwell::ShaderStage stage, u32 index) 27 : VideoCommon::Shader::ConstBuffer{max_offset, is_indirect}, index{index} {}
28 : VideoCommon::Shader::ConstBuffer{entry}, stage{stage}, index{index} {}
29
30 Maxwell::ShaderStage GetStage() const {
31 return stage;
32 }
33 28
34 u32 GetIndex() const { 29 u32 GetIndex() const {
35 return index; 30 return index;
36 } 31 }
37 32
38private: 33private:
39 Maxwell::ShaderStage stage{};
40 u32 index{}; 34 u32 index{};
41}; 35};
42 36
43class SamplerEntry : public VideoCommon::Shader::Sampler { 37using SamplerEntry = VideoCommon::Shader::Sampler;
44public:
45 explicit SamplerEntry(const VideoCommon::Shader::Sampler& entry, Maxwell::ShaderStage stage)
46 : VideoCommon::Shader::Sampler{entry}, stage{stage} {}
47
48 Maxwell::ShaderStage GetStage() const {
49 return stage;
50 }
51
52private:
53 Maxwell::ShaderStage stage{};
54};
55
56class GlobalMemoryEntry {
57public:
58 explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset, Maxwell::ShaderStage stage)
59 : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, stage{stage} {}
60
61 u32 GetCbufIndex() const {
62 return cbuf_index;
63 }
64
65 u32 GetCbufOffset() const {
66 return cbuf_offset;
67 }
68
69 Maxwell::ShaderStage GetStage() const {
70 return stage;
71 }
72
73private:
74 u32 cbuf_index{};
75 u32 cbuf_offset{};
76 Maxwell::ShaderStage stage{};
77 std::string name;
78};
79 38
80class GlobalMemoryEntry { 39class GlobalMemoryEntry {
81public: 40public:
82 explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset, Maxwell::ShaderStage stage, 41 explicit GlobalMemoryEntry(u32 cbuf_index, u32 cbuf_offset)
83 std::string name) 42 : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset} {}
84 : cbuf_index{cbuf_index}, cbuf_offset{cbuf_offset}, stage{stage}, name{std::move(name)} {}
85 43
86 u32 GetCbufIndex() const { 44 u32 GetCbufIndex() const {
87 return cbuf_index; 45 return cbuf_index;
@@ -91,22 +49,9 @@ public:
91 return cbuf_offset; 49 return cbuf_offset;
92 } 50 }
93 51
94 const std::string& GetName() const {
95 return name;
96 }
97
98 Maxwell::ShaderStage GetStage() const {
99 return stage;
100 }
101
102 u32 GetHash() const {
103 return (static_cast<u32>(stage) << 24) | (cbuf_index << 16) | cbuf_offset;
104 }
105
106private: 52private:
107 u32 cbuf_index{}; 53 u32 cbuf_index{};
108 u32 cbuf_offset{}; 54 u32 cbuf_offset{};
109 Maxwell::ShaderStage stage{};
110}; 55};
111 56
112struct ShaderEntries { 57struct ShaderEntries {
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 6a23b8fe2..7628a74c2 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -24,11 +24,16 @@
24 24
25namespace OpenGL { 25namespace OpenGL {
26 26
27enum class EntryKind : u32 { 27enum class TransferableEntryKind : u32 {
28 Raw, 28 Raw,
29 Usage, 29 Usage,
30}; 30};
31 31
32enum class PrecompiledEntryKind : u32 {
33 Decompiled,
34 Dump,
35};
36
32constexpr u32 NativeVersion = 1; 37constexpr u32 NativeVersion = 1;
33constexpr u32 ShaderHashSize = 64; 38constexpr u32 ShaderHashSize = 64;
34 39
@@ -108,17 +113,17 @@ bool ShaderDiskCacheOpenGL::LoadTransferable(std::vector<ShaderDiskCacheRaw>& ra
108 113
109 // Version is valid, load the shaders 114 // Version is valid, load the shaders
110 while (file.Tell() < file_size) { 115 while (file.Tell() < file_size) {
111 EntryKind kind{}; 116 TransferableEntryKind kind{};
112 file.ReadBytes(&kind, sizeof(u32)); 117 file.ReadBytes(&kind, sizeof(u32));
113 118
114 switch (kind) { 119 switch (kind) {
115 case EntryKind::Raw: { 120 case TransferableEntryKind::Raw: {
116 ShaderDiskCacheRaw entry{file}; 121 ShaderDiskCacheRaw entry{file};
117 transferable.insert({entry.GetUniqueIdentifier(), {}}); 122 transferable.insert({entry.GetUniqueIdentifier(), {}});
118 raws.push_back(std::move(entry)); 123 raws.push_back(std::move(entry));
119 break; 124 break;
120 } 125 }
121 case EntryKind::Usage: { 126 case TransferableEntryKind::Usage: {
122 ShaderDiskCacheUsage usage{}; 127 ShaderDiskCacheUsage usage{};
123 file.ReadBytes(&usage, sizeof(usage)); 128 file.ReadBytes(&usage, sizeof(usage));
124 usages.push_back(std::move(usage)); 129 usages.push_back(std::move(usage));
@@ -133,16 +138,19 @@ bool ShaderDiskCacheOpenGL::LoadTransferable(std::vector<ShaderDiskCacheRaw>& ra
133 return true; 138 return true;
134} 139}
135 140
136std::vector<ShaderDiskCachePrecompiledEntry> ShaderDiskCacheOpenGL::LoadPrecompiled() { 141bool ShaderDiskCacheOpenGL::LoadPrecompiled(
142 std::map<u64, ShaderDiskCacheDecompiled>& decompiled,
143 std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>& dumps) {
144
137 if (!Settings::values.use_disk_shader_cache) { 145 if (!Settings::values.use_disk_shader_cache) {
138 return {}; 146 return false;
139 } 147 }
140 148
141 FileUtil::IOFile file(GetPrecompiledPath(), "rb"); 149 FileUtil::IOFile file(GetPrecompiledPath(), "rb");
142 if (!file.IsOpen()) { 150 if (!file.IsOpen()) {
143 LOG_INFO(Render_OpenGL, "No precompiled shader cache found for game with title id={}", 151 LOG_INFO(Render_OpenGL, "No precompiled shader cache found for game with title id={}",
144 GetTitleID()); 152 GetTitleID());
145 return {}; 153 return false;
146 } 154 }
147 const u64 file_size = file.GetSize(); 155 const u64 file_size = file.GetSize();
148 156
@@ -152,24 +160,102 @@ std::vector<ShaderDiskCachePrecompiledEntry> ShaderDiskCacheOpenGL::LoadPrecompi
152 LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of yuzu - removing"); 160 LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of yuzu - removing");
153 file.Close(); 161 file.Close();
154 InvalidatePrecompiled(); 162 InvalidatePrecompiled();
155 return {}; 163 return false;
156 } 164 }
157 165
158 std::vector<ShaderDiskCachePrecompiledEntry> precompiled;
159 while (file.Tell() < file_size) { 166 while (file.Tell() < file_size) {
160 ShaderDiskCachePrecompiledEntry entry; 167 PrecompiledEntryKind kind{};
161 file.ReadBytes(&entry.usage, sizeof(entry.usage)); 168 file.ReadBytes(&kind, sizeof(u32));
162 169
163 file.ReadBytes(&entry.binary_format, sizeof(u32)); 170 switch (kind) {
171 case PrecompiledEntryKind::Decompiled: {
172 ShaderDiskCacheDecompiled entry;
173
174 u64 unique_identifier{};
175 file.ReadBytes(&unique_identifier, sizeof(u64));
176
177 u32 code_size{};
178 file.ReadBytes(&code_size, sizeof(u32));
179 std::vector<u8> code(code_size);
180 file.ReadArray(code.data(), code.size());
181 entry.code = std::string(reinterpret_cast<char*>(code.data()), code_size);
182
183 u32 const_buffers_count{};
184 file.ReadBytes(&const_buffers_count, sizeof(u32));
185 for (u32 i = 0; i < const_buffers_count; ++i) {
186 u32 max_offset{}, index{};
187 u8 is_indirect{};
188 file.ReadBytes(&max_offset, sizeof(u32));
189 file.ReadBytes(&index, sizeof(u32));
190 file.ReadBytes(&is_indirect, sizeof(u8));
191
192 entry.entries.const_buffers.emplace_back(max_offset, is_indirect != 0, index);
193 }
194
195 u32 samplers_count{};
196 file.ReadBytes(&samplers_count, sizeof(u32));
197 for (u32 i = 0; i < samplers_count; ++i) {
198 u64 offset{}, index{};
199 u32 type{};
200 u8 is_array{}, is_shadow{};
201 file.ReadBytes(&offset, sizeof(u64));
202 file.ReadBytes(&index, sizeof(u64));
203 file.ReadBytes(&type, sizeof(u32));
204 file.ReadBytes(&is_array, sizeof(u8));
205 file.ReadBytes(&is_shadow, sizeof(u8));
206
207 entry.entries.samplers.emplace_back(
208 static_cast<std::size_t>(offset), static_cast<std::size_t>(index),
209 static_cast<Tegra::Shader::TextureType>(type), is_array != 0, is_shadow != 0);
210 }
211
212 u32 global_memory_count{};
213 file.ReadBytes(&global_memory_count, sizeof(u32));
214 for (u32 i = 0; i < global_memory_count; ++i) {
215 u32 cbuf_index{}, cbuf_offset{};
216 file.ReadBytes(&cbuf_index, sizeof(u32));
217 file.ReadBytes(&cbuf_offset, sizeof(u32));
218 entry.entries.global_memory_entries.emplace_back(cbuf_index, cbuf_offset);
219 }
220
221 for (auto& clip_distance : entry.entries.clip_distances) {
222 u8 clip_distance_raw{};
223 file.ReadBytes(&clip_distance_raw, sizeof(u8));
224 clip_distance = clip_distance_raw != 0;
225 }
226
227 u64 shader_length{};
228 file.ReadBytes(&shader_length, sizeof(u64));
229 entry.entries.shader_length = static_cast<std::size_t>(shader_length);
230
231 decompiled.insert({unique_identifier, std::move(entry)});
232 break;
233 }
234 case PrecompiledEntryKind::Dump: {
235 ShaderDiskCacheUsage usage;
236 file.ReadBytes(&usage, sizeof(usage));
237
238 ShaderDiskCacheDump dump;
239 file.ReadBytes(&dump.binary_format, sizeof(u32));
164 240
165 u32 binary_length{}; 241 u32 binary_length{};
166 file.ReadBytes(&binary_length, sizeof(u32)); 242 file.ReadBytes(&binary_length, sizeof(u32));
167 entry.binary.resize(binary_length); 243 dump.binary.resize(binary_length);
168 file.ReadBytes(entry.binary.data(), entry.binary.size()); 244 file.ReadBytes(dump.binary.data(), dump.binary.size());
169 245
170 precompiled.push_back(entry); 246 dumps.insert({usage, dump});
247 break;
248 }
249 default:
250 LOG_ERROR(Render_OpenGL, "Unknown precompiled shader cache entry kind={} - removing",
251 static_cast<u32>(kind));
252 InvalidatePrecompiled();
253 dumps.clear();
254 decompiled.clear();
255 return false;
256 }
171 } 257 }
172 return precompiled; 258 return true;
173} 259}
174 260
175void ShaderDiskCacheOpenGL::InvalidateTransferable() const { 261void ShaderDiskCacheOpenGL::InvalidateTransferable() const {
@@ -196,7 +282,7 @@ void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) {
196 if (!file.IsOpen()) { 282 if (!file.IsOpen()) {
197 return; 283 return;
198 } 284 }
199 file.WriteObject(EntryKind::Raw); 285 file.WriteObject(TransferableEntryKind::Raw);
200 entry.Save(file); 286 entry.Save(file);
201 287
202 transferable.insert({id, {}}); 288 transferable.insert({id, {}});
@@ -220,11 +306,58 @@ void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) {
220 if (!file.IsOpen()) { 306 if (!file.IsOpen()) {
221 return; 307 return;
222 } 308 }
223 file.WriteObject(EntryKind::Usage); 309 file.WriteObject(TransferableEntryKind::Usage);
224 file.WriteObject(usage); 310 file.WriteObject(usage);
225} 311}
226 312
227void ShaderDiskCacheOpenGL::SavePrecompiled(const ShaderDiskCacheUsage& usage, GLuint program) { 313void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::string& code,
314 const GLShader::ShaderEntries& entries) {
315 if (!Settings::values.use_disk_shader_cache) {
316 return;
317 }
318
319 FileUtil::IOFile file = AppendPrecompiledFile();
320 if (!file.IsOpen()) {
321 return;
322 }
323
324 file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Decompiled));
325
326 file.WriteObject(unique_identifier);
327
328 file.WriteObject(static_cast<u32>(code.size()));
329 file.WriteArray(code.data(), code.size());
330
331 file.WriteObject(static_cast<u32>(entries.const_buffers.size()));
332 for (const auto& cbuf : entries.const_buffers) {
333 file.WriteObject(static_cast<u32>(cbuf.GetMaxOffset()));
334 file.WriteObject(static_cast<u32>(cbuf.GetIndex()));
335 file.WriteObject(static_cast<u8>(cbuf.IsIndirect() ? 1 : 0));
336 }
337
338 file.WriteObject(static_cast<u32>(entries.samplers.size()));
339 for (const auto& sampler : entries.samplers) {
340 file.WriteObject(static_cast<u64>(sampler.GetOffset()));
341 file.WriteObject(static_cast<u64>(sampler.GetIndex()));
342 file.WriteObject(static_cast<u32>(sampler.GetType()));
343 file.WriteObject(static_cast<u8>(sampler.IsArray() ? 1 : 0));
344 file.WriteObject(static_cast<u8>(sampler.IsShadow() ? 1 : 0));
345 }
346
347 file.WriteObject(static_cast<u32>(entries.global_memory_entries.size()));
348 for (const auto& gmem : entries.global_memory_entries) {
349 file.WriteObject(static_cast<u32>(gmem.GetCbufIndex()));
350 file.WriteObject(static_cast<u32>(gmem.GetCbufOffset()));
351 }
352
353 for (const bool clip_distance : entries.clip_distances) {
354 file.WriteObject(static_cast<u8>(clip_distance ? 1 : 0));
355 }
356
357 file.WriteObject(static_cast<u64>(entries.shader_length));
358}
359
360void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint program) {
228 if (!Settings::values.use_disk_shader_cache) { 361 if (!Settings::values.use_disk_shader_cache) {
229 return; 362 return;
230 } 363 }
@@ -234,6 +367,8 @@ void ShaderDiskCacheOpenGL::SavePrecompiled(const ShaderDiskCacheUsage& usage, G
234 return; 367 return;
235 } 368 }
236 369
370 file.WriteObject(static_cast<u32>(PrecompiledEntryKind::Dump));
371
237 file.WriteObject(usage); 372 file.WriteObject(usage);
238 373
239 GLint binary_length{}; 374 GLint binary_length{};
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 6c4c7bd5c..f11693789 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
@@ -130,14 +130,16 @@ public:
130 } 130 }
131}; 131};
132 132
133struct ShaderDiskCachePrecompiledEntry { 133struct ShaderDiskCacheDecompiled {
134 ShaderDiskCacheUsage usage;
135 GLenum binary_format;
136 std::vector<u8> binary;
137 std::string code; 134 std::string code;
138 GLShader::ShaderEntries entries; 135 GLShader::ShaderEntries entries;
139}; 136};
140 137
138struct ShaderDiskCacheDump {
139 GLenum binary_format;
140 std::vector<u8> binary;
141};
142
141class ShaderDiskCacheOpenGL { 143class ShaderDiskCacheOpenGL {
142public: 144public:
143 /// Loads transferable cache. If file has a old version, it deletes it. Returns true on success. 145 /// Loads transferable cache. If file has a old version, it deletes it. Returns true on success.
@@ -145,7 +147,8 @@ public:
145 std::vector<ShaderDiskCacheUsage>& usages); 147 std::vector<ShaderDiskCacheUsage>& usages);
146 148
147 /// Loads current game's precompiled cache. Invalidates if emulator's version has changed. 149 /// Loads current game's precompiled cache. Invalidates if emulator's version has changed.
148 std::vector<ShaderDiskCachePrecompiledEntry> LoadPrecompiled(); 150 bool LoadPrecompiled(std::map<u64, ShaderDiskCacheDecompiled>& decompiled,
151 std::map<ShaderDiskCacheUsage, ShaderDiskCacheDump>& dumps);
149 152
150 /// Removes the transferable (and precompiled) cache file. 153 /// Removes the transferable (and precompiled) cache file.
151 void InvalidateTransferable() const; 154 void InvalidateTransferable() const;
@@ -159,8 +162,12 @@ public:
159 /// Saves shader usage to the transferable file. Does not check for collisions. 162 /// Saves shader usage to the transferable file. Does not check for collisions.
160 void SaveUsage(const ShaderDiskCacheUsage& usage); 163 void SaveUsage(const ShaderDiskCacheUsage& usage);
161 164
162 /// Saves a precompiled shader entry. Does not check for collisions. 165 /// Saves a decompiled entry to the precompiled file. Does not check for collisions.
163 void SavePrecompiled(const ShaderDiskCacheUsage& usage, GLuint program); 166 void SaveDecompiled(u64 unique_identifier, const std::string& code,
167 const GLShader::ShaderEntries& entries);
168
169 /// Saves a dump entry to the precompiled file. Does not check for collisions.
170 void SaveDump(const ShaderDiskCacheUsage& usage, GLuint program);
164 171
165private: 172private:
166 /// Opens current game's transferable file and write it's header if it doesn't exist 173 /// Opens current game's transferable file and write it's header if it doesn't exist
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index ac5e6917b..fd3105de3 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -26,8 +26,6 @@ struct ShaderSetup {
26 ProgramCode code; 26 ProgramCode code;
27 ProgramCode code_b; // Used for dual vertex shaders 27 ProgramCode code_b; // Used for dual vertex shaders
28 u64 unique_identifier; 28 u64 unique_identifier;
29 std::size_t real_size;
30 std::size_t real_size_b;
31 } program; 29 } program;
32 30
33 /// Used in scenarios where we have a dual vertex shaders 31 /// Used in scenarios where we have a dual vertex shaders
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 6e42e3dfb..ef0f3a106 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -236,6 +236,11 @@ private:
236 236
237class ConstBuffer { 237class ConstBuffer {
238public: 238public:
239 explicit ConstBuffer(u32 max_offset, bool is_indirect)
240 : max_offset{max_offset}, is_indirect{is_indirect} {}
241
242 ConstBuffer() = default;
243
239 void MarkAsUsed(u64 offset) { 244 void MarkAsUsed(u64 offset) {
240 max_offset = std::max(max_offset, static_cast<u32>(offset)); 245 max_offset = std::max(max_offset, static_cast<u32>(offset));
241 } 246 }
@@ -252,6 +257,10 @@ public:
252 return max_offset + sizeof(float); 257 return max_offset + sizeof(float);
253 } 258 }
254 259
260 u32 GetMaxOffset() const {
261 return max_offset;
262 }
263
255private: 264private:
256 u32 max_offset{}; 265 u32 max_offset{};
257 bool is_indirect{}; 266 bool is_indirect{};