Texture composition for text no longer on the render thread
Some checks failed
CI / React UI Build (push) Successful in 10s
CI / Native Windows Build And Tests (push) Failing after 2m9s
CI / Windows Release Package (push) Has been skipped

This commit is contained in:
2026-05-21 17:25:28 +10:00
parent 3fc78d5bb8
commit 5cf1a09e75
8 changed files with 330 additions and 235 deletions

View File

@@ -44,6 +44,7 @@ add_video_shader_test(RenderCadenceCompositorRuntimeLayerModelTests
"${SRC_DIR}/runtime/RuntimeLayerModel.cpp"
"${SRC_DIR}/runtime/RuntimeJson.cpp"
"${SRC_DIR}/runtime/RuntimeParameterUtils.cpp"
"${SRC_DIR}/runtime/RuntimeTextTextureComposer.cpp"
"${SRC_DIR}/runtime/SupportedShaderCatalog.cpp"
"${SRC_DIR}/shader/ShaderPackageRegistry.cpp"
"${TEST_DIR}/RenderCadenceCompositorRuntimeLayerModelTests.cpp"
@@ -79,6 +80,7 @@ add_video_shader_test(RenderCadenceCompositorRuntimeStateJsonTests
"${SRC_DIR}/runtime/RuntimeJson.cpp"
"${SRC_DIR}/runtime/RuntimeLayerModel.cpp"
"${SRC_DIR}/runtime/RuntimeParameterUtils.cpp"
"${SRC_DIR}/runtime/RuntimeTextTextureComposer.cpp"
"${SRC_DIR}/runtime/SupportedShaderCatalog.cpp"
"${SRC_DIR}/shader/ShaderPackageRegistry.cpp"
"${TEST_DIR}/RenderCadenceCompositorRuntimeStateJsonTests.cpp"

View File

@@ -94,6 +94,42 @@ RenderCadenceCompositor::SupportedShaderCatalog MakeCatalog(std::filesystem::pat
return LoadCatalog(root);
}
RenderCadenceCompositor::FontAtlasBuildOutput MakeFakeFontAtlas()
{
RenderCadenceCompositor::FontAtlasBuildOutput atlas;
atlas.fontId = "inter";
atlas.width = 2;
atlas.height = 2;
atlas.ascender = -0.8;
atlas.rgbaPixels = {
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255
};
RenderCadenceCompositor::FontAtlasBuildOutput::Glyph glyph;
glyph.advance = 0.5;
glyph.planeLeft = 0.0;
glyph.planeTop = 0.0;
glyph.planeRight = 0.4;
glyph.planeBottom = 0.6;
glyph.atlasLeft = 0.0;
glyph.atlasTop = 0.0;
glyph.atlasRight = 1.0;
glyph.atlasBottom = 1.0;
glyph.hasBounds = true;
atlas.glyphsByCodepoint['A'] = glyph;
atlas.glyphsByCodepoint['B'] = glyph;
atlas.glyphsByCodepoint['D'] = glyph;
atlas.glyphsByCodepoint['E'] = glyph;
atlas.glyphsByCodepoint['F'] = glyph;
atlas.glyphsByCodepoint['L'] = glyph;
atlas.glyphsByCodepoint['T'] = glyph;
atlas.glyphsByCodepoint['U'] = glyph;
return atlas;
}
void TestSingleLayerLifecycle()
{
std::filesystem::path root;
@@ -368,6 +404,46 @@ void TestReloadRefreshesChangedShaderMetadataAndPreservesValues()
std::filesystem::remove_all(root);
}
void TestTextTexturesArePreparedInRuntimeModel()
{
std::filesystem::path root = MakeTestRoot();
WriteFile(root / "all-params" / "shader.slang", "float4 shadeVideo(float2 uv) { return float4(uv, 0.0, 1.0); }\n");
WriteFile(root / "all-params" / "Inter.ttf", "not a real font, but enough for catalog support checks");
WriteFile(root / "all-params" / "shader.json", AllParametersShaderManifest());
RenderCadenceCompositor::SupportedShaderCatalog catalog = LoadCatalog(root);
RenderCadenceCompositor::RuntimeLayerModel model;
std::string error;
Expect(model.InitializeSingleLayer(catalog, "all-params", error), "text layer can initialize");
RenderCadenceCompositor::RuntimeLayerModelSnapshot snapshot = model.Snapshot();
RuntimeShaderArtifact artifact;
artifact.layerId = model.FirstLayerId();
artifact.shaderId = "all-params";
artifact.displayName = "All Params";
artifact.fragmentShaderSource = "void main(){}";
artifact.parameterDefinitions = snapshot.displayLayers[0].parameterDefinitions;
artifact.fontAtlases.push_back(MakeFakeFontAtlas());
artifact.message = "build ready";
Expect(model.MarkBuildReady(artifact, error), error.empty() ? "ready text artifact prepares textures" : error);
snapshot = model.Snapshot();
Expect(snapshot.renderLayers.size() == 1, "text artifact is render-ready");
Expect(snapshot.renderLayers[0].artifact.preparedTextTextures.size() == 1, "render snapshot carries prepared text texture");
Expect(snapshot.renderLayers[0].artifact.fontAtlases.empty(), "render snapshot does not carry font atlas pixels");
const RuntimePreparedTextTexture preparedDefault = snapshot.renderLayers[0].artifact.preparedTextTextures[0];
Expect(preparedDefault.textValue == "DEFAULT", "default text is prepared");
Expect(preparedDefault.rgbaPixels && !preparedDefault.rgbaPixels->empty(), "prepared text has pixels");
Expect(model.UpdateParameter(model.FirstLayerId(), "titleText", JsonValue("AB"), error), error.empty() ? "text parameter update prepares texture" : error);
snapshot = model.Snapshot();
const RuntimePreparedTextTexture preparedUpdated = snapshot.renderLayers[0].artifact.preparedTextTextures[0];
Expect(preparedUpdated.textValue == "AB", "updated text is prepared before render snapshot");
Expect(preparedUpdated.rgbaPixels && preparedUpdated.rgbaPixels != preparedDefault.rgbaPixels, "updated text receives a new prepared pixel payload");
std::filesystem::remove_all(root);
}
}
int main()
@@ -380,6 +456,7 @@ int main()
TestInvalidRuntimeStateCanFallBackToConfiguredShader();
TestLayerControlsUpdateDisplayAndRenderModels();
TestReloadRefreshesChangedShaderMetadataAndPreservesValues();
TestTextTexturesArePreparedInRuntimeModel();
if (gFailures != 0)
{