#include "SupportedShaderCatalog.h" #include #include #include namespace { int gFailures = 0; void Expect(bool condition, const std::string& message) { if (condition) return; ++gFailures; std::cerr << "FAIL: " << message << "\n"; } ShaderPackage MakeSinglePassPackage() { ShaderPackage shaderPackage; shaderPackage.id = "supported"; ShaderPassDefinition pass; pass.id = "main"; pass.entryPoint = "mainImage"; pass.sourcePath = "shader.slang"; pass.outputName = "layerOutput"; shaderPackage.passes.push_back(pass); return shaderPackage; } std::filesystem::path RepoRoot() { std::filesystem::path path = std::filesystem::current_path(); while (!path.empty()) { if (std::filesystem::exists(path / "shaders" / "text-overlay" / "shader.json")) return path; const std::filesystem::path parent = path.parent_path(); if (parent.empty() || parent == path) break; path = parent; } return std::filesystem::current_path(); } void SupportsSinglePassStatelessPackage() { const ShaderPackage shaderPackage = MakeSinglePassPackage(); const RenderCadenceCompositor::ShaderSupportResult result = RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage); Expect(result.supported, "single-pass stateless packages should be supported"); Expect(result.reason.empty(), "supported packages should not report a rejection reason"); } void SupportsStatelessNamedPassPackage() { ShaderPackage shaderPackage = MakeSinglePassPackage(); shaderPackage.passes.front().outputName = "generatedMask"; ShaderPassDefinition secondPass; secondPass.id = "second"; secondPass.entryPoint = "mainImage"; secondPass.sourcePath = "shader.slang"; secondPass.inputNames.push_back("generatedMask"); secondPass.outputName = "layerOutput"; shaderPackage.passes.push_back(secondPass); const RenderCadenceCompositor::ShaderSupportResult result = RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage); Expect(result.supported, "stateless named-pass packages should be supported"); Expect(result.reason.empty(), "supported named-pass packages should not report a rejection reason"); } void RejectsUnknownPassInput() { ShaderPackage shaderPackage = MakeSinglePassPackage(); shaderPackage.passes.front().inputNames.push_back("missingIntermediate"); const RenderCadenceCompositor::ShaderSupportResult result = RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage); Expect(!result.supported, "packages with unknown pass inputs should be rejected"); Expect(result.reason.find("unknown input") != std::string::npos, "unknown input rejection should explain the missing named output"); } void RejectsTemporalPackage() { ShaderPackage shaderPackage = MakeSinglePassPackage(); shaderPackage.temporal.enabled = true; const RenderCadenceCompositor::ShaderSupportResult result = RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage); Expect(!result.supported, "temporal packages should be rejected"); Expect(result.reason.find("temporal") != std::string::npos, "temporal rejection should mention temporal storage"); } void RejectsTextureAssets() { ShaderPackage shaderPackage = MakeSinglePassPackage(); ShaderTextureAsset asset; asset.id = "lut"; shaderPackage.textureAssets.push_back(asset); const RenderCadenceCompositor::ShaderSupportResult result = RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage); Expect(!result.supported, "texture-backed packages should be rejected for now"); Expect(result.reason.find("texture") != std::string::npos, "texture rejection should mention texture assets"); } void RejectsTextParametersWithoutDeclaredFont() { ShaderPackage shaderPackage = MakeSinglePassPackage(); ShaderParameterDefinition parameter; parameter.id = "caption"; parameter.type = ShaderParameterType::Text; parameter.fontId = "missing"; shaderPackage.parameters.push_back(parameter); const RenderCadenceCompositor::ShaderSupportResult result = RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage); Expect(!result.supported, "text parameters without declared fonts should be rejected"); Expect(result.reason.find("unknown font") != std::string::npos, "text rejection should mention the missing font"); } void SupportsTextParametersWithDeclaredFont() { ShaderPackage shaderPackage = MakeSinglePassPackage(); ShaderFontAsset fontAsset; fontAsset.id = "roboto"; shaderPackage.fontAssets.push_back(fontAsset); ShaderParameterDefinition parameter; parameter.id = "caption"; parameter.type = ShaderParameterType::Text; parameter.fontId = "roboto"; shaderPackage.parameters.push_back(parameter); const RenderCadenceCompositor::ShaderSupportResult result = RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage); Expect(result.supported, "text parameters with declared fonts should be supported"); Expect(result.reason.empty(), "supported text parameters should not report a rejection reason"); } void BuildsDeclaredFontAtlasesDuringCatalogLoad() { RenderCadenceCompositor::SupportedShaderCatalog catalog; std::string error; Expect(catalog.Load(RepoRoot() / "shaders", 12, error), "shader catalog loads"); bool textOverlaySupported = false; for (const RenderCadenceCompositor::SupportedShaderSummary& shader : catalog.Shaders()) { if (shader.id == "text-overlay") textOverlaySupported = true; } Expect(textOverlaySupported, "text overlay is listed as a supported shader after font atlas preparation"); const auto& fontAtlases = catalog.FontAtlases(); const auto textOverlayIt = fontAtlases.find("text-overlay"); Expect(textOverlayIt != fontAtlases.end(), "text overlay font atlas is prepared during catalog load"); if (textOverlayIt != fontAtlases.end() && !textOverlayIt->second.empty()) { Expect(std::filesystem::exists(textOverlayIt->second.front().imagePath), "catalog font atlas image exists"); Expect(std::filesystem::exists(textOverlayIt->second.front().jsonPath), "catalog font atlas json exists"); Expect(std::filesystem::file_size(textOverlayIt->second.front().imagePath) > 0, "catalog font atlas image is not empty"); Expect(std::filesystem::file_size(textOverlayIt->second.front().jsonPath) > 0, "catalog font atlas json is not empty"); } } } int main() { SupportsSinglePassStatelessPackage(); SupportsStatelessNamedPassPackage(); RejectsUnknownPassInput(); RejectsTemporalPackage(); RejectsTextureAssets(); RejectsTextParametersWithoutDeclaredFont(); SupportsTextParametersWithDeclaredFont(); BuildsDeclaredFontAtlasesDuringCatalogLoad(); if (gFailures != 0) { std::cerr << gFailures << " RenderCadenceCompositorSupportedShaderCatalog test failure(s).\n"; return 1; } std::cout << "RenderCadenceCompositorSupportedShaderCatalog tests passed.\n"; return 0; }