diff --git a/apps/RenderCadenceCompositor/app/RuntimeLayerController.cpp b/apps/RenderCadenceCompositor/app/RuntimeLayerController.cpp index 532d529..d145d73 100644 --- a/apps/RenderCadenceCompositor/app/RuntimeLayerController.cpp +++ b/apps/RenderCadenceCompositor/app/RuntimeLayerController.cpp @@ -50,6 +50,8 @@ void RuntimeLayerController::Stop() ControlActionResult RuntimeLayerController::HandleAddLayer(const std::string& body) { + CleanupRetiredShaderBuilds(); + std::string shaderId; std::string error; if (!ExtractStringField(body, "shaderId", shaderId, error)) @@ -69,6 +71,8 @@ ControlActionResult RuntimeLayerController::HandleAddLayer(const std::string& bo ControlActionResult RuntimeLayerController::HandleRemoveLayer(const std::string& body) { + CleanupRetiredShaderBuilds(); + std::string layerId; std::string error; if (!ExtractStringField(body, "layerId", layerId, error)) @@ -81,7 +85,7 @@ ControlActionResult RuntimeLayerController::HandleRemoveLayer(const std::string& } Log("runtime-shader", "Layer removed: " + layerId); - StopLayerShaderBuild(layerId); + RetireLayerShaderBuild(layerId); PublishRuntimeRenderLayers(); return { true, std::string() }; } @@ -125,6 +129,9 @@ void RuntimeLayerController::InitializeLayerModel(std::string& runtimeShaderId) void RuntimeLayerController::StartLayerShaderBuild(const std::string& layerId, const std::string& shaderId) { + CleanupRetiredShaderBuilds(); + RetireLayerShaderBuild(layerId); + { std::lock_guard lock(mRuntimeLayerMutex); std::string error; @@ -135,9 +142,6 @@ void RuntimeLayerController::StartLayerShaderBuild(const std::string& layerId, c RuntimeShaderBridge* bridgePtr = bridge.get(); { std::lock_guard lock(mShaderBuildMutex); - auto existingIt = mShaderBuilds.find(layerId); - if (existingIt != mShaderBuilds.end()) - existingIt->second->Stop(); mShaderBuilds[layerId] = std::move(bridge); } @@ -154,7 +158,7 @@ void RuntimeLayerController::StartLayerShaderBuild(const std::string& layerId, c }); } -void RuntimeLayerController::StopLayerShaderBuild(const std::string& layerId) +void RuntimeLayerController::RetireLayerShaderBuild(const std::string& layerId) { std::unique_ptr bridge; { @@ -164,19 +168,45 @@ void RuntimeLayerController::StopLayerShaderBuild(const std::string& layerId) return; bridge = std::move(bridgeIt->second); mShaderBuilds.erase(bridgeIt); + bridge->RequestStop(); + mRetiredShaderBuilds.push_back(std::move(bridge)); } - bridge->Stop(); +} + +void RuntimeLayerController::CleanupRetiredShaderBuilds() +{ + std::vector> readyToStop; + { + std::lock_guard lock(mShaderBuildMutex); + for (auto it = mRetiredShaderBuilds.begin(); it != mRetiredShaderBuilds.end();) + { + if ((*it)->CanStopWithoutWaiting()) + { + readyToStop.push_back(std::move(*it)); + it = mRetiredShaderBuilds.erase(it); + continue; + } + ++it; + } + } + + for (std::unique_ptr& bridge : readyToStop) + bridge->Stop(); } void RuntimeLayerController::StopAllRuntimeShaderBuilds() { std::map> builds; + std::vector> retiredBuilds; { std::lock_guard lock(mShaderBuildMutex); builds.swap(mShaderBuilds); + retiredBuilds.swap(mRetiredShaderBuilds); } for (auto& entry : builds) entry.second->Stop(); + for (auto& bridge : retiredBuilds) + bridge->Stop(); } void RuntimeLayerController::PublishRuntimeRenderLayers() diff --git a/apps/RenderCadenceCompositor/app/RuntimeLayerController.h b/apps/RenderCadenceCompositor/app/RuntimeLayerController.h index 4b4cc25..cb52fca 100644 --- a/apps/RenderCadenceCompositor/app/RuntimeLayerController.h +++ b/apps/RenderCadenceCompositor/app/RuntimeLayerController.h @@ -40,7 +40,8 @@ private: void LoadSupportedShaderCatalog(const std::string& shaderLibrary, unsigned maxTemporalHistoryFrames); void InitializeLayerModel(std::string& runtimeShaderId); void StartLayerShaderBuild(const std::string& layerId, const std::string& shaderId); - void StopLayerShaderBuild(const std::string& layerId); + void RetireLayerShaderBuild(const std::string& layerId); + void CleanupRetiredShaderBuilds(); void StopAllRuntimeShaderBuilds(); void PublishRuntimeRenderLayers(); bool MarkRuntimeBuildReady(const RuntimeShaderArtifact& artifact); @@ -55,5 +56,6 @@ private: RuntimeLayerModel mRuntimeLayerModel; std::mutex mShaderBuildMutex; std::map> mShaderBuilds; + std::vector> mRetiredShaderBuilds; }; } diff --git a/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.cpp b/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.cpp index dc64dbd..03569c0 100644 --- a/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.cpp +++ b/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.cpp @@ -22,19 +22,31 @@ void RuntimeShaderBridge::Start(const std::string& layerId, const std::string& s mOnArtifactReady = std::move(onArtifactReady); mOnError = std::move(onError); mStopping.store(false, std::memory_order_release); + mFinished.store(false, std::memory_order_release); mCompiler.StartShaderBuild(shaderId); mThread = std::thread([this]() { ThreadMain(); }); } -void RuntimeShaderBridge::Stop() +void RuntimeShaderBridge::RequestStop() { mStopping.store(true, std::memory_order_release); +} + +void RuntimeShaderBridge::Stop() +{ + RequestStop(); if (mThread.joinable()) mThread.join(); mCompiler.Stop(); mLayerId.clear(); mOnArtifactReady = ArtifactCallback(); mOnError = ErrorCallback(); + mFinished.store(true, std::memory_order_release); +} + +bool RuntimeShaderBridge::CanStopWithoutWaiting() const +{ + return mFinished.load(std::memory_order_acquire) && !mCompiler.Running(); } void RuntimeShaderBridge::ThreadMain() @@ -54,8 +66,10 @@ void RuntimeShaderBridge::ThreadMain() { mOnError(build.message); } + mFinished.store(true, std::memory_order_release); return; } std::this_thread::sleep_for(std::chrono::milliseconds(5)); } + mFinished.store(true, std::memory_order_release); } diff --git a/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.h b/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.h index 60256a5..7c08194 100644 --- a/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.h +++ b/apps/RenderCadenceCompositor/runtime/RuntimeShaderBridge.h @@ -21,7 +21,9 @@ public: void Start(const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError); void Start(const std::string& layerId, const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError); + void RequestStop(); void Stop(); + bool CanStopWithoutWaiting() const; private: void ThreadMain(); @@ -29,6 +31,7 @@ private: RuntimeSlangShaderCompiler mCompiler; std::thread mThread; std::atomic mStopping{ false }; + std::atomic mFinished{ true }; std::string mLayerId; ArtifactCallback mOnArtifactReady; ErrorCallback mOnError;