reload no longer can disrupt the renderer

This commit is contained in:
2026-05-21 17:30:09 +10:00
parent 5cf1a09e75
commit f9aac85e5f
6 changed files with 118 additions and 29 deletions

View File

@@ -405,6 +405,84 @@ void TestReloadRefreshesChangedShaderMetadataAndPreservesValues()
std::filesystem::remove_all(root);
}
RuntimeShaderArtifact MakeReadyArtifact(
const RenderCadenceCompositor::SupportedShaderCatalog& catalog,
const std::string& layerId,
const std::string& shaderId,
const std::string& sourceToken)
{
const ShaderPackage* shaderPackage = catalog.FindPackage(shaderId);
RuntimeShaderArtifact artifact;
artifact.layerId = layerId;
artifact.shaderId = shaderId;
artifact.displayName = shaderPackage ? shaderPackage->displayName : shaderId;
artifact.packageFingerprint = shaderPackage ? RenderCadenceCompositor::ShaderPackageFingerprint(*shaderPackage) : sourceToken;
artifact.fragmentShaderSource = "void main(){/*" + sourceToken + "*/}";
if (shaderPackage)
artifact.parameterDefinitions = shaderPackage->parameters;
artifact.message = "build ready";
return artifact;
}
void TestReloadRebuildKeepsLastGoodRenderArtifacts()
{
std::filesystem::path root;
RenderCadenceCompositor::SupportedShaderCatalog catalog = MakeCatalog(root);
WriteFile(root / "passthrough" / "shader.slang", "float4 shadeVideo(float2 uv) { return float4(uv, 1.0, 1.0); }\n");
WriteFile(root / "passthrough" / "shader.json", R"({
"id": "passthrough",
"name": "Passthrough",
"description": "Passthrough test shader",
"category": "Tests",
"entryPoint": "shadeVideo",
"parameters": [
{ "id": "opacity", "label": "Opacity", "type": "float", "default": 1.0 }
]
})");
catalog = LoadCatalog(root);
RenderCadenceCompositor::RuntimeLayerModel model;
std::string error;
std::string solidLayerId;
std::string passthroughLayerId;
Expect(model.AddLayer(catalog, "solid", solidLayerId, error), "reload preserve solid layer can be added");
Expect(model.AddLayer(catalog, "passthrough", passthroughLayerId, error), "reload preserve passthrough layer can be added");
Expect(model.MarkBuildReady(MakeReadyArtifact(catalog, solidLayerId, "solid", "solid-old"), error), "solid layer starts render-ready");
Expect(model.MarkBuildReady(MakeReadyArtifact(catalog, passthroughLayerId, "passthrough", "passthrough-old"), error), "passthrough layer starts render-ready");
RenderCadenceCompositor::RuntimeLayerModelSnapshot snapshot = model.Snapshot();
Expect(snapshot.renderLayers.size() == 2, "ready stack exposes both render layers before reload");
const std::string oldSolidSource = snapshot.renderLayers[0].artifact.fragmentShaderSource;
const std::string oldPassthroughSource = snapshot.renderLayers[1].artifact.fragmentShaderSource;
WriteFile(root / "solid" / "shader.json", SolidShaderManifest(0.25, true));
RenderCadenceCompositor::SupportedShaderCatalog reloadedCatalog = LoadCatalog(root);
std::vector<std::pair<std::string, std::string>> buildsToStart;
Expect(model.ReloadFromCatalog(reloadedCatalog, buildsToStart, error), "reload preserve refreshes catalog");
for (const auto& build : buildsToStart)
Expect(model.MarkBuildStarted(build.first, "reload build started", error, true), "reload build preserves last good artifact");
snapshot = model.Snapshot();
Expect(snapshot.displayLayers[0].buildState == RenderCadenceCompositor::RuntimeLayerBuildState::Pending, "reload marks first layer pending");
Expect(snapshot.renderLayers.size() == 2, "pending reload keeps full render stack");
Expect(snapshot.renderLayers[0].artifact.fragmentShaderSource == oldSolidSource, "pending reload keeps old first layer artifact");
Expect(snapshot.renderLayers[1].artifact.fragmentShaderSource == oldPassthroughSource, "pending reload keeps old second layer artifact");
Expect(model.MarkBuildFailed(solidLayerId, "reload compile failed", error), "failed reload marks layer failed");
snapshot = model.Snapshot();
Expect(!snapshot.compileSucceeded, "failed reload reports compile failure");
Expect(snapshot.renderLayers.size() == 2, "failed reload keeps last good render stack");
Expect(snapshot.renderLayers[0].artifact.fragmentShaderSource == oldSolidSource, "failed reload keeps old failed layer artifact");
Expect(model.MarkBuildReady(MakeReadyArtifact(reloadedCatalog, passthroughLayerId, "passthrough", "passthrough-new"), error), "other reload layer can commit");
snapshot = model.Snapshot();
Expect(snapshot.renderLayers.size() == 2, "partial reload commit still keeps complete render stack");
Expect(snapshot.renderLayers[0].artifact.fragmentShaderSource == oldSolidSource, "partial reload commit keeps old failed layer artifact");
Expect(snapshot.renderLayers[1].artifact.fragmentShaderSource.find("passthrough-new") != std::string::npos, "partial reload commit updates ready layer");
std::filesystem::remove_all(root);
}
void TestTextTexturesArePreparedInRuntimeModel()
{
std::filesystem::path root = MakeTestRoot();
@@ -456,6 +534,7 @@ int main()
TestInvalidRuntimeStateCanFallBackToConfiguredShader();
TestLayerControlsUpdateDisplayAndRenderModels();
TestReloadRefreshesChangedShaderMetadataAndPreservesValues();
TestReloadRebuildKeepsLastGoodRenderArtifacts();
TestTextTexturesArePreparedInRuntimeModel();
if (gFailures != 0)