Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #8467 from CookiePLMonster/interruptable-shader-pr…
…ecompile

Make shader precompilation interruptable
  • Loading branch information
AdmiralCurtiss committed Jul 2, 2022
2 parents 2f22831 + 7faf5ea commit 3bcd7ac
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 38 deletions.
20 changes: 10 additions & 10 deletions Source/Core/VideoCommon/AsyncShaderCompiler.cpp
Expand Up @@ -9,6 +9,8 @@
#include "Common/Logging/Log.h"
#include "Common/Thread.h"

#include "Core/Core.h"

namespace VideoCommon
{
AsyncShaderCompiler::AsyncShaderCompiler()
Expand Down Expand Up @@ -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<void(size_t, size_t)>& 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.
Expand All @@ -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<std::mutex> pending_guard(m_pending_work_lock);
Expand All @@ -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<std::mutex> pending_guard(m_pending_work_lock);
Expand All @@ -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)
Expand Down
6 changes: 2 additions & 4 deletions Source/Core/VideoCommon/AsyncShaderCompiler.h
Expand Up @@ -49,11 +49,9 @@ class AsyncShaderCompiler
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<void(size_t, size_t)>& progress_callback);
// Returns false if interrupted.
bool WaitUntilCompletion(const std::function<void(size_t, size_t)>& progress_callback);

// Needed because of calling virtual methods in shutdown procedure.
bool StartWorkerThreads(u32 num_worker_threads);
Expand Down
58 changes: 34 additions & 24 deletions Source/Core/VideoCommon/ShaderCache.cpp
Expand Up @@ -157,34 +157,44 @@ const AbstractPipeline* ShaderCache::GetUberPipelineForUid(const GXUberPipelineU

void ShaderCache::WaitForAsyncCompiler()
{
while (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork())
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<float>(completed) /
static_cast<float>(std::max(total, static_cast<size_t>(1))),
ImVec2(-1.0f, 0.0f), "");
}
ImGui::End();

g_renderer->EndUIFrame();
};

while (running &&
(m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork()))
{
m_async_shader_compiler->WaitUntilCompletion([](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<float>(completed) /
static_cast<float>(std::max(total, static_cast<size_t>(1))),
ImVec2(-1.0f, 0.0f), "");
}
ImGui::End();
running = m_async_shader_compiler->WaitUntilCompletion(update_ui_progress);

g_renderer->EndUIFrame();
});
m_async_shader_compiler->RetrieveWorkItems();
}

// Just render nothing to clear the screen
g_renderer->BeginUIFrame();
g_renderer->EndUIFrame();
}

template <typename SerializedUidType, typename UidType>
Expand Down

0 comments on commit 3bcd7ac

Please sign in to comment.