diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 113 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.h | 10 |
3 files changed, 116 insertions, 11 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 72a6dfd2a..eec01e8c2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -140,7 +140,9 @@ void RasterizerOpenGL::SyncVertexInstances() { | |||
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 142 | void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 143 | const VideoCore::DiskResourceLoadCallback& callback) {} | 143 | const VideoCore::DiskResourceLoadCallback& callback) { |
| 144 | shader_cache.LoadDiskResources(title_id, stop_loading, callback); | ||
| 145 | } | ||
| 144 | 146 | ||
| 145 | void RasterizerOpenGL::Clear() { | 147 | void RasterizerOpenGL::Clear() { |
| 146 | MICROPROFILE_SCOPE(OpenGL_Clears); | 148 | MICROPROFILE_SCOPE(OpenGL_Clears); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 33757938a..3aa5ac31d 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -3,17 +3,19 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <atomic> | 5 | #include <atomic> |
| 6 | #include <fstream> | ||
| 6 | #include <functional> | 7 | #include <functional> |
| 7 | #include <mutex> | 8 | #include <mutex> |
| 8 | #include <optional> | ||
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <thread> | 10 | #include <thread> |
| 11 | #include <unordered_set> | ||
| 12 | 11 | ||
| 13 | #include "common/alignment.h" | 12 | #include "common/alignment.h" |
| 14 | #include "common/assert.h" | 13 | #include "common/assert.h" |
| 14 | #include "common/fs/fs.h" | ||
| 15 | #include "common/fs/path_util.h" | ||
| 15 | #include "common/logging/log.h" | 16 | #include "common/logging/log.h" |
| 16 | #include "common/scope_exit.h" | 17 | #include "common/scope_exit.h" |
| 18 | #include "common/thread_worker.h" | ||
| 17 | #include "core/core.h" | 19 | #include "core/core.h" |
| 18 | #include "core/frontend/emu_window.h" | 20 | #include "core/frontend/emu_window.h" |
| 19 | #include "shader_recompiler/backend/glasm/emit_glasm.h" | 21 | #include "shader_recompiler/backend/glasm/emit_glasm.h" |
| @@ -40,6 +42,8 @@ using Shader::Backend::GLASM::EmitGLASM; | |||
| 40 | using Shader::Backend::SPIRV::EmitSPIRV; | 42 | using Shader::Backend::SPIRV::EmitSPIRV; |
| 41 | using Shader::Maxwell::TranslateProgram; | 43 | using Shader::Maxwell::TranslateProgram; |
| 42 | using VideoCommon::ComputeEnvironment; | 44 | using VideoCommon::ComputeEnvironment; |
| 45 | using VideoCommon::FileEnvironment; | ||
| 46 | using VideoCommon::GenericEnvironment; | ||
| 43 | using VideoCommon::GraphicsEnvironment; | 47 | using VideoCommon::GraphicsEnvironment; |
| 44 | 48 | ||
| 45 | template <typename Container> | 49 | template <typename Container> |
| @@ -154,8 +158,6 @@ GLenum AssemblyStage(size_t stage_index) { | |||
| 154 | 158 | ||
| 155 | Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, | 159 | Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, |
| 156 | const Shader::IR::Program& program) { | 160 | const Shader::IR::Program& program) { |
| 157 | UNIMPLEMENTED_IF_MSG(key.xfb_enabled != 0, "Transform feedbacks"); | ||
| 158 | |||
| 159 | Shader::RuntimeInfo info; | 161 | Shader::RuntimeInfo info; |
| 160 | switch (program.stage) { | 162 | switch (program.stage) { |
| 161 | case Shader::Stage::TessellationEval: | 163 | case Shader::Stage::TessellationEval: |
| @@ -282,6 +284,89 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 282 | 284 | ||
| 283 | ShaderCache::~ShaderCache() = default; | 285 | ShaderCache::~ShaderCache() = default; |
| 284 | 286 | ||
| 287 | void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||
| 288 | const VideoCore::DiskResourceLoadCallback& callback) { | ||
| 289 | if (title_id == 0) { | ||
| 290 | return; | ||
| 291 | } | ||
| 292 | auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir)}; | ||
| 293 | auto base_dir{shader_dir / "new_opengl"}; | ||
| 294 | auto transferable_dir{base_dir / "transferable"}; | ||
| 295 | auto precompiled_dir{base_dir / "precompiled"}; | ||
| 296 | if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir) || | ||
| 297 | !Common::FS::CreateDir(transferable_dir) || !Common::FS::CreateDir(precompiled_dir)) { | ||
| 298 | LOG_ERROR(Common_Filesystem, "Failed to create pipeline cache directories"); | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | shader_cache_filename = transferable_dir / fmt::format("{:016x}.bin", title_id); | ||
| 302 | |||
| 303 | struct Context { | ||
| 304 | explicit Context(Core::Frontend::EmuWindow& emu_window) | ||
| 305 | : gl_context{emu_window.CreateSharedContext()}, scoped{*gl_context} {} | ||
| 306 | |||
| 307 | std::unique_ptr<Core::Frontend::GraphicsContext> gl_context; | ||
| 308 | Core::Frontend::GraphicsContext::Scoped scoped; | ||
| 309 | ShaderPools pools; | ||
| 310 | }; | ||
| 311 | Common::StatefulThreadWorker<Context> workers( | ||
| 312 | std::max(std::thread::hardware_concurrency(), 2U) - 1, "yuzu:ShaderBuilder", | ||
| 313 | [this] { return Context{emu_window}; }); | ||
| 314 | |||
| 315 | struct { | ||
| 316 | std::mutex mutex; | ||
| 317 | size_t total{0}; | ||
| 318 | size_t built{0}; | ||
| 319 | bool has_loaded{false}; | ||
| 320 | } state; | ||
| 321 | |||
| 322 | const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { | ||
| 323 | ComputePipelineKey key; | ||
| 324 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | ||
| 325 | workers.QueueWork( | ||
| 326 | [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { | ||
| 327 | ctx->pools.ReleaseContents(); | ||
| 328 | auto pipeline{CreateComputePipeline(ctx->pools, key, env, false)}; | ||
| 329 | |||
| 330 | std::lock_guard lock{state.mutex}; | ||
| 331 | compute_cache.emplace(key, std::move(pipeline)); | ||
| 332 | ++state.built; | ||
| 333 | if (state.has_loaded) { | ||
| 334 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | ||
| 335 | } | ||
| 336 | }); | ||
| 337 | ++state.total; | ||
| 338 | }}; | ||
| 339 | const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) { | ||
| 340 | GraphicsPipelineKey key; | ||
| 341 | file.read(reinterpret_cast<char*>(&key), sizeof(key)); | ||
| 342 | workers.QueueWork( | ||
| 343 | [this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { | ||
| 344 | boost::container::static_vector<Shader::Environment*, 5> env_ptrs; | ||
| 345 | for (auto& env : envs) { | ||
| 346 | env_ptrs.push_back(&env); | ||
| 347 | } | ||
| 348 | ctx->pools.ReleaseContents(); | ||
| 349 | auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; | ||
| 350 | |||
| 351 | std::lock_guard lock{state.mutex}; | ||
| 352 | graphics_cache.emplace(key, std::move(pipeline)); | ||
| 353 | ++state.built; | ||
| 354 | if (state.has_loaded) { | ||
| 355 | callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | ||
| 356 | } | ||
| 357 | }); | ||
| 358 | ++state.total; | ||
| 359 | }}; | ||
| 360 | VideoCommon::LoadPipelines(stop_loading, shader_cache_filename, load_compute, load_graphics); | ||
| 361 | |||
| 362 | std::unique_lock lock{state.mutex}; | ||
| 363 | callback(VideoCore::LoadCallbackStage::Build, 0, state.total); | ||
| 364 | state.has_loaded = true; | ||
| 365 | lock.unlock(); | ||
| 366 | |||
| 367 | workers.WaitForRequests(); | ||
| 368 | } | ||
| 369 | |||
| 285 | GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { | 370 | GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { |
| 286 | if (!RefreshStages(graphics_key.unique_hashes)) { | 371 | if (!RefreshStages(graphics_key.unique_hashes)) { |
| 287 | return nullptr; | 372 | return nullptr; |
| @@ -332,7 +417,18 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline() { | |||
| 332 | GetGraphicsEnvironments(environments, graphics_key.unique_hashes); | 417 | GetGraphicsEnvironments(environments, graphics_key.unique_hashes); |
| 333 | 418 | ||
| 334 | main_pools.ReleaseContents(); | 419 | main_pools.ReleaseContents(); |
| 335 | return CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), true); | 420 | auto pipeline{CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), true)}; |
| 421 | if (shader_cache_filename.empty()) { | ||
| 422 | return pipeline; | ||
| 423 | } | ||
| 424 | boost::container::static_vector<const GenericEnvironment*, Maxwell::MaxShaderProgram> env_ptrs; | ||
| 425 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | ||
| 426 | if (graphics_key.unique_hashes[index] != 0) { | ||
| 427 | env_ptrs.push_back(&environments.envs[index]); | ||
| 428 | } | ||
| 429 | } | ||
| 430 | VideoCommon::SerializePipeline(graphics_key, env_ptrs, shader_cache_filename); | ||
| 431 | return pipeline; | ||
| 336 | } | 432 | } |
| 337 | 433 | ||
| 338 | std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( | 434 | std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( |
| @@ -396,7 +492,12 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline( | |||
| 396 | env.SetCachedSize(shader->size_bytes); | 492 | env.SetCachedSize(shader->size_bytes); |
| 397 | 493 | ||
| 398 | main_pools.ReleaseContents(); | 494 | main_pools.ReleaseContents(); |
| 399 | return CreateComputePipeline(main_pools, key, env, true); | 495 | auto pipeline{CreateComputePipeline(main_pools, key, env, true)}; |
| 496 | if (!shader_cache_filename.empty()) { | ||
| 497 | VideoCommon::SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env}, | ||
| 498 | shader_cache_filename); | ||
| 499 | } | ||
| 500 | return pipeline; | ||
| 400 | } | 501 | } |
| 401 | 502 | ||
| 402 | std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(ShaderPools& pools, | 503 | std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(ShaderPools& pools, |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index a56559ea9..16175318b 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <filesystem> | ||
| 9 | #include <stop_token> | ||
| 8 | #include <unordered_map> | 10 | #include <unordered_map> |
| 9 | 11 | ||
| 10 | #include <glad/glad.h> | 12 | #include <glad/glad.h> |
| @@ -23,10 +25,6 @@ namespace Tegra { | |||
| 23 | class MemoryManager; | 25 | class MemoryManager; |
| 24 | } | 26 | } |
| 25 | 27 | ||
| 26 | namespace Core::Frontend { | ||
| 27 | class EmuWindow; | ||
| 28 | } | ||
| 29 | |||
| 30 | namespace OpenGL { | 28 | namespace OpenGL { |
| 31 | 29 | ||
| 32 | class Device; | 30 | class Device; |
| @@ -55,6 +53,9 @@ public: | |||
| 55 | ProgramManager& program_manager_, StateTracker& state_tracker_); | 53 | ProgramManager& program_manager_, StateTracker& state_tracker_); |
| 56 | ~ShaderCache(); | 54 | ~ShaderCache(); |
| 57 | 55 | ||
| 56 | void LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||
| 57 | const VideoCore::DiskResourceLoadCallback& callback); | ||
| 58 | |||
| 58 | [[nodiscard]] GraphicsPipeline* CurrentGraphicsPipeline(); | 59 | [[nodiscard]] GraphicsPipeline* CurrentGraphicsPipeline(); |
| 59 | 60 | ||
| 60 | [[nodiscard]] ComputePipeline* CurrentComputePipeline(); | 61 | [[nodiscard]] ComputePipeline* CurrentComputePipeline(); |
| @@ -88,6 +89,7 @@ private: | |||
| 88 | std::unordered_map<ComputePipelineKey, std::unique_ptr<ComputePipeline>> compute_cache; | 89 | std::unordered_map<ComputePipelineKey, std::unique_ptr<ComputePipeline>> compute_cache; |
| 89 | 90 | ||
| 90 | Shader::Profile profile; | 91 | Shader::Profile profile; |
| 92 | std::filesystem::path shader_cache_filename; | ||
| 91 | }; | 93 | }; |
| 92 | 94 | ||
| 93 | } // namespace OpenGL | 95 | } // namespace OpenGL |