From dcad3ec892f02a703eb732c5679125291e7f0033 Mon Sep 17 00:00:00 2001 From: Silent Date: Sun, 10 Nov 2019 21:52:52 +0100 Subject: [PATCH 1/2] Allow to interrupt shader precompilation by stopping emulation --- .../Core/VideoCommon/AsyncShaderCompiler.cpp | 20 +++++++++---------- Source/Core/VideoCommon/AsyncShaderCompiler.h | 6 ++---- Source/Core/VideoCommon/ShaderCache.cpp | 7 +++++-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp index 7e13168f69..7e6f960d7f 100644 --- a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp +++ b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp @@ -9,6 +9,8 @@ #include "Common/Logging/Log.h" #include "Common/Thread.h" +#include "Core/Core.h" + namespace VideoCommon { AsyncShaderCompiler::AsyncShaderCompiler() @@ -65,17 +67,11 @@ bool AsyncShaderCompiler::HasCompletedWork() return !m_completed_work.empty(); } -void AsyncShaderCompiler::WaitUntilCompletion() -{ - while (HasPendingWork()) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); -} - -void AsyncShaderCompiler::WaitUntilCompletion( +bool AsyncShaderCompiler::WaitUntilCompletion( const std::function& progress_callback) { if (!HasPendingWork()) - return; + return true; // Wait a second before opening a progress dialog. // This way, if the operation completes quickly, we don't annoy the user. @@ -85,11 +81,11 @@ void AsyncShaderCompiler::WaitUntilCompletion( { std::this_thread::sleep_for(std::chrono::milliseconds(CHECK_INTERVAL)); if (!HasPendingWork()) - return; + return true; } // Grab the number of pending items. We use this to work out how many are left. - size_t total_items = 0; + size_t total_items; { // Safe to hold both locks here, since nowhere else does. std::lock_guard pending_guard(m_pending_work_lock); @@ -100,6 +96,9 @@ void AsyncShaderCompiler::WaitUntilCompletion( // Update progress while the compiles complete. for (;;) { + if (Core::GetState() == Core::State::Stopping) + return false; + size_t remaining_items; { std::lock_guard pending_guard(m_pending_work_lock); @@ -111,6 +110,7 @@ void AsyncShaderCompiler::WaitUntilCompletion( progress_callback(total_items - remaining_items, total_items); std::this_thread::sleep_for(CHECK_INTERVAL); } + return true; } bool AsyncShaderCompiler::StartWorkerThreads(u32 num_worker_threads) diff --git a/Source/Core/VideoCommon/AsyncShaderCompiler.h b/Source/Core/VideoCommon/AsyncShaderCompiler.h index 15f46f1a0a..8773891d61 100644 --- a/Source/Core/VideoCommon/AsyncShaderCompiler.h +++ b/Source/Core/VideoCommon/AsyncShaderCompiler.h @@ -49,11 +49,9 @@ public: bool HasPendingWork(); bool HasCompletedWork(); - // Simpler version without progress updates. - void WaitUntilCompletion(); - // Calls progress_callback periodically, with completed_items, and total_items. - void WaitUntilCompletion(const std::function& progress_callback); + // Returns false if interrupted. + bool WaitUntilCompletion(const std::function& progress_callback); // Needed because of calling virtual methods in shutdown procedure. bool StartWorkerThreads(u32 num_worker_threads); diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index 984793d9d8..b5d848238a 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -157,9 +157,12 @@ const AbstractPipeline* ShaderCache::GetUberPipelineForUid(const GXUberPipelineU void ShaderCache::WaitForAsyncCompiler() { - while (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork()) + bool running = true; + + while (running && + (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork())) { - m_async_shader_compiler->WaitUntilCompletion([](size_t completed, size_t total) { + running = m_async_shader_compiler->WaitUntilCompletion([](size_t completed, size_t total) { g_renderer->BeginUIFrame(); const float center_x = ImGui::GetIO().DisplaySize.x * 0.5f; From 7faf5ea170f23de3b4a7b9362926490c5b7a97bc Mon Sep 17 00:00:00 2001 From: Silent Date: Sun, 10 Nov 2019 22:33:33 +0100 Subject: [PATCH 2/2] Clear the UI after async shader compilation --- Source/Core/VideoCommon/ShaderCache.cpp | 53 ++++++++++++++----------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index b5d848238a..35ce392be2 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -159,35 +159,42 @@ void ShaderCache::WaitForAsyncCompiler() { bool running = true; + constexpr auto update_ui_progress = [](size_t completed, size_t total) { + g_renderer->BeginUIFrame(); + + const float center_x = ImGui::GetIO().DisplaySize.x * 0.5f; + const float center_y = ImGui::GetIO().DisplaySize.y * 0.5f; + const float scale = ImGui::GetIO().DisplayFramebufferScale.x; + + ImGui::SetNextWindowSize(ImVec2(400.0f * scale, 50.0f * scale), ImGuiCond_Always); + ImGui::SetNextWindowPos(ImVec2(center_x, center_y), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + if (ImGui::Begin(Common::GetStringT("Compiling Shaders").c_str(), nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) + { + ImGui::Text("Compiling shaders: %zu/%zu", completed, total); + ImGui::ProgressBar(static_cast(completed) / + static_cast(std::max(total, static_cast(1))), + ImVec2(-1.0f, 0.0f), ""); + } + ImGui::End(); + + g_renderer->EndUIFrame(); + }; + while (running && (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork())) { - running = m_async_shader_compiler->WaitUntilCompletion([](size_t completed, size_t total) { - g_renderer->BeginUIFrame(); + running = m_async_shader_compiler->WaitUntilCompletion(update_ui_progress); - const float center_x = ImGui::GetIO().DisplaySize.x * 0.5f; - const float center_y = ImGui::GetIO().DisplaySize.y * 0.5f; - const float scale = ImGui::GetIO().DisplayFramebufferScale.x; - - ImGui::SetNextWindowSize(ImVec2(400.0f * scale, 50.0f * scale), ImGuiCond_Always); - ImGui::SetNextWindowPos(ImVec2(center_x, center_y), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); - if (ImGui::Begin(Common::GetStringT("Compiling Shaders").c_str(), nullptr, - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | - ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | - ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) - { - ImGui::Text("Compiling shaders: %zu/%zu", completed, total); - ImGui::ProgressBar(static_cast(completed) / - static_cast(std::max(total, static_cast(1))), - ImVec2(-1.0f, 0.0f), ""); - } - ImGui::End(); - - g_renderer->EndUIFrame(); - }); m_async_shader_compiler->RetrieveWorkItems(); } + + // Just render nothing to clear the screen + g_renderer->BeginUIFrame(); + g_renderer->EndUIFrame(); } template