Fixes
Some checks failed
CI / React UI Build (push) Successful in 38s
CI / Native Windows Build And Tests (push) Failing after 3m0s
CI / Windows Release Package (push) Has been skipped

This commit is contained in:
2026-05-22 14:43:03 +10:00
parent 084e60cbe0
commit 0b6a2300ea
47 changed files with 169 additions and 80 deletions

View File

@@ -0,0 +1,49 @@
#pragma once
#include "ShaderTypes.h"
#include "FontAtlasBuilder.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
struct RuntimeShaderPassArtifact
{
std::string passId;
std::string fragmentShaderSource;
std::vector<std::string> inputNames;
std::string outputName;
};
struct RuntimeTextTextureMetrics
{
float activeWidthScale = 1.0f;
float aspect = 1.0f;
};
struct RuntimePreparedTextTexture
{
std::string parameterId;
std::string textValue;
unsigned width = 0;
unsigned height = 0;
unsigned liveWidth = 1;
std::shared_ptr<const std::vector<unsigned char>> rgbaPixels;
};
struct RuntimeShaderArtifact
{
std::string layerId;
std::string shaderId;
std::string packageFingerprint;
std::string displayName;
std::string fragmentShaderSource;
std::vector<RuntimeShaderPassArtifact> passes;
std::string message;
std::vector<ShaderParameterDefinition> parameterDefinitions;
std::map<std::string, ShaderParameterValue> parameterValues;
std::map<std::string, RuntimeTextTextureMetrics> textTextureMetrics;
std::vector<RuntimePreparedTextTexture> preparedTextTextures;
std::vector<RenderCadenceCompositor::FontAtlasBuildOutput> fontAtlases;
};

View File

@@ -0,0 +1,75 @@
#include "RuntimeShaderBridge.h"
#include <chrono>
RuntimeShaderBridge::~RuntimeShaderBridge()
{
Stop();
}
void RuntimeShaderBridge::Start(const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError)
{
Start(std::string(), shaderId, std::move(onArtifactReady), std::move(onError));
}
void RuntimeShaderBridge::Start(const std::string& layerId, const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError)
{
Stop();
if (shaderId.empty())
return;
mLayerId = layerId;
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::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()
{
while (!mStopping.load(std::memory_order_acquire))
{
RuntimeSlangShaderBuild build;
if (mCompiler.TryConsume(build))
{
if (build.succeeded)
{
build.artifact.layerId = mLayerId;
if (mOnArtifactReady)
mOnArtifactReady(build.artifact);
}
else if (mOnError)
{
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);
}

View File

@@ -0,0 +1,38 @@
#pragma once
#include "RuntimeShaderArtifact.h"
#include "RuntimeSlangShaderCompiler.h"
#include <atomic>
#include <functional>
#include <string>
#include <thread>
class RuntimeShaderBridge
{
public:
using ArtifactCallback = std::function<void(const RuntimeShaderArtifact&)>;
using ErrorCallback = std::function<void(const std::string&)>;
RuntimeShaderBridge() = default;
RuntimeShaderBridge(const RuntimeShaderBridge&) = delete;
RuntimeShaderBridge& operator=(const RuntimeShaderBridge&) = delete;
~RuntimeShaderBridge();
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();
RuntimeSlangShaderCompiler mCompiler;
std::thread mThread;
std::atomic<bool> mStopping{ false };
std::atomic<bool> mFinished{ true };
std::string mLayerId;
ArtifactCallback mOnArtifactReady;
ErrorCallback mOnError;
};

View File

@@ -0,0 +1,172 @@
#include "RuntimeSlangShaderCompiler.h"
#include "ShaderCompiler.h"
#include "ShaderPackageRegistry.h"
#include "ShaderTypes.h"
#include "SupportedShaderCatalog.h"
#include <chrono>
#include <filesystem>
namespace
{
std::filesystem::path FindRepoRoot()
{
std::filesystem::path current = std::filesystem::current_path();
for (;;)
{
if (std::filesystem::exists(current / "shaders" / "happy-accident" / "shader.slang") &&
std::filesystem::exists(current / "runtime" / "templates" / "shader_wrapper.slang.in"))
{
return current;
}
const std::filesystem::path parent = current.parent_path();
if (parent.empty() || parent == current)
return std::filesystem::current_path();
current = parent;
}
}
}
RuntimeSlangShaderCompiler::~RuntimeSlangShaderCompiler()
{
Stop();
}
void RuntimeSlangShaderCompiler::StartHappyAccidentBuild()
{
StartShaderBuild("happy-accident");
}
void RuntimeSlangShaderCompiler::StartShaderBuild(const std::string& shaderId)
{
if (mRunning.load(std::memory_order_acquire))
return;
if (mThread.joinable())
mThread.join();
{
std::lock_guard<std::mutex> lock(mMutex);
mReadyBuild = RuntimeSlangShaderBuild();
}
mRunning.store(true, std::memory_order_release);
mThread = std::thread([this, shaderId]() {
RuntimeSlangShaderBuild build = BuildShader(shaderId);
{
std::lock_guard<std::mutex> lock(mMutex);
mReadyBuild = std::move(build);
mReadyBuild.available = true;
}
mRunning.store(false, std::memory_order_release);
});
}
void RuntimeSlangShaderCompiler::Stop()
{
if (mThread.joinable())
mThread.join();
mRunning.store(false, std::memory_order_release);
}
bool RuntimeSlangShaderCompiler::TryConsume(RuntimeSlangShaderBuild& build)
{
std::lock_guard<std::mutex> lock(mMutex);
if (!mReadyBuild.available)
return false;
build = std::move(mReadyBuild);
mReadyBuild = RuntimeSlangShaderBuild();
return true;
}
RuntimeSlangShaderBuild RuntimeSlangShaderCompiler::BuildShader(const std::string& shaderId) const
{
RuntimeSlangShaderBuild build;
build.artifact.shaderId = shaderId;
try
{
const std::filesystem::path repoRoot = FindRepoRoot();
const std::filesystem::path shaderDir = repoRoot / "shaders" / shaderId;
const std::filesystem::path runtimeBuildDir = repoRoot / "runtime" / "generated" / "render-cadence-compositor";
ShaderPackageRegistry registry(0);
ShaderPackage shaderPackage;
std::string error;
if (!registry.ParseManifest(shaderDir / "shader.json", shaderPackage, error))
{
build.succeeded = false;
build.message = error.empty() ? "Shader manifest parse failed." : error;
return build;
}
const RenderCadenceCompositor::ShaderSupportResult support =
RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage);
if (!support.supported)
{
build.succeeded = false;
build.message = support.reason;
return build;
}
RenderCadenceCompositor::FontAtlasBuildConfig fontConfig;
fontConfig.repoRoot = repoRoot;
RenderCadenceCompositor::FontAtlasBuilder fontAtlasBuilder(fontConfig);
std::vector<RenderCadenceCompositor::FontAtlasBuildOutput> fontAtlasOutputs;
if (!fontAtlasBuilder.BuildPackageFontAtlases(shaderPackage, fontAtlasOutputs, error))
{
build.succeeded = false;
build.message = error.empty() ? "Font atlas build failed." : error;
return build;
}
ShaderCompiler compiler(
repoRoot,
runtimeBuildDir / (shaderId + ".wrapper.slang"),
runtimeBuildDir / (shaderId + ".generated.glsl"),
runtimeBuildDir / (shaderId + ".patched.glsl"),
0);
const auto start = std::chrono::steady_clock::now();
for (const ShaderPassDefinition& pass : shaderPackage.passes)
{
std::string fragmentShaderSource;
if (!compiler.BuildPassFragmentShaderSource(shaderPackage, pass, fragmentShaderSource, error))
{
build.succeeded = false;
build.message = error.empty() ? "Slang compile failed." : error;
return build;
}
RuntimeShaderPassArtifact passArtifact;
passArtifact.passId = pass.id;
passArtifact.fragmentShaderSource = std::move(fragmentShaderSource);
passArtifact.inputNames = pass.inputNames;
passArtifact.outputName = pass.outputName;
build.artifact.passes.push_back(std::move(passArtifact));
}
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.artifact.shaderId = shaderPackage.id;
build.artifact.packageFingerprint = RenderCadenceCompositor::ShaderPackageFingerprint(shaderPackage);
build.artifact.displayName = shaderPackage.displayName;
build.artifact.parameterDefinitions = shaderPackage.parameters;
build.artifact.fontAtlases = std::move(fontAtlasOutputs);
if (!build.artifact.passes.empty())
build.artifact.fragmentShaderSource = build.artifact.passes.front().fragmentShaderSource;
build.artifact.message = shaderPackage.displayName + " Slang compile completed in " + std::to_string(milliseconds) + " ms.";
build.message = build.artifact.message;
return build;
}
catch (const std::exception& exception)
{
build.succeeded = false;
build.message = exception.what();
return build;
}
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include "RuntimeShaderArtifact.h"
#include <atomic>
#include <mutex>
#include <string>
#include <thread>
struct RuntimeSlangShaderBuild
{
bool available = false;
bool succeeded = false;
RuntimeShaderArtifact artifact;
std::string message;
};
class RuntimeSlangShaderCompiler
{
public:
RuntimeSlangShaderCompiler() = default;
RuntimeSlangShaderCompiler(const RuntimeSlangShaderCompiler&) = delete;
RuntimeSlangShaderCompiler& operator=(const RuntimeSlangShaderCompiler&) = delete;
~RuntimeSlangShaderCompiler();
void StartHappyAccidentBuild();
void StartShaderBuild(const std::string& shaderId);
void Stop();
bool TryConsume(RuntimeSlangShaderBuild& build);
bool Running() const { return mRunning.load(std::memory_order_acquire); }
private:
RuntimeSlangShaderBuild BuildShader(const std::string& shaderId) const;
std::thread mThread;
std::atomic<bool> mRunning{ false };
std::mutex mMutex;
RuntimeSlangShaderBuild mReadyBuild;
};