Shader ownership change
This commit is contained in:
@@ -38,7 +38,8 @@ Included now:
|
||||
- latest-N system-memory frame exchange
|
||||
- rendered-frame warmup
|
||||
- background Slang compile of `shaders/happy-accident`
|
||||
- render-thread-only GL commit once compiled shader source is ready
|
||||
- app-owned submission of a completed shader artifact
|
||||
- render-thread-only GL commit once the artifact is ready
|
||||
- compact telemetry
|
||||
- non-GL frame-exchange tests
|
||||
|
||||
@@ -106,9 +107,9 @@ Healthy first-run signs:
|
||||
|
||||
## Runtime Slang Shader Test
|
||||
|
||||
On startup the app begins compiling `shaders/happy-accident` on a background thread.
|
||||
On startup the app begins compiling `shaders/happy-accident` on a background thread owned by the app orchestration layer.
|
||||
|
||||
The render thread keeps drawing the simple motion renderer while Slang compiles. It only attempts the OpenGL shader compile/link once a complete GLSL fragment shader is ready. If either the Slang build or GL commit fails, the app keeps rendering the simple motion fallback.
|
||||
The render thread keeps drawing the simple motion renderer while Slang compiles. It does not choose packages, launch Slang, or track build lifecycle. It only receives a completed shader artifact and attempts the OpenGL shader compile/link at a frame boundary. If either the Slang build or GL commit fails, the app keeps rendering the simple motion fallback.
|
||||
|
||||
Successful handoff signs:
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include "../runtime/RuntimeSlangShaderCompiler.h"
|
||||
#include "../telemetry/TelemetryPrinter.h"
|
||||
#include "../video/DeckLinkOutput.h"
|
||||
#include "../video/DeckLinkOutputThread.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
@@ -78,6 +80,7 @@ public:
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
StartRuntimeShaderBuild();
|
||||
|
||||
if (!mFrameExchange.WaitForCompletedDepth(mConfig.warmupCompletedFrames, mConfig.warmupTimeout))
|
||||
{
|
||||
@@ -116,6 +119,7 @@ public:
|
||||
mTelemetry.Stop();
|
||||
mOutputThread.Stop();
|
||||
mOutput.Stop();
|
||||
StopRuntimeShaderBuild();
|
||||
mRenderThread.Stop();
|
||||
mOutput.ReleaseResources();
|
||||
mStarted = false;
|
||||
@@ -137,12 +141,47 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
void StartRuntimeShaderBuild()
|
||||
{
|
||||
mShaderCompiler.StartHappyAccidentBuild();
|
||||
mShaderBridgeStopping = false;
|
||||
mShaderBridgeThread = std::thread([this]() { ShaderBridgeMain(); });
|
||||
}
|
||||
|
||||
void StopRuntimeShaderBuild()
|
||||
{
|
||||
mShaderBridgeStopping = true;
|
||||
if (mShaderBridgeThread.joinable())
|
||||
mShaderBridgeThread.join();
|
||||
mShaderCompiler.Stop();
|
||||
}
|
||||
|
||||
void ShaderBridgeMain()
|
||||
{
|
||||
while (!mShaderBridgeStopping)
|
||||
{
|
||||
RuntimeSlangShaderBuild build;
|
||||
if (mShaderCompiler.TryConsume(build))
|
||||
{
|
||||
if (build.succeeded)
|
||||
mRenderThread.SubmitRuntimeShaderArtifact(build.artifact);
|
||||
else
|
||||
std::cout << "Runtime Slang build failed: " << build.message << "\n";
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
}
|
||||
|
||||
RenderThread& mRenderThread;
|
||||
SystemFrameExchange& mFrameExchange;
|
||||
AppConfig mConfig;
|
||||
DeckLinkOutput mOutput;
|
||||
DeckLinkOutputThread<SystemFrameExchange> mOutputThread;
|
||||
TelemetryPrinter mTelemetry;
|
||||
RuntimeSlangShaderCompiler mShaderCompiler;
|
||||
std::thread mShaderBridgeThread;
|
||||
std::atomic<bool> mShaderBridgeStopping{ false };
|
||||
bool mStarted = false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@ void RenderThread::ThreadMain()
|
||||
SignalStartupFailure("Render pipeline initialization failed.");
|
||||
return;
|
||||
}
|
||||
mSlangCompiler.StartHappyAccidentBuild();
|
||||
|
||||
RenderCadenceClock clock(mConfig.frameDurationMilliseconds);
|
||||
uint64_t frameIndex = 0;
|
||||
@@ -156,7 +155,6 @@ void RenderThread::ThreadMain()
|
||||
readback.Shutdown();
|
||||
runtimeShaderRenderer.ShutdownGl();
|
||||
renderer.ShutdownGl();
|
||||
mSlangCompiler.Stop();
|
||||
window.ClearCurrent();
|
||||
mRunning.store(false, std::memory_order_release);
|
||||
}
|
||||
@@ -193,23 +191,36 @@ void RenderThread::CountAcquireMiss()
|
||||
++mMetrics.acquireMisses;
|
||||
}
|
||||
|
||||
void RenderThread::SubmitRuntimeShaderArtifact(const RuntimeShaderArtifact& artifact)
|
||||
{
|
||||
if (artifact.fragmentShaderSource.empty())
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mShaderArtifactMutex);
|
||||
mPendingShaderArtifact = artifact;
|
||||
mHasPendingShaderArtifact = true;
|
||||
}
|
||||
|
||||
bool RenderThread::TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mShaderArtifactMutex);
|
||||
if (!mHasPendingShaderArtifact)
|
||||
return false;
|
||||
|
||||
artifact = std::move(mPendingShaderArtifact);
|
||||
mPendingShaderArtifact = RuntimeShaderArtifact();
|
||||
mHasPendingShaderArtifact = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderThread::TryCommitReadyRuntimeShader(RuntimeShaderRenderer& runtimeShaderRenderer)
|
||||
{
|
||||
RuntimeSlangShaderBuild build;
|
||||
if (!mSlangCompiler.TryConsume(build))
|
||||
RuntimeShaderArtifact artifact;
|
||||
if (!TryTakePendingRuntimeShaderArtifact(artifact))
|
||||
return;
|
||||
|
||||
if (!build.succeeded)
|
||||
{
|
||||
std::cout << "Runtime Slang build failed: " << build.message << "\n";
|
||||
OutputDebugStringA(("Runtime Slang build failed: " + build.message + "\n").c_str());
|
||||
std::lock_guard<std::mutex> lock(mMetricsMutex);
|
||||
++mMetrics.shaderBuildFailures;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string commitError;
|
||||
if (!runtimeShaderRenderer.CommitFragmentShader(build.fragmentShaderSource, commitError))
|
||||
if (!runtimeShaderRenderer.CommitFragmentShader(artifact.fragmentShaderSource, commitError))
|
||||
{
|
||||
std::cout << "Runtime shader GL commit failed: " << commitError << "\n";
|
||||
OutputDebugStringA(("Runtime shader GL commit failed: " + commitError + "\n").c_str());
|
||||
@@ -218,8 +229,8 @@ void RenderThread::TryCommitReadyRuntimeShader(RuntimeShaderRenderer& runtimeSha
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Runtime shader committed: " << build.shaderId << ". " << build.message << "\n";
|
||||
OutputDebugStringA(("Runtime shader committed: " + build.shaderId + ". " + build.message + "\n").c_str());
|
||||
std::cout << "Runtime shader committed: " << artifact.shaderId << ". " << artifact.message << "\n";
|
||||
OutputDebugStringA(("Runtime shader committed: " + artifact.shaderId + ". " + artifact.message + "\n").c_str());
|
||||
std::lock_guard<std::mutex> lock(mMetricsMutex);
|
||||
++mMetrics.shaderBuildsCommitted;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "RenderCadenceClock.h"
|
||||
#include "../runtime/RuntimeSlangShaderCompiler.h"
|
||||
#include "../runtime/RuntimeShaderArtifact.h"
|
||||
#include "RuntimeShaderRenderer.h"
|
||||
|
||||
#include <atomic>
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
|
||||
bool Start(std::string& error);
|
||||
void Stop();
|
||||
void SubmitRuntimeShaderArtifact(const RuntimeShaderArtifact& artifact);
|
||||
|
||||
Metrics GetMetrics() const;
|
||||
bool IsRunning() const { return mRunning.load(std::memory_order_acquire); }
|
||||
@@ -56,10 +57,10 @@ private:
|
||||
void CountCompleted();
|
||||
void CountAcquireMiss();
|
||||
void TryCommitReadyRuntimeShader(RuntimeShaderRenderer& runtimeShaderRenderer);
|
||||
bool TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact);
|
||||
|
||||
SystemFrameExchange& mFrameExchange;
|
||||
Config mConfig;
|
||||
RuntimeSlangShaderCompiler mSlangCompiler;
|
||||
std::thread mThread;
|
||||
std::atomic<bool> mStopping{ false };
|
||||
std::atomic<bool> mRunning{ false };
|
||||
@@ -71,4 +72,8 @@ private:
|
||||
|
||||
mutable std::mutex mMetricsMutex;
|
||||
Metrics mMetrics;
|
||||
|
||||
std::mutex mShaderArtifactMutex;
|
||||
bool mHasPendingShaderArtifact = false;
|
||||
RuntimeShaderArtifact mPendingShaderArtifact;
|
||||
};
|
||||
|
||||
10
apps/RenderCadenceCompositor/runtime/RuntimeShaderArtifact.h
Normal file
10
apps/RenderCadenceCompositor/runtime/RuntimeShaderArtifact.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
struct RuntimeShaderArtifact
|
||||
{
|
||||
std::string shaderId;
|
||||
std::string fragmentShaderSource;
|
||||
std::string message;
|
||||
};
|
||||
@@ -89,7 +89,7 @@ bool RuntimeSlangShaderCompiler::TryConsume(RuntimeSlangShaderBuild& build)
|
||||
RuntimeSlangShaderBuild RuntimeSlangShaderCompiler::BuildHappyAccident() const
|
||||
{
|
||||
RuntimeSlangShaderBuild build;
|
||||
build.shaderId = "happy-accident";
|
||||
build.artifact.shaderId = "happy-accident";
|
||||
|
||||
try
|
||||
{
|
||||
@@ -126,7 +126,7 @@ RuntimeSlangShaderBuild RuntimeSlangShaderCompiler::BuildHappyAccident() const
|
||||
|
||||
std::string error;
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
if (!compiler.BuildPassFragmentShaderSource(shaderPackage, pass, build.fragmentShaderSource, error))
|
||||
if (!compiler.BuildPassFragmentShaderSource(shaderPackage, pass, build.artifact.fragmentShaderSource, error))
|
||||
{
|
||||
build.succeeded = false;
|
||||
build.message = error.empty() ? "Happy Accident Slang compile failed." : error;
|
||||
@@ -136,7 +136,8 @@ RuntimeSlangShaderBuild RuntimeSlangShaderCompiler::BuildHappyAccident() const
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
const double milliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(end - start).count();
|
||||
build.succeeded = true;
|
||||
build.message = "Happy Accident Slang compile completed in " + std::to_string(milliseconds) + " ms.";
|
||||
build.artifact.message = "Happy Accident Slang compile completed in " + std::to_string(milliseconds) + " ms.";
|
||||
build.message = build.artifact.message;
|
||||
return build;
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "RuntimeShaderArtifact.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
@@ -9,8 +11,7 @@ struct RuntimeSlangShaderBuild
|
||||
{
|
||||
bool available = false;
|
||||
bool succeeded = false;
|
||||
std::string shaderId;
|
||||
std::string fragmentShaderSource;
|
||||
RuntimeShaderArtifact artifact;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../video/DeckLinkOutput.h"
|
||||
#include "../video/DeckLinkOutputThread.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -34,10 +31,10 @@ struct CadenceTelemetrySnapshot
|
||||
class CadenceTelemetry
|
||||
{
|
||||
public:
|
||||
template <typename SystemFrameExchange, typename OutputThread>
|
||||
template <typename SystemFrameExchange, typename Output, typename OutputThread>
|
||||
CadenceTelemetrySnapshot Sample(
|
||||
const SystemFrameExchange& exchange,
|
||||
const DeckLinkOutput& output,
|
||||
const Output& output,
|
||||
const OutputThread& outputThread)
|
||||
{
|
||||
const auto now = Clock::now();
|
||||
@@ -46,7 +43,7 @@ public:
|
||||
: 0.0;
|
||||
|
||||
const auto exchangeMetrics = exchange.Metrics();
|
||||
const DeckLinkOutputMetrics outputMetrics = output.Metrics();
|
||||
const auto outputMetrics = output.Metrics();
|
||||
const auto threadMetrics = outputThread.Metrics();
|
||||
|
||||
CadenceTelemetrySnapshot snapshot;
|
||||
@@ -80,10 +77,10 @@ public:
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
template <typename SystemFrameExchange, typename OutputThread, typename RenderThread>
|
||||
template <typename SystemFrameExchange, typename Output, typename OutputThread, typename RenderThread>
|
||||
CadenceTelemetrySnapshot Sample(
|
||||
const SystemFrameExchange& exchange,
|
||||
const DeckLinkOutput& output,
|
||||
const Output& output,
|
||||
const OutputThread& outputThread,
|
||||
const RenderThread& renderThread)
|
||||
{
|
||||
|
||||
@@ -31,8 +31,8 @@ public:
|
||||
Stop();
|
||||
}
|
||||
|
||||
template <typename SystemFrameExchange, typename OutputThread, typename RenderThread>
|
||||
void Start(const SystemFrameExchange& exchange, const DeckLinkOutput& output, const OutputThread& outputThread, const RenderThread& renderThread)
|
||||
template <typename SystemFrameExchange, typename Output, typename OutputThread, typename RenderThread>
|
||||
void Start(const SystemFrameExchange& exchange, const Output& output, const OutputThread& outputThread, const RenderThread& renderThread)
|
||||
{
|
||||
if (mRunning)
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user