From b7a47c5c8881cc0077a834b56f91896c7cd881ff Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:43:04 +0300 Subject: [PATCH] Recompile pipelines on option change. --- UnleashedRecomp/gpu/video.cpp | 74 ++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index b597e71e..0a0e395c 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -5115,12 +5115,12 @@ struct DatabaseDataHolderPair // Having this separate, because I don't want to lock a mutex in the render thread before // every single draw. Might be worth profiling to see if it actually has an impact and merge them. -static ankerl::unordered_dense::set g_asyncPipelines; +static xxHashMap g_asyncPipelines; static void EnqueueGraphicsPipelineCompilation(const PipelineState& pipelineState, DatabaseDataHolderPair& databaseDataHolderPair, const char* name) { XXH64_hash_t hash = XXH3_64bits(&pipelineState, sizeof(pipelineState)); - bool shouldCompile = g_asyncPipelines.emplace(hash).second; + bool shouldCompile = g_asyncPipelines.emplace(hash, pipelineState).second; if (shouldCompile) { @@ -5743,6 +5743,8 @@ static bool CheckMadeAll(const T& modelData) return true; } +static std::atomic g_pendingPipelineRecompilations; + static void ModelConsumerThread() { #ifdef _WIN32 @@ -5852,6 +5854,58 @@ static void ModelConsumerThread() g_compilingDataCount.notify_all(); } + if (g_pendingPipelineRecompilations != 0) + { + DatabaseDataHolderPair emptyHolderPair; + auto asyncPipelines = g_asyncPipelines.values(); + + for (auto& [hash, pipelineState] : asyncPipelines) + { + bool alphaTest = (pipelineState.specConstants & (SPEC_CONSTANT_ALPHA_TEST | SPEC_CONSTANT_ALPHA_TO_COVERAGE)) != 0; + bool msaa = pipelineState.sampleCount != 1 || (pipelineState.renderTargetFormat == RenderFormat::R16G16B16A16_FLOAT && pipelineState.depthStencilFormat == RenderFormat::D32_FLOAT); + + pipelineState.sampleCount = 1; + pipelineState.enableAlphaToCoverage = false; + pipelineState.specConstants &= ~(SPEC_CONSTANT_BICUBIC_GI_FILTER | SPEC_CONSTANT_ALPHA_TEST | SPEC_CONSTANT_ALPHA_TO_COVERAGE); + + if (msaa && Config::AntiAliasing != EAntiAliasing::None) + { + pipelineState.sampleCount = int32_t(Config::AntiAliasing.Value); + + if (alphaTest) + { + if (Config::TransparencyAntiAliasing) + { + pipelineState.enableAlphaToCoverage = true; + pipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TO_COVERAGE; + } + else + { + pipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TEST; + } + } + } + else if (alphaTest) + { + pipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TEST; + } + + if (Config::GITextureFiltering == EGITextureFiltering::Bicubic) + pipelineState.specConstants |= SPEC_CONSTANT_BICUBIC_GI_FILTER; + + SanitizePipelineState(pipelineState); + EnqueueGraphicsPipelineCompilation(pipelineState, emptyHolderPair, "Recompiled Pipeline State"); + } + + if ((--g_pendingPipelineRecompilations) == 0) + { + --g_pendingDataCount; + + if ((--g_compilingDataCount) == 0) + g_compilingDataCount.notify_all(); + } + } + { std::lock_guard lock(g_pendingModelMutex); localPendingDataQueue.insert(localPendingDataQueue.end(), g_pendingDataQueue.begin(), g_pendingDataQueue.end()); @@ -6089,6 +6143,22 @@ void VideoConfigValueChangedCallback(IConfigDef* config) config == &Config::ResolutionScale || config == &Config::AntiAliasing || config == &Config::ShadowResolution; + + // Config options that require pipeline recompilation + bool shouldRecompile = + config == &Config::AntiAliasing || + config == &Config::TransparencyAntiAliasing || + config == &Config::GITextureFiltering; + + if (shouldRecompile) + { + ++g_compilingDataCount; + + if ((++g_pendingDataCount) == 1) + g_pendingDataCount.notify_all(); + + ++g_pendingPipelineRecompilations; + } } // SWA::CCsdTexListMirage::SetFilter