#include "RuntimeSlangShaderCompiler.h" #include "ShaderCompiler.h" #include "ShaderTypes.h" #include #include #include namespace { ShaderParameterDefinition FloatParam(const std::string& id, double defaultValue) { ShaderParameterDefinition parameter; parameter.id = id; parameter.label = id; parameter.type = ShaderParameterType::Float; parameter.defaultNumbers.push_back(defaultValue); return parameter; } 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() { if (mRunning.load(std::memory_order_acquire)) return; if (mThread.joinable()) mThread.join(); { std::lock_guard lock(mMutex); mReadyBuild = RuntimeSlangShaderBuild(); } mRunning.store(true, std::memory_order_release); mThread = std::thread([this]() { RuntimeSlangShaderBuild build = BuildHappyAccident(); { std::lock_guard 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 lock(mMutex); if (!mReadyBuild.available) return false; build = std::move(mReadyBuild); mReadyBuild = RuntimeSlangShaderBuild(); return true; } RuntimeSlangShaderBuild RuntimeSlangShaderCompiler::BuildHappyAccident() const { RuntimeSlangShaderBuild build; build.shaderId = "happy-accident"; try { const std::filesystem::path repoRoot = FindRepoRoot(); const std::filesystem::path shaderDir = repoRoot / "shaders" / "happy-accident"; const std::filesystem::path runtimeBuildDir = repoRoot / "runtime" / "generated" / "render-cadence-compositor"; ShaderPackage shaderPackage; shaderPackage.id = "happy-accident"; shaderPackage.displayName = "Happy Accident"; shaderPackage.entryPoint = "shadeVideo"; shaderPackage.directoryPath = shaderDir; shaderPackage.shaderPath = shaderDir / "shader.slang"; shaderPackage.manifestPath = shaderDir / "shader.json"; shaderPackage.parameters.push_back(FloatParam("speed", 1.0)); shaderPackage.parameters.push_back(FloatParam("scale", 1.0)); shaderPackage.parameters.push_back(FloatParam("raySteps", 77.0)); shaderPackage.parameters.push_back(FloatParam("intensity", 1.0)); shaderPackage.parameters.push_back(FloatParam("sourceMix", 0.0)); ShaderPassDefinition pass; pass.id = "main"; pass.entryPoint = shaderPackage.entryPoint; pass.sourcePath = shaderPackage.shaderPath; pass.outputName = "output"; shaderPackage.passes.push_back(pass); ShaderCompiler compiler( repoRoot, runtimeBuildDir / "happy_accident_wrapper.slang", runtimeBuildDir / "happy_accident.generated.glsl", runtimeBuildDir / "happy_accident.patched.glsl", 0); std::string error; const auto start = std::chrono::steady_clock::now(); if (!compiler.BuildPassFragmentShaderSource(shaderPackage, pass, build.fragmentShaderSource, error)) { build.succeeded = false; build.message = error.empty() ? "Happy Accident Slang compile failed." : error; return build; } const auto end = std::chrono::steady_clock::now(); const double milliseconds = std::chrono::duration_cast>(end - start).count(); build.succeeded = true; build.message = "Happy Accident Slang compile completed in " + std::to_string(milliseconds) + " ms."; return build; } catch (const std::exception& exception) { build.succeeded = false; build.message = exception.what(); return build; } }