From 067c60609254a19fef0a938de6eec933ca53fdde Mon Sep 17 00:00:00 2001 From: Aiden <68633820+awils27@users.noreply.github.com> Date: Sat, 30 May 2026 20:57:01 +1000 Subject: [PATCH] removed hard coded shader start up --- config/runtime-host.json | 2 +- config/runtime-host.schema.json | 4 ++-- docs/FORKING_RENDER_CADENCE_BASE.md | 2 +- docs/openapi.yaml | 2 ++ src/README.md | 6 +++--- src/app/AppConfig.cpp | 2 +- src/app/AppConfig.h | 2 +- src/app/RuntimeLayerControllerStartup.cpp | 11 ++++++++-- .../shader/RuntimeSlangShaderCompiler.cpp | 10 ++++----- .../shader/RuntimeSlangShaderCompiler.h | 1 - ...adenceCompositorHttpControlServerTests.cpp | 2 +- ...adenceCompositorRuntimeLayerModelTests.cpp | 17 +++++++++++++++ ui/src/components/ConfigEditor.jsx | 21 ++++++++++++++++++- 13 files changed, 62 insertions(+), 20 deletions(-) diff --git a/config/runtime-host.json b/config/runtime-host.json index 7b4f7f8..a1bedf7 100644 --- a/config/runtime-host.json +++ b/config/runtime-host.json @@ -24,7 +24,7 @@ }, "previewEnabled": true, "previewFps": 59.94, - "runtimeShaderId": "happy-accident", + "runtimeShaderId": "", "serverPort": 8080, "shaderLibrary": "shaders" } diff --git a/config/runtime-host.schema.json b/config/runtime-host.schema.json index 3118875..9c6ce3e 100644 --- a/config/runtime-host.schema.json +++ b/config/runtime-host.schema.json @@ -70,8 +70,8 @@ }, "runtimeShaderId": { "type": "string", - "default": "happy-accident", - "description": "Startup shader package id used when no saved runtime layer stack is restored." + "default": "", + "description": "Optional startup shader package id used only when no saved runtime layer stack is restored. Leave empty to keep the simple fallback renderer until layers are added or restored." } }, "required": [ diff --git a/docs/FORKING_RENDER_CADENCE_BASE.md b/docs/FORKING_RENDER_CADENCE_BASE.md index 576d1cd..560f868 100644 --- a/docs/FORKING_RENDER_CADENCE_BASE.md +++ b/docs/FORKING_RENDER_CADENCE_BASE.md @@ -65,7 +65,7 @@ Do not move DeckLink, NDI, file I/O, shader compilation, or control handling int Before cutting a long-lived fork, fix or decide these items: -- Remove hardcoded `happy-accident` assumptions in `src/app/AppConfig.h` and `src/runtime/shader/RuntimeSlangShaderCompiler.cpp`. +- Keep `runtimeShaderId` empty in checked-in config unless this repo intentionally wants a default startup shader again. - Align remaining runtime third-party discovery with CMake. Font atlas generation now checks `MSDF_ATLAS_GEN_ROOT`, `THIRD_PARTY_ROOT`, `3rdParty`, and `video-io-3rdParty`; shader compiler lookup still needs the same treatment for Slang. - Make `config/runtime-host.json` portable. Current checked-in defaults include a local NDI source name and DeckLink output. - Decide whether the fork keeps the Slang shader package contract. If not, retire or clearly isolate `shaders/SHADER_CONTRACT.md`, shader package UI, and shader manifest tests. diff --git a/docs/openapi.yaml b/docs/openapi.yaml index ca85ab8..b439836 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -640,6 +640,8 @@ components: type: number runtimeShaderId: type: string + description: Optional startup shader id used only when no saved runtime layer stack is restored. + default: "" additionalProperties: false HostVideoInputConfig: type: object diff --git a/src/README.md b/src/README.md index 94d5379..7c381d9 100644 --- a/src/README.md +++ b/src/README.md @@ -62,7 +62,7 @@ Included now: - bounded FIFO system-memory frame exchange - bounded completed-frame output preroll reserve before DeckLink playback, with DeckLink scheduled depth still targeted at four - conservative DeckLink schedule-lead telemetry and recovery -- background Slang compile of `shaders/happy-accident` +- optional background Slang compile of configured or restored runtime shader layers - app-owned display/render layer model for shader build readiness - app-owned submission of a completed shader artifact - render-thread-owned render-content interface with runtime shader content as the default implementation @@ -364,7 +364,7 @@ Healthy first-run signs: ## Runtime Slang Shader Stack -On startup the app first tries to restore `runtime/runtime_state.json`. Valid saved layers are rebuilt in saved order, including shader id, bypass state, and parameter values. Missing shader packages are skipped, invalid saved parameter values fall back to manifest defaults, and if the runtime-state file is missing or unusable the app falls back to the configured shader package. The default configured shader is `shaders/happy-accident`. +On startup the app first tries to restore `runtime/runtime_state.json`. Valid saved layers are rebuilt in saved order, including shader id, bypass state, and parameter values. Missing shader packages are skipped, invalid saved parameter values fall back to manifest defaults, and if the runtime-state file is missing or unusable the app falls back to the optional configured startup shader. The checked-in config leaves `runtimeShaderId` empty so a fresh host keeps the simple fallback renderer until layers are added or a saved stack exists. The render thread keeps drawing the simple motion renderer while Slang compiles. It does not choose packages, launch Slang, or track build lifecycle. Once a completed shader artifact is published, the render-thread-owned runtime scene queues changed layers to a shared-context GL prepare worker. That worker compiles/links runtime shader programs off the cadence thread. The render thread only swaps in an already-prepared GL program at a frame boundary. If either the Slang build or GL preparation fails, the app keeps rendering the current renderer or simple motion fallback. @@ -405,7 +405,7 @@ When a layer becomes render-ready, the app publishes the ready render-layer snap Successful handoff signs: - telemetry shows `shaderCommitted=1` -- output changes from the simple motion pattern to the Happy Accident shader +- output changes from the simple motion pattern to the restored or configured runtime shader stack - render/schedule cadence remains near 60 fps during and after the handoff - DeckLink buffer remains stable diff --git a/src/app/AppConfig.cpp b/src/app/AppConfig.cpp index c6ff4f6..4f10047 100644 --- a/src/app/AppConfig.cpp +++ b/src/app/AppConfig.cpp @@ -40,7 +40,7 @@ AppConfig DefaultAppConfig() config.warmupTimeout = std::chrono::seconds(3); config.prerollTimeout = std::chrono::seconds(3); config.prerollPoll = std::chrono::milliseconds(2); - config.runtimeShaderId = "happy-accident"; + config.runtimeShaderId.clear(); return config; } } diff --git a/src/app/AppConfig.h b/src/app/AppConfig.h index 9b42c8b..1a33be3 100644 --- a/src/app/AppConfig.h +++ b/src/app/AppConfig.h @@ -54,7 +54,7 @@ struct AppConfig std::chrono::milliseconds warmupTimeout = std::chrono::seconds(3); std::chrono::milliseconds prerollTimeout = std::chrono::seconds(3); std::chrono::milliseconds prerollPoll = std::chrono::milliseconds(2); - std::string runtimeShaderId = "happy-accident"; + std::string runtimeShaderId; }; AppConfig DefaultAppConfig(); diff --git a/src/app/RuntimeLayerControllerStartup.cpp b/src/app/RuntimeLayerControllerStartup.cpp index 841f077..ed320ed 100644 --- a/src/app/RuntimeLayerControllerStartup.cpp +++ b/src/app/RuntimeLayerControllerStartup.cpp @@ -36,8 +36,15 @@ void RuntimeLayerController::InitializeLayerModel(std::string& runtimeShaderId) if (InitializeLayerModelFromRuntimeState()) return; - if (!runtimeShaderId.empty()) - Log("runtime-state", "Falling back to configured runtime shader '" + runtimeShaderId + "'."); + if (runtimeShaderId.empty()) + { + Log("runtime-state", "No saved runtime layer stack or startup shader configured; using fallback renderer."); + std::lock_guard lock(mRuntimeLayerMutex); + mRuntimeLayerModel.Clear(); + return; + } + + Log("runtime-state", "Falling back to configured runtime shader '" + runtimeShaderId + "'."); std::lock_guard lock(mRuntimeLayerMutex); std::string error; diff --git a/src/runtime/shader/RuntimeSlangShaderCompiler.cpp b/src/runtime/shader/RuntimeSlangShaderCompiler.cpp index a747b36..8ced6c1 100644 --- a/src/runtime/shader/RuntimeSlangShaderCompiler.cpp +++ b/src/runtime/shader/RuntimeSlangShaderCompiler.cpp @@ -17,7 +17,7 @@ std::filesystem::path FindRepoRoot() std::filesystem::path current = std::filesystem::current_path(); for (;;) { - if (std::filesystem::exists(current / "shaders" / "happy-accident" / "shader.slang") && + if (std::filesystem::exists(current / "shaders") && std::filesystem::exists(current / "runtime" / "templates" / "shader_wrapper.slang.in")) { return current; @@ -49,13 +49,11 @@ RuntimeSlangShaderCompiler::~RuntimeSlangShaderCompiler() Stop(); } -void RuntimeSlangShaderCompiler::StartHappyAccidentBuild() -{ - StartShaderBuild("happy-accident"); -} - void RuntimeSlangShaderCompiler::StartShaderBuild(const std::string& shaderId) { + if (shaderId.empty()) + return; + if (mRunning.load(std::memory_order_acquire)) return; diff --git a/src/runtime/shader/RuntimeSlangShaderCompiler.h b/src/runtime/shader/RuntimeSlangShaderCompiler.h index bdd9a38..73725d1 100644 --- a/src/runtime/shader/RuntimeSlangShaderCompiler.h +++ b/src/runtime/shader/RuntimeSlangShaderCompiler.h @@ -23,7 +23,6 @@ public: RuntimeSlangShaderCompiler& operator=(const RuntimeSlangShaderCompiler&) = delete; ~RuntimeSlangShaderCompiler(); - void StartHappyAccidentBuild(); void StartShaderBuild(const std::string& shaderId); void Stop(); bool TryConsume(RuntimeSlangShaderBuild& build); diff --git a/tests/RenderCadenceCompositorHttpControlServerTests.cpp b/tests/RenderCadenceCompositorHttpControlServerTests.cpp index 15e41fa..f8d631b 100644 --- a/tests/RenderCadenceCompositorHttpControlServerTests.cpp +++ b/tests/RenderCadenceCompositorHttpControlServerTests.cpp @@ -165,7 +165,7 @@ void TestKnownPostEndpointReturnsActionError() HttpControlServer::HttpRequest request; request.method = "POST"; request.path = "/api/layers/add"; - request.body = "{\"shaderId\":\"happy-accident\"}"; + request.body = "{\"shaderId\":\"solid\"}"; RenderCadenceHttpRouteCallbacks callbacks; const HttpControlServer::HttpResponse response = RouteRenderCadenceHttpRequest(request, server, callbacks); diff --git a/tests/RenderCadenceCompositorRuntimeLayerModelTests.cpp b/tests/RenderCadenceCompositorRuntimeLayerModelTests.cpp index 2b39b14..3bfbcca 100644 --- a/tests/RenderCadenceCompositorRuntimeLayerModelTests.cpp +++ b/tests/RenderCadenceCompositorRuntimeLayerModelTests.cpp @@ -180,6 +180,22 @@ void TestRejectsUnsupportedStartupShader() std::filesystem::remove_all(root); } +void TestEmptyStartupShaderKeepsModelEmpty() +{ + std::filesystem::path root; + RenderCadenceCompositor::SupportedShaderCatalog catalog = MakeCatalog(root); + + RenderCadenceCompositor::RuntimeLayerModel model; + std::string error = "unexpected"; + Expect(model.InitializeSingleLayer(catalog, "", error), "empty startup shader is accepted"); + Expect(error.empty(), "empty startup shader reports no error"); + Expect(model.FirstLayerId().empty(), "empty startup shader creates no startup layer"); + Expect(model.Snapshot().displayLayers.empty(), "empty startup shader leaves display model empty"); + Expect(model.PendingLayerBuilds().empty(), "empty startup shader queues no build"); + + std::filesystem::remove_all(root); +} + void TestBuildFailureStaysDisplaySide() { std::filesystem::path root; @@ -576,6 +592,7 @@ int main() { TestSingleLayerLifecycle(); TestRejectsUnsupportedStartupShader(); + TestEmptyStartupShaderKeepsModelEmpty(); TestBuildFailureStaysDisplaySide(); TestAddAndRemoveLayers(); TestSnapshotCompileMessageSummarizesLayerStack(); diff --git a/ui/src/components/ConfigEditor.jsx b/ui/src/components/ConfigEditor.jsx index f0a86ba..6351efa 100644 --- a/ui/src/components/ConfigEditor.jsx +++ b/ui/src/components/ConfigEditor.jsx @@ -50,6 +50,19 @@ function TextField({ config, label, path, setConfig }) { ); } +function OptionalTextField({ config, label, path, placeholder, setConfig }) { + return ( + + setConfig((current) => writePath(current, path, event.target.value))} + /> + + ); +} + function InputDeviceField({ config, manualOpen, @@ -397,7 +410,13 @@ export function ConfigEditor({ onClose }) {

Runtime

- +