diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 9307f632..4b2131b3 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -402,8 +402,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/LegacyShaderAuthoringParser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/UnityStyleShaderAuthoringParser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderSourceUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderSourceUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderAuthoringParser.h diff --git a/engine/src/Rendering/Detail/ShaderVariantUtils.h b/engine/src/Rendering/Detail/ShaderVariantUtils.h index 13453fe4..4bb695c7 100644 --- a/engine/src/Rendering/Detail/ShaderVariantUtils.h +++ b/engine/src/Rendering/Detail/ShaderVariantUtils.h @@ -331,7 +331,7 @@ inline void AddShaderCompileMacro( compileDesc.macros.push_back(std::move(macro)); } -inline void InjectUnityStyleBackendMacros( +inline void InjectShaderBackendMacros( Resources::ShaderBackend backend, RHI::ShaderCompileDesc& compileDesc) { switch (backend) { @@ -377,7 +377,7 @@ inline void ApplyShaderStageVariant( compileDesc.sourceLanguage = ToRHIShaderLanguage(variant.language); compileDesc.entryPoint = ToWideAscii(variant.entryPoint); compileDesc.profile = ToWideAscii(variant.profile); - InjectUnityStyleBackendMacros(backend, compileDesc); + InjectShaderBackendMacros(backend, compileDesc); } inline Containers::String BuildShaderKeywordSignature( diff --git a/engine/src/Resources/Shader/Internal/LegacyShaderAuthoringParser.cpp b/engine/src/Resources/Shader/Internal/LegacyShaderAuthoringParser.cpp deleted file mode 100644 index 7afb3350..00000000 --- a/engine/src/Resources/Shader/Internal/LegacyShaderAuthoringParser.cpp +++ /dev/null @@ -1,290 +0,0 @@ -#include "ShaderAuthoringInternal.h" - -#include "../ShaderSourceUtils.h" - -namespace XCEngine { -namespace Resources { -namespace Internal { - -bool ParseLegacyBackendSplitShaderAuthoring( - const Containers::String& path, - const std::string& sourceText, - ShaderIR& outDesc, - Containers::String* outError) { - (void)path; - outDesc = {}; - - enum class BlockKind { - None, - Shader, - Properties, - SubShader, - Pass, - Resources - }; - - auto fail = [&outError](const std::string& message, size_t lineNumber) -> bool { - if (outError != nullptr) { - *outError = Containers::String( - ("Legacy shader parse error at line " + std::to_string(lineNumber) + ": " + message).c_str()); - } - return false; - }; - - std::vector lines; - SplitShaderAuthoringLines(sourceText, lines); - if (lines.empty()) { - return fail("shader file is empty", 0); - } - - std::vector blockStack; - BlockKind pendingBlock = BlockKind::None; - ShaderSubShaderIR* currentSubShader = nullptr; - ShaderPassIR* currentPass = nullptr; - bool inProgram = false; - - auto currentBlock = [&blockStack]() -> BlockKind { - return blockStack.empty() ? BlockKind::None : blockStack.back(); - }; - - for (size_t lineIndex = 0; lineIndex < lines.size(); ++lineIndex) { - const std::string& line = lines[lineIndex]; - const size_t humanLine = lineIndex + 1; - - if (inProgram) { - if (line == "ENDHLSL" || line == "ENDCG") { - inProgram = false; - continue; - } - - std::vector pragmaTokens; - if (!TryTokenizeQuotedArguments(line, pragmaTokens) || pragmaTokens.empty()) { - continue; - } - - if (pragmaTokens[0] != "#pragma") { - continue; - } - - if (pragmaTokens.size() >= 3u && pragmaTokens[1] == "vertex") { - currentPass->vertexEntryPoint = pragmaTokens[2].c_str(); - continue; - } - if (pragmaTokens.size() >= 3u && pragmaTokens[1] == "fragment") { - currentPass->fragmentEntryPoint = pragmaTokens[2].c_str(); - continue; - } - if (pragmaTokens.size() >= 6u && pragmaTokens[1] == "backend") { - ShaderBackendVariantIR backendVariant = {}; - if (!TryParseShaderBackend(pragmaTokens[2].c_str(), backendVariant.backend)) { - return fail("invalid backend pragma backend name", humanLine); - } - if (!TryParseShaderLanguage(pragmaTokens[3].c_str(), backendVariant.language)) { - return fail("invalid backend pragma language name", humanLine); - } - - backendVariant.vertexSourcePath = pragmaTokens[4].c_str(); - backendVariant.fragmentSourcePath = pragmaTokens[5].c_str(); - if (pragmaTokens.size() >= 7u) { - backendVariant.vertexProfile = pragmaTokens[6].c_str(); - } - if (pragmaTokens.size() >= 8u) { - backendVariant.fragmentProfile = pragmaTokens[7].c_str(); - } - - currentPass->backendVariants.push_back(std::move(backendVariant)); - continue; - } - if (pragmaTokens.size() >= 2u && - (pragmaTokens[1] == "multi_compile" || - pragmaTokens[1] == "multi_compile_local" || - pragmaTokens[1] == "shader_feature" || - pragmaTokens[1] == "shader_feature_local")) { - ShaderKeywordDeclaration declaration = {}; - if (!TryParseShaderKeywordDeclarationPragma(pragmaTokens, declaration)) { - return fail("keyword pragma must declare at least one option", humanLine); - } - - currentPass->keywordDeclarations.PushBack(declaration); - continue; - } - continue; - } - - if (line == "{") { - switch (pendingBlock) { - case BlockKind::Shader: - blockStack.push_back(BlockKind::Shader); - break; - case BlockKind::Properties: - blockStack.push_back(BlockKind::Properties); - break; - case BlockKind::SubShader: - outDesc.subShaders.emplace_back(); - currentSubShader = &outDesc.subShaders.back(); - blockStack.push_back(BlockKind::SubShader); - break; - case BlockKind::Pass: - if (currentSubShader == nullptr) { - return fail("pass block must be inside a SubShader", humanLine); - } - currentSubShader->passes.emplace_back(); - currentPass = ¤tSubShader->passes.back(); - blockStack.push_back(BlockKind::Pass); - break; - case BlockKind::Resources: - if (currentPass == nullptr) { - return fail("resources block must be inside a Pass", humanLine); - } - blockStack.push_back(BlockKind::Resources); - break; - case BlockKind::None: - default: - return fail("unexpected opening brace", humanLine); - } - - pendingBlock = BlockKind::None; - continue; - } - - if (line == "}") { - if (blockStack.empty()) { - return fail("unexpected closing brace", humanLine); - } - - const BlockKind closingBlock = blockStack.back(); - blockStack.pop_back(); - if (closingBlock == BlockKind::Pass) { - currentPass = nullptr; - } else if (closingBlock == BlockKind::SubShader) { - currentSubShader = nullptr; - } - continue; - } - - if (StartsWithKeyword(line, "Shader")) { - std::vector tokens; - if (!TryTokenizeQuotedArguments(line, tokens) || tokens.size() < 2u) { - return fail("Shader declaration is missing a name", humanLine); - } - outDesc.name = tokens[1].c_str(); - pendingBlock = BlockKind::Shader; - continue; - } - - if (line == "Properties") { - pendingBlock = BlockKind::Properties; - continue; - } - - if (currentBlock() == BlockKind::Shader && StartsWithKeyword(line, "Fallback")) { - std::vector tokens; - if (!TryTokenizeQuotedArguments(line, tokens) || tokens.size() < 2u) { - return fail("Fallback directive is missing a value", humanLine); - } - outDesc.fallback = tokens[1].c_str(); - continue; - } - - if (StartsWithKeyword(line, "SubShader")) { - pendingBlock = BlockKind::SubShader; - continue; - } - - if (StartsWithKeyword(line, "Pass")) { - pendingBlock = BlockKind::Pass; - continue; - } - - if (line == "Resources") { - pendingBlock = BlockKind::Resources; - continue; - } - - if (StartsWithKeyword(line, "Tags")) { - std::vector parsedTags; - if (!TryParseInlineTagAssignments(line, parsedTags)) { - return fail("Tags block must use inline key/value pairs", humanLine); - } - - if (currentPass != nullptr) { - currentPass->tags.insert(currentPass->tags.end(), parsedTags.begin(), parsedTags.end()); - } else if (currentSubShader != nullptr) { - currentSubShader->tags.insert(currentSubShader->tags.end(), parsedTags.begin(), parsedTags.end()); - } else { - return fail("Tags block is only supported inside SubShader or Pass", humanLine); - } - continue; - } - - if (currentBlock() == BlockKind::Properties) { - ShaderPropertyDesc property = {}; - if (!TryParseAuthoringPropertyLine(line, property)) { - return fail("invalid Properties entry", humanLine); - } - outDesc.properties.PushBack(property); - continue; - } - - if (currentBlock() == BlockKind::Resources) { - ShaderResourceBindingDesc resourceBinding = {}; - if (!TryParseAuthoringResourceLine(line, resourceBinding)) { - return fail("invalid Resources entry", humanLine); - } - currentPass->resources.PushBack(resourceBinding); - continue; - } - - if (currentBlock() == BlockKind::Pass && currentPass != nullptr) { - if (StartsWithKeyword(line, "Name")) { - std::vector tokens; - if (!TryTokenizeQuotedArguments(line, tokens) || tokens.size() < 2u) { - return fail("pass Name directive is missing a value", humanLine); - } - currentPass->name = tokens[1].c_str(); - continue; - } - - if (line == "HLSLPROGRAM" || line == "CGPROGRAM") { - inProgram = true; - continue; - } - } - - return fail("unsupported authoring statement: " + line, humanLine); - } - - if (inProgram) { - return fail("program block was not closed", lines.size()); - } - if (!blockStack.empty()) { - return fail("one or more blocks were not closed", lines.size()); - } - if (outDesc.name.Empty()) { - return fail("shader name is missing", 0); - } - if (outDesc.subShaders.empty()) { - return fail("shader does not declare any SubShader blocks", 0); - } - - for (const ShaderSubShaderIR& subShader : outDesc.subShaders) { - if (subShader.passes.empty()) { - continue; - } - - for (const ShaderPassIR& pass : subShader.passes) { - if (pass.name.Empty()) { - return fail("a Pass is missing a Name directive", 0); - } - if (pass.backendVariants.empty()) { - return fail("a Pass is missing backend variants", 0); - } - } - } - - return true; -} - -} // namespace Internal -} // namespace Resources -} // namespace XCEngine diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp b/engine/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp index a1d318c4..07e55fb4 100644 --- a/engine/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp +++ b/engine/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp @@ -4,7 +4,7 @@ namespace XCEngine { namespace Resources { namespace Internal { -MaterialRenderState BuildUnityDefaultFixedFunctionState() { +MaterialRenderState BuildDefaultAuthoringFixedFunctionState() { MaterialRenderState state = {}; state.blendEnable = false; state.srcBlend = MaterialBlendFactor::One; @@ -26,11 +26,11 @@ void EnsureAuthoringFixedFunctionStateInitialized( MaterialRenderState& fixedFunctionState) { if (!hasFixedFunctionState) { hasFixedFunctionState = true; - fixedFunctionState = BuildUnityDefaultFixedFunctionState(); + fixedFunctionState = BuildDefaultAuthoringFixedFunctionState(); } } -bool TryParseUnityStyleBoolDirectiveToken(const std::string& token, bool& outValue) { +bool TryParseAuthoringBoolDirectiveToken(const std::string& token, bool& outValue) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower(); if (normalized == "on") { outValue = true; @@ -43,7 +43,7 @@ bool TryParseUnityStyleBoolDirectiveToken(const std::string& token, bool& outVal return false; } -bool TryParseUnityStyleCullMode(const std::string& token, MaterialCullMode& outMode) { +bool TryParseAuthoringCullMode(const std::string& token, MaterialCullMode& outMode) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower(); if (normalized == "back") { outMode = MaterialCullMode::Back; @@ -60,7 +60,7 @@ bool TryParseUnityStyleCullMode(const std::string& token, MaterialCullMode& outM return false; } -bool TryParseUnityStyleComparisonFunc(const std::string& token, MaterialComparisonFunc& outFunc) { +bool TryParseAuthoringComparisonFunc(const std::string& token, MaterialComparisonFunc& outFunc) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower(); if (normalized == "never") { outFunc = MaterialComparisonFunc::Never; @@ -97,7 +97,7 @@ bool TryParseUnityStyleComparisonFunc(const std::string& token, MaterialComparis return false; } -bool TryParseUnityStyleBlendFactor(const std::string& token, MaterialBlendFactor& outFactor) { +bool TryParseAuthoringBlendFactor(const std::string& token, MaterialBlendFactor& outFactor) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToLower(); if (normalized == "zero") { outFactor = MaterialBlendFactor::Zero; @@ -146,7 +146,7 @@ bool TryParseUnityStyleBlendFactor(const std::string& token, MaterialBlendFactor return false; } -bool TryParseUnityStyleColorMask(const std::string& token, Core::uint8& outMask) { +bool TryParseAuthoringColorMask(const std::string& token, Core::uint8& outMask) { const Containers::String normalized = Containers::String(token.c_str()).Trim().ToUpper(); if (normalized == "0") { outMask = 0u; @@ -177,7 +177,7 @@ bool TryParseUnityStyleColorMask(const std::string& token, Core::uint8& outMask) return true; } -bool TryParseUnityStyleBlendDirective( +bool TryParseAuthoringBlendDirective( const std::vector& tokens, MaterialRenderState& outState) { std::vector normalizedTokens; @@ -204,7 +204,7 @@ bool TryParseUnityStyleBlendDirective( if (normalizedTokens.size() == 2u) { bool enabled = false; - if (!TryParseUnityStyleBoolDirectiveToken(normalizedTokens[1], enabled)) { + if (!TryParseAuthoringBoolDirectiveToken(normalizedTokens[1], enabled)) { return false; } @@ -220,8 +220,8 @@ bool TryParseUnityStyleBlendDirective( MaterialBlendFactor srcBlend = MaterialBlendFactor::One; MaterialBlendFactor dstBlend = MaterialBlendFactor::Zero; - if (!TryParseUnityStyleBlendFactor(normalizedTokens[1], srcBlend) || - !TryParseUnityStyleBlendFactor(normalizedTokens[2], dstBlend)) { + if (!TryParseAuthoringBlendFactor(normalizedTokens[1], srcBlend) || + !TryParseAuthoringBlendFactor(normalizedTokens[2], dstBlend)) { return false; } @@ -230,8 +230,8 @@ bool TryParseUnityStyleBlendDirective( outState.dstBlend = dstBlend; if (normalizedTokens.size() == 5u) { - if (!TryParseUnityStyleBlendFactor(normalizedTokens[3], outState.srcBlendAlpha) || - !TryParseUnityStyleBlendFactor(normalizedTokens[4], outState.dstBlendAlpha)) { + if (!TryParseAuthoringBlendFactor(normalizedTokens[3], outState.srcBlendAlpha) || + !TryParseAuthoringBlendFactor(normalizedTokens[4], outState.dstBlendAlpha)) { return false; } } else { diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringInternal.h b/engine/src/Resources/Shader/Internal/ShaderAuthoringInternal.h index 6e10297a..54bfb049 100644 --- a/engine/src/Resources/Shader/Internal/ShaderAuthoringInternal.h +++ b/engine/src/Resources/Shader/Internal/ShaderAuthoringInternal.h @@ -33,21 +33,17 @@ bool TryExtractProgramBlocks( std::vector& outBlocks, Containers::String* outError); -bool ContainsBackendPragma(const std::vector& lines); -bool ContainsResourcesBlock(const std::vector& lines); -bool ContainsSingleSourceAuthoringConstructs(const std::vector& lines); - -MaterialRenderState BuildUnityDefaultFixedFunctionState(); +MaterialRenderState BuildDefaultAuthoringFixedFunctionState(); void EnsureAuthoringFixedFunctionStateInitialized( bool& hasFixedFunctionState, MaterialRenderState& fixedFunctionState); -bool TryParseUnityStyleBoolDirectiveToken(const std::string& token, bool& outValue); -bool TryParseUnityStyleCullMode(const std::string& token, MaterialCullMode& outMode); -bool TryParseUnityStyleComparisonFunc(const std::string& token, MaterialComparisonFunc& outFunc); -bool TryParseUnityStyleBlendFactor(const std::string& token, MaterialBlendFactor& outFactor); -bool TryParseUnityStyleColorMask(const std::string& token, Core::uint8& outMask); -bool TryParseUnityStyleBlendDirective( +bool TryParseAuthoringBoolDirectiveToken(const std::string& token, bool& outValue); +bool TryParseAuthoringCullMode(const std::string& token, MaterialCullMode& outMode); +bool TryParseAuthoringComparisonFunc(const std::string& token, MaterialComparisonFunc& outFunc); +bool TryParseAuthoringBlendFactor(const std::string& token, MaterialBlendFactor& outFactor); +bool TryParseAuthoringColorMask(const std::string& token, Core::uint8& outMask); +bool TryParseAuthoringBlendDirective( const std::vector& tokens, MaterialRenderState& outState); @@ -66,9 +62,9 @@ void CollectQuotedIncludeDependencyPaths( std::unordered_set& seenPaths, Containers::Array& outDependencies); -bool IsUnityStyleAuthoringPragmaDirective(const std::string& line); +bool IsShaderAuthoringPragmaDirective(const std::string& line); -Containers::String StripUnityStyleAuthoringPragmas(const Containers::String& sourceText); +Containers::String StripShaderAuthoringPragmas(const Containers::String& sourceText); std::vector BuildShaderKeywordVariantSets( const Containers::Array& declarations); @@ -111,17 +107,7 @@ bool TryParseAuthoringPropertyLine( const std::string& line, ShaderPropertyDesc& outProperty); -bool TryParseAuthoringResourceLine( - const std::string& line, - ShaderResourceBindingDesc& outBinding); - -bool ParseLegacyBackendSplitShaderAuthoring( - const Containers::String& path, - const std::string& sourceText, - ShaderIR& outDesc, - Containers::String* outError); - -bool ParseUnityStyleSingleSourceShaderAuthoring( +bool ParseShaderAuthoring( const Containers::String& path, const std::string& sourceText, ShaderIR& outDesc, diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.cpp b/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.cpp index 88b180ef..493d1f95 100644 --- a/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.cpp +++ b/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.cpp @@ -9,11 +9,7 @@ namespace XCEngine { namespace Resources { -bool LooksLikeShaderAuthoring(const std::string& sourceText) { - return DetectShaderAuthoringStyle(sourceText) != ShaderAuthoringStyle::NotShaderAuthoring; -} - -bool CollectLegacyBackendSplitShaderDependencyPaths( +bool CollectShaderAuthoringDependencyPaths( const Containers::String& path, const std::string& sourceText, Containers::Array& outDependencies) { @@ -21,43 +17,7 @@ bool CollectLegacyBackendSplitShaderDependencyPaths( ShaderIR shaderIR = {}; Containers::String parseError; - if (!ParseLegacyBackendSplitShaderAuthoring(path, sourceText, shaderIR, &parseError)) { - return false; - } - - std::unordered_set seenPaths; - for (const ShaderSubShaderIR& subShader : shaderIR.subShaders) { - for (const ShaderPassIR& pass : subShader.passes) { - for (const ShaderBackendVariantIR& backendVariant : pass.backendVariants) { - const Containers::String resolvedVertexPath = - ResolveShaderDependencyPath(backendVariant.vertexSourcePath, path); - const std::string vertexKey = ToStdString(resolvedVertexPath); - if (!vertexKey.empty() && seenPaths.insert(vertexKey).second) { - outDependencies.PushBack(resolvedVertexPath); - } - - const Containers::String resolvedFragmentPath = - ResolveShaderDependencyPath(backendVariant.fragmentSourcePath, path); - const std::string fragmentKey = ToStdString(resolvedFragmentPath); - if (!fragmentKey.empty() && seenPaths.insert(fragmentKey).second) { - outDependencies.PushBack(resolvedFragmentPath); - } - } - } - } - - return true; -} - -bool CollectUnityStyleSingleSourceShaderDependencyPaths( - const Containers::String& path, - const std::string& sourceText, - Containers::Array& outDependencies) { - outDependencies.Clear(); - - ShaderIR shaderIR = {}; - Containers::String parseError; - if (!ParseUnityStyleSingleSourceShaderAuthoring(path, sourceText, shaderIR, &parseError)) { + if (!ParseShaderAuthoring(path, sourceText, shaderIR, &parseError)) { return false; } @@ -74,24 +34,12 @@ bool CollectUnityStyleSingleSourceShaderDependencyPaths( return true; } -LoadResult LoadLegacyBackendSplitShaderAuthoring( +LoadResult LoadShaderAuthoring( const Containers::String& path, const std::string& sourceText) { ShaderIR shaderIR = {}; Containers::String parseError; - if (!ParseLegacyBackendSplitShaderAuthoring(path, sourceText, shaderIR, &parseError)) { - return LoadResult(parseError); - } - - return BuildShaderFromIR(path, shaderIR); -} - -LoadResult LoadUnityStyleSingleSourceShaderAuthoring( - const Containers::String& path, - const std::string& sourceText) { - ShaderIR shaderIR = {}; - Containers::String parseError; - if (!ParseUnityStyleSingleSourceShaderAuthoring(path, sourceText, shaderIR, &parseError)) { + if (!ParseShaderAuthoring(path, sourceText, shaderIR, &parseError)) { return LoadResult(parseError); } diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.h b/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.h index ddb31561..13bad78d 100644 --- a/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.h +++ b/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.h @@ -9,23 +9,12 @@ namespace XCEngine { namespace Resources { -bool LooksLikeShaderAuthoring(const std::string& sourceText); - -bool CollectLegacyBackendSplitShaderDependencyPaths( +bool CollectShaderAuthoringDependencyPaths( const Containers::String& path, const std::string& sourceText, Containers::Array& outDependencies); -bool CollectUnityStyleSingleSourceShaderDependencyPaths( - const Containers::String& path, - const std::string& sourceText, - Containers::Array& outDependencies); - -LoadResult LoadLegacyBackendSplitShaderAuthoring( - const Containers::String& path, - const std::string& sourceText); - -LoadResult LoadUnityStyleSingleSourceShaderAuthoring( +LoadResult LoadShaderAuthoring( const Containers::String& path, const std::string& sourceText); diff --git a/engine/src/Resources/Shader/Internal/UnityStyleShaderAuthoringParser.cpp b/engine/src/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp similarity index 92% rename from engine/src/Resources/Shader/Internal/UnityStyleShaderAuthoringParser.cpp rename to engine/src/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp index 3c8ee4b2..8f1272ce 100644 --- a/engine/src/Resources/Shader/Internal/UnityStyleShaderAuthoringParser.cpp +++ b/engine/src/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp @@ -4,7 +4,7 @@ namespace XCEngine { namespace Resources { namespace Internal { -bool ParseUnityStyleSingleSourceShaderAuthoring( +bool ParseShaderAuthoring( const Containers::String& path, const std::string& sourceText, ShaderIR& outDesc, @@ -23,7 +23,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( auto fail = [&outError](const std::string& message, size_t lineNumber) -> bool { if (outError != nullptr) { *outError = Containers::String( - ("Unity-style shader parse error at line " + std::to_string(lineNumber) + ": " + message).c_str()); + ("shader authoring parse error at line " + std::to_string(lineNumber) + ": " + message).c_str()); } return false; }; @@ -97,7 +97,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( } if (pragmaTokens.size() >= 2u && pragmaTokens[1] == "backend") { - return fail("Unity-style single-source shaders must not use #pragma backend", humanLine); + return fail("shader authoring must not use #pragma backend", humanLine); } if (inSharedIncludeBlock) { @@ -130,7 +130,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( continue; } - return fail("unsupported pragma in Unity-style single-source shader", humanLine); + return fail("unsupported pragma in shader authoring", humanLine); } if (line == "{") { @@ -153,7 +153,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( currentSubShader->passes.emplace_back(); currentPass = ¤tSubShader->passes.back(); currentPass->hasFixedFunctionState = true; - currentPass->fixedFunctionState = BuildUnityDefaultFixedFunctionState(); + currentPass->fixedFunctionState = BuildDefaultAuthoringFixedFunctionState(); if (currentSubShader->hasFixedFunctionState) { currentPass->fixedFunctionState = currentSubShader->fixedFunctionState; } @@ -218,7 +218,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( } if (line == "Resources" || StartsWithKeyword(line, "Resources")) { - return fail("Unity-style single-source shaders must not declare Resources blocks", humanLine); + return fail("shader authoring must not declare Resources blocks", humanLine); } if (StartsWithKeyword(line, "Tags")) { @@ -258,7 +258,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( destination = ¤tSubShader->sharedProgramSource; } else { return fail( - "HLSLINCLUDE is only supported directly inside Shader or SubShader in the new authoring mode", + "HLSLINCLUDE is only supported directly inside Shader or SubShader", humanLine); } @@ -298,7 +298,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentSubShader->hasFixedFunctionState, currentSubShader->fixedFunctionState); - if (!TryParseUnityStyleCullMode(tokens[1], currentSubShader->fixedFunctionState.cullMode)) { + if (!TryParseAuthoringCullMode(tokens[1], currentSubShader->fixedFunctionState.cullMode)) { return fail("Cull directive must use Front, Back, or Off", humanLine); } continue; @@ -309,7 +309,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( bool enabled = false; if (!TryTokenizeQuotedArguments(line, tokens) || tokens.size() != 2u || - !TryParseUnityStyleBoolDirectiveToken(tokens[1], enabled)) { + !TryParseAuthoringBoolDirectiveToken(tokens[1], enabled)) { return fail("ZWrite directive must use On or Off", humanLine); } @@ -329,7 +329,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentSubShader->hasFixedFunctionState, currentSubShader->fixedFunctionState); - if (!TryParseUnityStyleComparisonFunc(tokens[1], currentSubShader->fixedFunctionState.depthFunc)) { + if (!TryParseAuthoringComparisonFunc(tokens[1], currentSubShader->fixedFunctionState.depthFunc)) { return fail("ZTest directive uses an unsupported compare function", humanLine); } currentSubShader->fixedFunctionState.depthTestEnable = true; @@ -351,7 +351,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentSubShader->hasFixedFunctionState, currentSubShader->fixedFunctionState); - if (!TryParseUnityStyleBlendDirective(tokens, currentSubShader->fixedFunctionState)) { + if (!TryParseAuthoringBlendDirective(tokens, currentSubShader->fixedFunctionState)) { return fail("Blend directive uses an unsupported factor combination", humanLine); } continue; @@ -367,7 +367,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentSubShader->hasFixedFunctionState, currentSubShader->fixedFunctionState); - if (!TryParseUnityStyleColorMask(tokens[1], currentSubShader->fixedFunctionState.colorWriteMask)) { + if (!TryParseAuthoringColorMask(tokens[1], currentSubShader->fixedFunctionState.colorWriteMask)) { return fail("ColorMask directive uses an unsupported channel mask", humanLine); } continue; @@ -393,7 +393,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentPass->hasFixedFunctionState, currentPass->fixedFunctionState); - if (!TryParseUnityStyleCullMode(tokens[1], currentPass->fixedFunctionState.cullMode)) { + if (!TryParseAuthoringCullMode(tokens[1], currentPass->fixedFunctionState.cullMode)) { return fail("Cull directive must use Front, Back, or Off", humanLine); } continue; @@ -404,7 +404,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( bool enabled = false; if (!TryTokenizeQuotedArguments(line, tokens) || tokens.size() != 2u || - !TryParseUnityStyleBoolDirectiveToken(tokens[1], enabled)) { + !TryParseAuthoringBoolDirectiveToken(tokens[1], enabled)) { return fail("ZWrite directive must use On or Off", humanLine); } @@ -424,7 +424,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentPass->hasFixedFunctionState, currentPass->fixedFunctionState); - if (!TryParseUnityStyleComparisonFunc(tokens[1], currentPass->fixedFunctionState.depthFunc)) { + if (!TryParseAuthoringComparisonFunc(tokens[1], currentPass->fixedFunctionState.depthFunc)) { return fail("ZTest directive uses an unsupported compare function", humanLine); } currentPass->fixedFunctionState.depthTestEnable = true; @@ -446,7 +446,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentPass->hasFixedFunctionState, currentPass->fixedFunctionState); - if (!TryParseUnityStyleBlendDirective(tokens, currentPass->fixedFunctionState)) { + if (!TryParseAuthoringBlendDirective(tokens, currentPass->fixedFunctionState)) { return fail("Blend directive uses an unsupported factor combination", humanLine); } continue; @@ -462,7 +462,7 @@ bool ParseUnityStyleSingleSourceShaderAuthoring( EnsureAuthoringFixedFunctionStateInitialized( currentPass->hasFixedFunctionState, currentPass->fixedFunctionState); - if (!TryParseUnityStyleColorMask(tokens[1], currentPass->fixedFunctionState.colorWriteMask)) { + if (!TryParseAuthoringColorMask(tokens[1], currentPass->fixedFunctionState.colorWriteMask)) { return fail("ColorMask directive uses an unsupported channel mask", humanLine); } continue; diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp b/engine/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp index 3c4db87d..063a52a6 100644 --- a/engine/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp +++ b/engine/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp @@ -76,7 +76,7 @@ void CollectQuotedIncludeDependencyPaths( } } -bool IsUnityStyleAuthoringPragmaDirective(const std::string& line) { +bool IsShaderAuthoringPragmaDirective(const std::string& line) { std::vector pragmaTokens; if (!TryTokenizeQuotedArguments(line, pragmaTokens) || pragmaTokens.empty() || @@ -95,14 +95,14 @@ bool IsUnityStyleAuthoringPragmaDirective(const std::string& line) { pragmaTokens[1] == "backend"; } -Containers::String StripUnityStyleAuthoringPragmas(const Containers::String& sourceText) { +Containers::String StripShaderAuthoringPragmas(const Containers::String& sourceText) { std::istringstream stream(ToStdString(sourceText)); std::string rawLine; std::string strippedSource; while (std::getline(stream, rawLine)) { const std::string normalizedLine = TrimCopy(StripAuthoringLineComment(rawLine)); - if (IsUnityStyleAuthoringPragmaDirective(normalizedLine)) { + if (IsShaderAuthoringPragmaDirective(normalizedLine)) { continue; } diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp b/engine/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp index 687de44b..d6a0b62b 100644 --- a/engine/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp +++ b/engine/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp @@ -103,7 +103,7 @@ bool TryExtractProgramBlocks( auto fail = [&outError](const std::string& message, size_t humanLine) -> bool { if (outError != nullptr) { *outError = Containers::String( - ("Unity-style shader parse error at line " + std::to_string(humanLine) + ": " + message).c_str()); + ("shader authoring parse error at line " + std::to_string(humanLine) + ": " + message).c_str()); } return false; }; @@ -148,40 +148,6 @@ bool TryExtractProgramBlocks( return true; } -bool ContainsBackendPragma(const std::vector& lines) { - for (const std::string& line : lines) { - if (line.rfind("#pragma backend", 0) == 0) { - return true; - } - } - - return false; -} - -bool ContainsResourcesBlock(const std::vector& lines) { - for (const std::string& line : lines) { - if (line == "Resources" || StartsWithKeyword(line, "Resources")) { - return true; - } - } - - return false; -} - -bool ContainsSingleSourceAuthoringConstructs(const std::vector& lines) { - for (const std::string& line : lines) { - if (line == "HLSLINCLUDE" || line == "CGINCLUDE") { - return true; - } - - if (line.rfind("#pragma target", 0) == 0) { - return true; - } - } - - return false; -} - size_t FindMatchingDelimiter( const std::string& text, size_t openPos, @@ -544,54 +510,6 @@ bool TryParseAuthoringPropertyLine( return true; } -bool TryParseAuthoringResourceLine( - const std::string& line, - ShaderResourceBindingDesc& outBinding) { - outBinding = {}; - - const size_t openParen = line.find('('); - if (openParen == std::string::npos) { - return false; - } - - const size_t closeParen = FindMatchingDelimiter(line, openParen, '(', ')'); - if (closeParen == std::string::npos) { - return false; - } - - outBinding.name = Containers::String(TrimCopy(line.substr(0, openParen)).c_str()); - if (outBinding.name.Empty()) { - return false; - } - - std::vector parts; - if (!SplitCommaSeparatedAuthoring(line.substr(openParen + 1, closeParen - openParen - 1), parts) || - parts.size() != 3u) { - return false; - } - - if (!TryParseShaderResourceType(parts[0].c_str(), outBinding.type)) { - return false; - } - - try { - outBinding.set = static_cast(std::stoul(parts[1])); - outBinding.binding = static_cast(std::stoul(parts[2])); - } catch (...) { - return false; - } - - const size_t attributePos = FindFirstTopLevelChar(line.substr(closeParen + 1), '['); - if (attributePos != std::string::npos) { - const std::string attributesText = line.substr(closeParen + 1 + attributePos); - if (!TryParseSemanticAttributes(attributesText, outBinding.semantic)) { - return false; - } - } - - return true; -} - } // namespace Internal } // namespace Resources } // namespace XCEngine diff --git a/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp b/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp index f2f9c23e..5eca0e37 100644 --- a/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp +++ b/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp @@ -135,66 +135,14 @@ LoadResult BuildShaderFromIR( shader->AddPassKeywordDeclaration(pass.name, keywordDeclaration); } - if (!pass.backendVariants.empty()) { - const std::vector keywordSets = - BuildShaderKeywordVariantSets(pass.keywordDeclarations); - for (const ShaderBackendVariantIR& backendVariant : pass.backendVariants) { - Containers::String vertexSourceCode; - ShaderStageVariant vertexVariant = {}; - vertexVariant.stage = ShaderType::Vertex; - vertexVariant.backend = backendVariant.backend; - vertexVariant.language = backendVariant.language; - vertexVariant.entryPoint = - backendVariant.language == ShaderLanguage::HLSL && !pass.vertexEntryPoint.Empty() - ? pass.vertexEntryPoint - : GetDefaultEntryPoint(backendVariant.language, ShaderType::Vertex); - vertexVariant.profile = !backendVariant.vertexProfile.Empty() - ? backendVariant.vertexProfile - : GetDefaultProfile(backendVariant.language, backendVariant.backend, ShaderType::Vertex); - - const Containers::String resolvedVertexPath = - ResolveShaderDependencyPath(backendVariant.vertexSourcePath, path); - if (!ReadShaderTextFile(resolvedVertexPath, vertexSourceCode)) { - return LoadResult("Failed to read shader authoring vertex source: " + resolvedVertexPath); - } - - Containers::String fragmentSourceCode; - ShaderStageVariant fragmentVariant = {}; - fragmentVariant.stage = ShaderType::Fragment; - fragmentVariant.backend = backendVariant.backend; - fragmentVariant.language = backendVariant.language; - fragmentVariant.entryPoint = - backendVariant.language == ShaderLanguage::HLSL && !pass.fragmentEntryPoint.Empty() - ? pass.fragmentEntryPoint - : GetDefaultEntryPoint(backendVariant.language, ShaderType::Fragment); - fragmentVariant.profile = !backendVariant.fragmentProfile.Empty() - ? backendVariant.fragmentProfile - : GetDefaultProfile(backendVariant.language, backendVariant.backend, ShaderType::Fragment); - - const Containers::String resolvedFragmentPath = - ResolveShaderDependencyPath(backendVariant.fragmentSourcePath, path); - if (!ReadShaderTextFile(resolvedFragmentPath, fragmentSourceCode)) { - return LoadResult("Failed to read shader authoring fragment source: " + resolvedFragmentPath); - } - - for (const ShaderKeywordSet& keywordSet : keywordSets) { - vertexVariant.requiredKeywords = keywordSet; - vertexVariant.sourceCode = BuildKeywordVariantSource(vertexSourceCode, keywordSet); - shader->AddPassVariant(pass.name, vertexVariant); - - fragmentVariant.requiredKeywords = keywordSet; - fragmentVariant.sourceCode = BuildKeywordVariantSource(fragmentSourceCode, keywordSet); - shader->AddPassVariant(pass.name, fragmentVariant); - } - } - } else if (!pass.programSource.Empty()) { + if (!pass.programSource.Empty()) { Containers::String combinedSource; AppendAuthoringSourceBlock(combinedSource, shaderIR.sharedProgramSource); AppendAuthoringSourceBlock(combinedSource, subShader.sharedProgramSource); AppendAuthoringSourceBlock(combinedSource, pass.sharedProgramSource); AppendAuthoringSourceBlock(combinedSource, pass.programSource); const Containers::String strippedCombinedSource = - StripUnityStyleAuthoringPragmas(combinedSource); + StripShaderAuthoringPragmas(combinedSource); const std::vector keywordSets = BuildShaderKeywordVariantSets(pass.keywordDeclarations); diff --git a/engine/src/Resources/Shader/ShaderAuthoringParser.cpp b/engine/src/Resources/Shader/ShaderAuthoringParser.cpp index 6ba4d6fc..6c7eddad 100644 --- a/engine/src/Resources/Shader/ShaderAuthoringParser.cpp +++ b/engine/src/Resources/Shader/ShaderAuthoringParser.cpp @@ -5,25 +5,10 @@ namespace XCEngine { namespace Resources { -ShaderAuthoringStyle DetectShaderAuthoringStyle(const std::string& sourceText) { +bool LooksLikeShaderAuthoring(const std::string& sourceText) { std::vector lines; Internal::SplitShaderAuthoringLines(sourceText, lines); - if (lines.empty() || !Internal::StartsWithKeyword(lines.front(), "Shader")) { - return ShaderAuthoringStyle::NotShaderAuthoring; - } - - const bool hasBackendPragma = Internal::ContainsBackendPragma(lines); - const bool hasSingleSourceConstructs = Internal::ContainsSingleSourceAuthoringConstructs(lines); - - if (hasBackendPragma && !hasSingleSourceConstructs) { - return ShaderAuthoringStyle::LegacyBackendSplit; - } - - if (Internal::ContainsResourcesBlock(lines) || hasSingleSourceConstructs) { - return ShaderAuthoringStyle::UnityStyleSingleSource; - } - - return ShaderAuthoringStyle::UnityStyleSingleSource; + return !lines.empty() && Internal::StartsWithKeyword(lines.front(), "Shader"); } void AppendAuthoringSourceBlock( @@ -40,8 +25,8 @@ void CollectQuotedIncludeDependencyPaths( Internal::CollectQuotedIncludeDependencyPaths(sourcePath, sourceText, seenPaths, outDependencies); } -Containers::String StripUnityStyleAuthoringPragmas(const Containers::String& sourceText) { - return Internal::StripUnityStyleAuthoringPragmas(sourceText); +Containers::String StripShaderAuthoringPragmas(const Containers::String& sourceText) { + return Internal::StripShaderAuthoringPragmas(sourceText); } std::vector BuildShaderKeywordVariantSets( @@ -55,20 +40,12 @@ Containers::String BuildKeywordVariantSource( return Internal::BuildKeywordVariantSource(baseSource, requiredKeywords); } -bool ParseLegacyBackendSplitShaderAuthoring( +bool ParseShaderAuthoring( const Containers::String& path, const std::string& sourceText, ShaderIR& outDesc, Containers::String* outError) { - return Internal::ParseLegacyBackendSplitShaderAuthoring(path, sourceText, outDesc, outError); -} - -bool ParseUnityStyleSingleSourceShaderAuthoring( - const Containers::String& path, - const std::string& sourceText, - ShaderIR& outDesc, - Containers::String* outError) { - return Internal::ParseUnityStyleSingleSourceShaderAuthoring(path, sourceText, outDesc, outError); + return Internal::ParseShaderAuthoring(path, sourceText, outDesc, outError); } } // namespace Resources diff --git a/engine/src/Resources/Shader/ShaderAuthoringParser.h b/engine/src/Resources/Shader/ShaderAuthoringParser.h index 6933bdbd..ce52e7a2 100644 --- a/engine/src/Resources/Shader/ShaderAuthoringParser.h +++ b/engine/src/Resources/Shader/ShaderAuthoringParser.h @@ -9,12 +9,6 @@ namespace XCEngine { namespace Resources { -enum class ShaderAuthoringStyle { - NotShaderAuthoring = 0, - LegacyBackendSplit, - UnityStyleSingleSource -}; - void AppendAuthoringSourceBlock( Containers::String& target, const Containers::String& sourceBlock); @@ -25,7 +19,7 @@ void CollectQuotedIncludeDependencyPaths( std::unordered_set& seenPaths, Containers::Array& outDependencies); -Containers::String StripUnityStyleAuthoringPragmas(const Containers::String& sourceText); +Containers::String StripShaderAuthoringPragmas(const Containers::String& sourceText); std::vector BuildShaderKeywordVariantSets( const Containers::Array& declarations); @@ -34,15 +28,9 @@ Containers::String BuildKeywordVariantSource( const Containers::String& baseSource, const ShaderKeywordSet& requiredKeywords); -ShaderAuthoringStyle DetectShaderAuthoringStyle(const std::string& sourceText); +bool LooksLikeShaderAuthoring(const std::string& sourceText); -bool ParseLegacyBackendSplitShaderAuthoring( - const Containers::String& path, - const std::string& sourceText, - ShaderIR& outDesc, - Containers::String* outError); - -bool ParseUnityStyleSingleSourceShaderAuthoring( +bool ParseShaderAuthoring( const Containers::String& path, const std::string& sourceText, ShaderIR& outDesc, diff --git a/engine/src/Resources/Shader/ShaderIR.h b/engine/src/Resources/Shader/ShaderIR.h index d563753b..c6623fb6 100644 --- a/engine/src/Resources/Shader/ShaderIR.h +++ b/engine/src/Resources/Shader/ShaderIR.h @@ -14,15 +14,6 @@ struct ShaderTagIR { Containers::String value; }; -struct ShaderBackendVariantIR { - ShaderBackend backend = ShaderBackend::Generic; - ShaderLanguage language = ShaderLanguage::GLSL; - Containers::String vertexSourcePath; - Containers::String fragmentSourcePath; - Containers::String vertexProfile; - Containers::String fragmentProfile; -}; - struct ShaderPassIR { Containers::String name; bool hasFixedFunctionState = false; @@ -35,7 +26,6 @@ struct ShaderPassIR { Containers::String sharedProgramSource; Containers::String programSource; Containers::String targetProfile; - std::vector backendVariants; }; struct ShaderSubShaderIR { diff --git a/engine/src/Resources/Shader/ShaderLoader.cpp b/engine/src/Resources/Shader/ShaderLoader.cpp index e47a8bb2..f57b6b0a 100644 --- a/engine/src/Resources/Shader/ShaderLoader.cpp +++ b/engine/src/Resources/Shader/ShaderLoader.cpp @@ -64,16 +64,8 @@ LoadResult ShaderLoader::Load(const Containers::String& path, const ImportSettin if (ext == "shader" && LooksLikeShaderManifest(sourceText)) { return LoadShaderManifest(path, sourceText); } - if (ext == "shader") { - switch (DetectShaderAuthoringStyle(sourceText)) { - case ShaderAuthoringStyle::LegacyBackendSplit: - return LoadLegacyBackendSplitShaderAuthoring(path, sourceText); - case ShaderAuthoringStyle::UnityStyleSingleSource: - return LoadUnityStyleSingleSourceShaderAuthoring(path, sourceText); - case ShaderAuthoringStyle::NotShaderAuthoring: - default: - break; - } + if (ext == "shader" && LooksLikeShaderAuthoring(sourceText)) { + return LoadShaderAuthoring(path, sourceText); } return LoadLegacySingleStageShader(path, sourceText); @@ -104,15 +96,9 @@ bool ShaderLoader::CollectSourceDependencies( const std::string sourceText = ToStdStringFromBytes(data); if (!LooksLikeShaderManifest(sourceText)) { - switch (DetectShaderAuthoringStyle(sourceText)) { - case ShaderAuthoringStyle::LegacyBackendSplit: - return CollectLegacyBackendSplitShaderDependencyPaths(path, sourceText, outDependencies); - case ShaderAuthoringStyle::UnityStyleSingleSource: - return CollectUnityStyleSingleSourceShaderDependencyPaths(path, sourceText, outDependencies); - case ShaderAuthoringStyle::NotShaderAuthoring: - default: - return true; - } + return LooksLikeShaderAuthoring(sourceText) + ? CollectShaderAuthoringDependencyPaths(path, sourceText, outDependencies) + : true; } return CollectShaderManifestDependencyPaths(path, sourceText, outDependencies); diff --git a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp index eca3f7e4..2eac9b81 100644 --- a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp +++ b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp @@ -111,7 +111,7 @@ TEST(BuiltinForwardPipeline_Test, SplitsSceneItemsIntoOpaqueAndTransparentQueueR EXPECT_TRUE(IsTransparentRenderQueue(static_cast(MaterialRenderQueue::Overlay))); } -TEST(BuiltinForwardPipeline_Test, BuiltinForwardShaderUsesUnityStyleSingleSourceSurfaceContract) { +TEST(BuiltinForwardPipeline_Test, BuiltinForwardShaderUsesAuthoringSurfaceContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinForwardLitShaderPath()); ASSERT_TRUE(result); @@ -145,7 +145,7 @@ TEST(BuiltinForwardPipeline_Test, BuiltinForwardShaderUsesUnityStyleSingleSource delete shader; } -TEST(BuiltinForwardPipeline_Test, BuiltinUnlitShaderUsesUnityStyleSingleSourceSurfaceContract) { +TEST(BuiltinForwardPipeline_Test, BuiltinUnlitShaderUsesAuthoringSurfaceContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinUnlitShaderPath()); ASSERT_TRUE(result); @@ -211,7 +211,7 @@ TEST(BuiltinForwardPipeline_Test, BuiltinUnlitShaderBuildsVulkanRuntimeSourceWit delete shader; } -TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesUnityStyleUnlitBindingsToDescriptorSpaces) { +TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesAuthoringUnlitBindingsToDescriptorSpaces) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinUnlitShaderPath()); ASSERT_TRUE(result); @@ -278,7 +278,7 @@ TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesUnityStyleUnli delete shader; } -TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesUnityStyleForwardBindingsToDescriptorSpaces) { +TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesAuthoringForwardBindingsToDescriptorSpaces) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinForwardLitShaderPath()); ASSERT_TRUE(result); @@ -591,7 +591,7 @@ TEST(BuiltinDepthStylePass_Test, OpenGLRuntimeTranspilesShadowCasterAlphaVariant delete shader; } -TEST(BuiltinForwardPipeline_Test, BuiltinSkyboxShaderUsesUnityStyleSingleSourceContract) { +TEST(BuiltinForwardPipeline_Test, BuiltinSkyboxShaderUsesAuthoringContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinSkyboxShaderPath()); ASSERT_TRUE(result); @@ -663,7 +663,7 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromImplic delete shader; } -TEST(BuiltinForwardPipeline_Test, BuiltinFinalColorShaderUsesUnityStyleSingleSourceContract) { +TEST(BuiltinForwardPipeline_Test, BuiltinFinalColorShaderUsesAuthoringContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); ASSERT_TRUE(result); @@ -724,7 +724,7 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromImplic delete shader; } -TEST(BuiltinForwardPipeline_Test, BuiltinColorScalePostProcessShaderUsesUnityStyleSingleSourceContract) { +TEST(BuiltinForwardPipeline_Test, BuiltinColorScalePostProcessShaderUsesAuthoringContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); ASSERT_TRUE(result); @@ -773,7 +773,7 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromImplic delete shader; } -TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesUnityStyleFinalColorBindingsToDescriptorSpaces) { +TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesAuthoringFinalColorBindingsToDescriptorSpaces) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); ASSERT_TRUE(result); @@ -899,7 +899,7 @@ TEST(BuiltinForwardPipeline_Test, OpenGLRuntimeTranspilesFinalColorVariantToComb delete shader; } -TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesUnityStyleColorScaleBindingsToDescriptorSpaces) { +TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesAuthoringColorScaleBindingsToDescriptorSpaces) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); ASSERT_TRUE(result); @@ -1198,7 +1198,7 @@ TEST(BuiltinPassLayout_Test, BuildsSharedSetLayoutsFromImplicitForwardResources) delete shader; } -TEST(BuiltinDepthStylePass_Test, BuiltinDepthOnlyShaderUsesUnityStyleSingleSourceContract) { +TEST(BuiltinDepthStylePass_Test, BuiltinDepthOnlyShaderUsesAuthoringContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinDepthOnlyShaderPath()); ASSERT_TRUE(result); @@ -1218,7 +1218,7 @@ TEST(BuiltinDepthStylePass_Test, BuiltinDepthOnlyShaderUsesUnityStyleSingleSourc delete shader; } -TEST(BuiltinDepthStylePass_Test, BuiltinShadowCasterShaderUsesUnityStyleSingleSourceContract) { +TEST(BuiltinDepthStylePass_Test, BuiltinShadowCasterShaderUsesAuthoringContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinShadowCasterShaderPath()); ASSERT_TRUE(result); @@ -1238,7 +1238,7 @@ TEST(BuiltinDepthStylePass_Test, BuiltinShadowCasterShaderUsesUnityStyleSingleSo delete shader; } -TEST(BuiltinObjectIdPass_Test, BuiltinObjectIdShaderUsesUnityStyleSingleSourceContract) { +TEST(BuiltinObjectIdPass_Test, BuiltinObjectIdShaderUsesAuthoringContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinObjectIdShaderPath()); ASSERT_TRUE(result); diff --git a/tests/Rendering/unit/test_render_scene_extractor.cpp b/tests/Rendering/unit/test_render_scene_extractor.cpp index 1cc4f52d..38b10253 100644 --- a/tests/Rendering/unit/test_render_scene_extractor.cpp +++ b/tests/Rendering/unit/test_render_scene_extractor.cpp @@ -788,7 +788,7 @@ TEST(RenderMaterialUtility_Test, ShaderPassFixedFunctionStateIsUsedBeforeLegacyM EXPECT_EQ(effectiveState.depthFunc, MaterialComparisonFunc::Less); } -TEST(RenderMaterialUtility_Test, ShaderPassQueueTagResolvesUnityStyleRenderQueue) { +TEST(RenderMaterialUtility_Test, ShaderPassQueueTagResolvesAuthoringRenderQueue) { ShaderPass shaderPass = {}; shaderPass.tags.PushBack({ "Queue", "Transparent" }); diff --git a/tests/Resources/Shader/test_shader_loader.cpp b/tests/Resources/Shader/test_shader_loader.cpp index 88cd3da2..b7814af4 100644 --- a/tests/Resources/Shader/test_shader_loader.cpp +++ b/tests/Resources/Shader/test_shader_loader.cpp @@ -251,151 +251,6 @@ TEST(ShaderLoader, LoadShaderManifestBuildsMultiPassBackendVariants) { fs::remove_all(shaderRoot); } -TEST(ShaderLoader, LoadLegacyBackendSplitShaderAuthoringBuildsRuntimeContract) { - namespace fs = std::filesystem; - - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_test"; - const fs::path stageRoot = shaderRoot / "stages"; - const fs::path shaderPath = shaderRoot / "multi_pass.shader"; - - fs::remove_all(shaderRoot); - fs::create_directories(stageRoot); - - WriteTextFile(stageRoot / "forward_lit.vs.hlsl", "float4 MainVS() : SV_POSITION { return 0; } // AUTHORING_FORWARD_LIT_D3D12_VS\n"); - WriteTextFile(stageRoot / "forward_lit.ps.hlsl", "float4 MainPS() : SV_TARGET { return 1; } // AUTHORING_FORWARD_LIT_D3D12_PS\n"); - WriteTextFile(stageRoot / "forward_lit.vert.glsl", "#version 430\n// AUTHORING_FORWARD_LIT_GL_VS\nvoid main() {}\n"); - WriteTextFile(stageRoot / "forward_lit.frag.glsl", "#version 430\n// AUTHORING_FORWARD_LIT_GL_PS\nvoid main() {}\n"); - WriteTextFile(stageRoot / "forward_lit.vert.vk.glsl", "#version 450\n// AUTHORING_FORWARD_LIT_VK_VS\nvoid main() {}\n"); - WriteTextFile(stageRoot / "forward_lit.frag.vk.glsl", "#version 450\n// AUTHORING_FORWARD_LIT_VK_PS\nvoid main() {}\n"); - WriteTextFile(stageRoot / "depth_only.vs.hlsl", "float4 MainVS() : SV_POSITION { return 0; } // AUTHORING_DEPTH_ONLY_D3D12_VS\n"); - WriteTextFile(stageRoot / "depth_only.ps.hlsl", "float4 MainPS() : SV_TARGET { return 1; } // AUTHORING_DEPTH_ONLY_D3D12_PS\n"); - - WriteTextFile( - shaderPath, - R"(Shader "AuthoringLit" -{ - Properties - { - _BaseColor ("Base Color", Color) = (1,1,1,1) [Semantic(BaseColor)] - _MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)] - } - SubShader - { - Tags { "Queue" = "Geometry" } - Pass - { - Name "ForwardLit" - Tags { "LightMode" = "ForwardBase" } - Resources - { - PerObjectConstants (ConstantBuffer, 1, 0) [Semantic(PerObject)] - LightingConstants (ConstantBuffer, 2, 0) [Semantic(Lighting)] - MaterialConstants (ConstantBuffer, 3, 0) [Semantic(Material)] - ShadowReceiverConstants (ConstantBuffer, 4, 0) [Semantic(ShadowReceiver)] - BaseColorTexture (Texture2D, 5, 0) [Semantic(BaseColorTexture)] - LinearClampSampler (Sampler, 6, 0) [Semantic(LinearClampSampler)] - ShadowMapTexture (Texture2D, 7, 0) [Semantic(ShadowMapTexture)] - ShadowMapSampler (Sampler, 8, 0) [Semantic(ShadowMapSampler)] - } - HLSLPROGRAM - #pragma vertex MainVS - #pragma fragment MainPS - #pragma backend D3D12 HLSL "stages/forward_lit.vs.hlsl" "stages/forward_lit.ps.hlsl" vs_5_0 ps_5_0 - #pragma backend OpenGL GLSL "stages/forward_lit.vert.glsl" "stages/forward_lit.frag.glsl" - #pragma backend Vulkan GLSL "stages/forward_lit.vert.vk.glsl" "stages/forward_lit.frag.vk.glsl" - ENDHLSL - } - Pass - { - Name "DepthOnly" - Tags { "LightMode" = "DepthOnly" } - HLSLPROGRAM - #pragma vertex MainVS - #pragma fragment MainPS - #pragma backend D3D12 HLSL "stages/depth_only.vs.hlsl" "stages/depth_only.ps.hlsl" - ENDHLSL - } - } -} -)"); - - ShaderLoader loader; - LoadResult result = loader.Load(shaderPath.string().c_str()); - ASSERT_TRUE(result); - ASSERT_NE(result.resource, nullptr); - - Shader* shader = static_cast(result.resource); - ASSERT_NE(shader, nullptr); - ASSERT_TRUE(shader->IsValid()); - EXPECT_EQ(shader->GetName(), "AuthoringLit"); - ASSERT_EQ(shader->GetProperties().Size(), 2u); - ASSERT_EQ(shader->GetPassCount(), 2u); - - const ShaderPropertyDesc* baseColorProperty = shader->FindProperty("_BaseColor"); - ASSERT_NE(baseColorProperty, nullptr); - EXPECT_EQ(baseColorProperty->displayName, "Base Color"); - EXPECT_EQ(baseColorProperty->type, ShaderPropertyType::Color); - EXPECT_EQ(baseColorProperty->defaultValue, "(1,1,1,1)"); - EXPECT_EQ(baseColorProperty->semantic, "BaseColor"); - - const ShaderPropertyDesc* baseMapProperty = shader->FindProperty("_MainTex"); - ASSERT_NE(baseMapProperty, nullptr); - EXPECT_EQ(baseMapProperty->type, ShaderPropertyType::Texture2D); - EXPECT_EQ(baseMapProperty->defaultValue, "white"); - EXPECT_EQ(baseMapProperty->semantic, "BaseColorTexture"); - - const ShaderPass* forwardLitPass = shader->FindPass("ForwardLit"); - ASSERT_NE(forwardLitPass, nullptr); - ASSERT_EQ(forwardLitPass->tags.Size(), 2u); - ASSERT_EQ(forwardLitPass->resources.Size(), 8u); - EXPECT_EQ(forwardLitPass->tags[0].name, "Queue"); - EXPECT_EQ(forwardLitPass->tags[0].value, "Geometry"); - EXPECT_EQ(forwardLitPass->tags[1].name, "LightMode"); - EXPECT_EQ(forwardLitPass->tags[1].value, "ForwardBase"); - - const ShaderResourceBindingDesc* baseTextureBinding = - shader->FindPassResourceBinding("ForwardLit", "BaseColorTexture"); - ASSERT_NE(baseTextureBinding, nullptr); - EXPECT_EQ(baseTextureBinding->type, ShaderResourceType::Texture2D); - EXPECT_EQ(baseTextureBinding->set, 5u); - EXPECT_EQ(baseTextureBinding->binding, 0u); - EXPECT_EQ(baseTextureBinding->semantic, "BaseColorTexture"); - - const ShaderStageVariant* d3d12Vertex = - shader->FindVariant("ForwardLit", ShaderType::Vertex, ShaderBackend::D3D12); - ASSERT_NE(d3d12Vertex, nullptr); - EXPECT_EQ(d3d12Vertex->entryPoint, "MainVS"); - EXPECT_EQ(d3d12Vertex->profile, "vs_5_0"); - EXPECT_NE(std::string(d3d12Vertex->sourceCode.CStr()).find("AUTHORING_FORWARD_LIT_D3D12_VS"), std::string::npos); - - const ShaderStageVariant* openglFragment = - shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::OpenGL); - ASSERT_NE(openglFragment, nullptr); - EXPECT_EQ(openglFragment->entryPoint, "main"); - EXPECT_EQ(openglFragment->profile, "fs_4_30"); - EXPECT_NE(std::string(openglFragment->sourceCode.CStr()).find("AUTHORING_FORWARD_LIT_GL_PS"), std::string::npos); - - const ShaderStageVariant* vulkanFragment = - shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::Vulkan); - ASSERT_NE(vulkanFragment, nullptr); - EXPECT_EQ(vulkanFragment->entryPoint, "main"); - EXPECT_EQ(vulkanFragment->profile, "fs_4_50"); - EXPECT_NE(std::string(vulkanFragment->sourceCode.CStr()).find("AUTHORING_FORWARD_LIT_VK_PS"), std::string::npos); - - const ShaderPass* depthOnlyPass = shader->FindPass("DepthOnly"); - ASSERT_NE(depthOnlyPass, nullptr); - ASSERT_EQ(depthOnlyPass->tags.Size(), 2u); - EXPECT_EQ(depthOnlyPass->tags[0].name, "Queue"); - EXPECT_EQ(depthOnlyPass->tags[0].value, "Geometry"); - EXPECT_EQ(depthOnlyPass->tags[1].name, "LightMode"); - EXPECT_EQ(depthOnlyPass->tags[1].value, "DepthOnly"); - EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); - EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); - - delete shader; - fs::remove_all(shaderRoot); -} - TEST(ShaderLoader, LoadShaderManifestParsesVariantKeywordsAndKeywordAwareLookup) { namespace fs = std::filesystem; @@ -456,137 +311,12 @@ TEST(ShaderLoader, LoadShaderManifestParsesVariantKeywordsAndKeywordAwareLookup) fs::remove_all(shaderRoot); } -TEST(ShaderLoader, LoadLegacyBackendSplitShaderAuthoringExpandsKeywordVariantsPerBackend) { +TEST(ShaderLoader, LoadShaderAuthoringBuildsGenericHlslVariants) { namespace fs = std::filesystem; - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_legacy_keyword_variants"; - const fs::path stageRoot = shaderRoot / "stages"; - const fs::path shaderPath = shaderRoot / "keyword_variants.shader"; - - fs::remove_all(shaderRoot); - fs::create_directories(stageRoot); - - WriteTextFile( - stageRoot / "keyword_test.vs.hlsl", - "float4 MainVS() : SV_POSITION { return 0; } // LEGACY_KEYWORD_D3D12_VS\n"); - WriteTextFile( - stageRoot / "keyword_test.ps.hlsl", - "float4 MainPS() : SV_TARGET { return 1; } // LEGACY_KEYWORD_D3D12_PS\n"); - WriteTextFile( - stageRoot / "keyword_test.vert.glsl", - "#version 430\n// LEGACY_KEYWORD_GL_VS\nvoid main() {}\n"); - WriteTextFile( - stageRoot / "keyword_test.frag.glsl", - "#version 430\n// LEGACY_KEYWORD_GL_PS\nvoid main() {}\n"); - - WriteTextFile( - shaderPath, - R"(Shader "LegacyKeywordVariants" -{ - SubShader - { - Pass - { - Name "ForwardLit" - HLSLPROGRAM - #pragma vertex MainVS - #pragma fragment MainPS - #pragma multi_compile _ XC_MAIN_LIGHT_SHADOWS - #pragma multi_compile_local _ XC_ALPHA_TEST - #pragma backend D3D12 HLSL "stages/keyword_test.vs.hlsl" "stages/keyword_test.ps.hlsl" vs_5_0 ps_5_0 - #pragma backend OpenGL GLSL "stages/keyword_test.vert.glsl" "stages/keyword_test.frag.glsl" - ENDHLSL - } - } -} -)"); - - ShaderLoader loader; - LoadResult result = loader.Load(shaderPath.string().c_str()); - ASSERT_TRUE(result); - ASSERT_NE(result.resource, nullptr); - - auto* shader = static_cast(result.resource); - ASSERT_NE(shader, nullptr); - ASSERT_TRUE(shader->IsValid()); - EXPECT_EQ(shader->GetName(), "LegacyKeywordVariants"); - - const ShaderPass* pass = shader->FindPass("ForwardLit"); - ASSERT_NE(pass, nullptr); - ASSERT_EQ(pass->keywordDeclarations.Size(), 2u); - EXPECT_EQ(pass->keywordDeclarations[0].type, ShaderKeywordDeclarationType::MultiCompile); - EXPECT_EQ(pass->keywordDeclarations[1].type, ShaderKeywordDeclarationType::MultiCompileLocal); - EXPECT_TRUE(pass->keywordDeclarations[1].IsLocal()); - EXPECT_TRUE(shader->PassDeclaresKeyword("ForwardLit", "XC_MAIN_LIGHT_SHADOWS")); - EXPECT_TRUE(shader->PassDeclaresKeyword("ForwardLit", "XC_ALPHA_TEST")); - ASSERT_EQ(pass->variants.Size(), 16u); - - const ShaderStageVariant* baseD3D12Fragment = - shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::D3D12); - ASSERT_NE(baseD3D12Fragment, nullptr); - EXPECT_EQ(baseD3D12Fragment->requiredKeywords.enabledKeywords.Size(), 0u); - EXPECT_NE( - std::string(baseD3D12Fragment->sourceCode.CStr()).find("LEGACY_KEYWORD_D3D12_PS"), - std::string::npos); - EXPECT_EQ( - std::string(baseD3D12Fragment->sourceCode.CStr()).find("#define XC_MAIN_LIGHT_SHADOWS 1"), - std::string::npos); - - ShaderKeywordSet enabledKeywords = {}; - enabledKeywords.enabledKeywords.PushBack("XC_ALPHA_TEST"); - enabledKeywords.enabledKeywords.PushBack("XC_MAIN_LIGHT_SHADOWS"); - - const ShaderStageVariant* keywordD3D12Fragment = - shader->FindVariant( - "ForwardLit", - ShaderType::Fragment, - ShaderBackend::D3D12, - enabledKeywords); - ASSERT_NE(keywordD3D12Fragment, nullptr); - ASSERT_EQ(keywordD3D12Fragment->requiredKeywords.enabledKeywords.Size(), 2u); - EXPECT_EQ(keywordD3D12Fragment->requiredKeywords.enabledKeywords[0], "XC_ALPHA_TEST"); - EXPECT_EQ(keywordD3D12Fragment->requiredKeywords.enabledKeywords[1], "XC_MAIN_LIGHT_SHADOWS"); - EXPECT_NE( - std::string(keywordD3D12Fragment->sourceCode.CStr()).find("#define XC_ALPHA_TEST 1"), - std::string::npos); - EXPECT_NE( - std::string(keywordD3D12Fragment->sourceCode.CStr()).find("#define XC_MAIN_LIGHT_SHADOWS 1"), - std::string::npos); - EXPECT_NE( - std::string(keywordD3D12Fragment->sourceCode.CStr()).find("LEGACY_KEYWORD_D3D12_PS"), - std::string::npos); - - const ShaderStageVariant* keywordOpenGLFragment = - shader->FindVariant( - "ForwardLit", - ShaderType::Fragment, - ShaderBackend::OpenGL, - enabledKeywords); - ASSERT_NE(keywordOpenGLFragment, nullptr); - EXPECT_EQ(keywordOpenGLFragment->entryPoint, "main"); - EXPECT_EQ(keywordOpenGLFragment->profile, "fs_4_30"); - const std::string keywordOpenGLSource = keywordOpenGLFragment->sourceCode.CStr(); - EXPECT_NE( - keywordOpenGLSource.find("#define XC_ALPHA_TEST 1"), - std::string::npos); - EXPECT_NE(keywordOpenGLSource.find("#version 430"), std::string::npos); - EXPECT_LT( - keywordOpenGLSource.find("#version 430"), - keywordOpenGLSource.find("#define XC_ALPHA_TEST 1")); - EXPECT_NE( - keywordOpenGLSource.find("LEGACY_KEYWORD_GL_PS"), - std::string::npos); - - delete shader; - fs::remove_all(shaderRoot); -} - -TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringBuildsGenericHlslVariants) { - namespace fs = std::filesystem; - - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_single_source_test"; + const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_test"; const fs::path includeRoot = shaderRoot / "shaderlib"; - const fs::path shaderPath = shaderRoot / "single_source.shader"; + const fs::path shaderPath = shaderRoot / "authoring.shader"; fs::remove_all(shaderRoot); fs::create_directories(includeRoot); @@ -599,7 +329,7 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringBuildsGenericHlslVar WriteTextFile( shaderPath, - R"(Shader "SingleSourceLit" + R"(Shader "AuthoringLit" { Properties { @@ -648,7 +378,7 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringBuildsGenericHlslVar Shader* shader = static_cast(result.resource); ASSERT_NE(shader, nullptr); ASSERT_TRUE(shader->IsValid()); - EXPECT_EQ(shader->GetName(), "SingleSourceLit"); + EXPECT_EQ(shader->GetName(), "AuthoringLit"); ASSERT_EQ(shader->GetProperties().Size(), 1u); ASSERT_EQ(shader->GetPassCount(), 1u); @@ -724,18 +454,18 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringBuildsGenericHlslVar fs::remove_all(shaderRoot); } -TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringParsesPassStateAndFallback) { +TEST(ShaderLoader, LoadShaderAuthoringParsesPassStateAndFallback) { namespace fs = std::filesystem; - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_single_source_pass_state"; - const fs::path shaderPath = shaderRoot / "single_source_state.shader"; + const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_pass_state"; + const fs::path shaderPath = shaderRoot / "authoring_state.shader"; fs::remove_all(shaderRoot); fs::create_directories(shaderRoot); WriteTextFile( shaderPath, - R"(Shader "SingleSourceStateful" + R"(Shader "AuthoringStateful" { Fallback "Legacy/Diffuse" SubShader @@ -786,19 +516,19 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringParsesPassStateAndFa fs::remove_all(shaderRoot); } -TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromSingleSourceAuthoringPreservesPassStateAndFallback) { +TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromAuthoringPreservesPassStateAndFallback) { namespace fs = std::filesystem; - const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_single_source_artifact_pass_state"; + const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_authoring_artifact_pass_state"; const fs::path shaderDir = projectRoot / "Assets" / "Shaders"; - const fs::path shaderPath = shaderDir / "single_source_state.shader"; + const fs::path shaderPath = shaderDir / "authoring_state.shader"; fs::remove_all(projectRoot); fs::create_directories(shaderDir); WriteTextFile( shaderPath, - R"(Shader "ArtifactSingleSourceStateful" + R"(Shader "ArtifactAuthoringStateful" { Fallback "Legacy/Cutout" SubShader @@ -825,7 +555,7 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromSingleSourceAuthoringPr database.Initialize(projectRoot.string().c_str()); AssetDatabase::ResolvedAsset resolvedAsset; - ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/single_source_state.shader", ResourceType::Shader, resolvedAsset)); + ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/authoring_state.shader", ResourceType::Shader, resolvedAsset)); ASSERT_TRUE(resolvedAsset.artifactReady); ShaderLoader loader; @@ -852,18 +582,18 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromSingleSourceAuthoringPr fs::remove_all(projectRoot); } -TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringParsesMultiCompileLocalKeywords) { +TEST(ShaderLoader, LoadShaderAuthoringParsesMultiCompileLocalKeywords) { namespace fs = std::filesystem; - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_single_source_multi_compile_local"; - const fs::path shaderPath = shaderRoot / "single_source_multi_compile_local.shader"; + const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_multi_compile_local"; + const fs::path shaderPath = shaderRoot / "authoring_multi_compile_local.shader"; fs::remove_all(shaderRoot); fs::create_directories(shaderRoot); WriteTextFile( shaderPath, - R"(Shader "SingleSourceLocalKeywords" + R"(Shader "AuthoringLocalKeywords" { SubShader { @@ -914,18 +644,18 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringParsesMultiCompileLo fs::remove_all(shaderRoot); } -TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringParsesFallbackAndFixedFunctionStateInheritance) { +TEST(ShaderLoader, LoadShaderAuthoringParsesFallbackAndFixedFunctionStateInheritance) { namespace fs = std::filesystem; - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_single_source_fixed_state"; - const fs::path shaderPath = shaderRoot / "single_source_fixed_state.shader"; + const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_fixed_state"; + const fs::path shaderPath = shaderRoot / "authoring_fixed_state.shader"; fs::remove_all(shaderRoot); fs::create_directories(shaderRoot); WriteTextFile( shaderPath, - R"(Shader "SingleSourceFixedState" + R"(Shader "AuthoringFixedState" { Fallback "Legacy Shaders/Diffuse" SubShader @@ -990,10 +720,10 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringParsesFallbackAndFix fs::remove_all(shaderRoot); } -TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringRejectsBackendPragma) { +TEST(ShaderLoader, LoadShaderAuthoringRejectsLegacyBackendPragma) { namespace fs = std::filesystem; - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_single_source_reject_backend"; + const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_reject_backend"; const fs::path shaderPath = shaderRoot / "invalid_backend.shader"; fs::remove_all(shaderRoot); @@ -1035,10 +765,10 @@ TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringRejectsBackendPragma fs::remove_all(shaderRoot); } -TEST(ShaderLoader, LoadUnityStyleSingleSourceShaderAuthoringRejectsResourcesBlock) { +TEST(ShaderLoader, LoadShaderAuthoringRejectsLegacyResourcesBlock) { namespace fs = std::filesystem; - const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_single_source_reject_resources"; + const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_reject_resources"; const fs::path shaderPath = shaderRoot / "invalid_resources.shader"; fs::remove_all(shaderRoot); @@ -1228,19 +958,19 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactAndLoaderReadsItBack) { fs::remove_all(projectRoot); } -TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromSingleSourceAuthoringPreservesKeywords) { +TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromAuthoringPreservesKeywords) { namespace fs = std::filesystem; - const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_single_source_artifact_keywords"; + const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_authoring_artifact_keywords"; const fs::path shaderDir = projectRoot / "Assets" / "Shaders"; - const fs::path shaderPath = shaderDir / "single_source.shader"; + const fs::path shaderPath = shaderDir / "authoring.shader"; fs::remove_all(projectRoot); fs::create_directories(shaderDir); WriteTextFile( shaderPath, - R"(Shader "ArtifactSingleSourceKeywords" + R"(Shader "ArtifactAuthoringKeywords" { SubShader { @@ -1265,7 +995,7 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromSingleSourceAuthoringPr database.Initialize(projectRoot.string().c_str()); AssetDatabase::ResolvedAsset resolvedAsset; - ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/single_source.shader", ResourceType::Shader, resolvedAsset)); + ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/authoring.shader", ResourceType::Shader, resolvedAsset)); ASSERT_TRUE(resolvedAsset.artifactReady); EXPECT_TRUE(fs::exists(resolvedAsset.artifactMainPath.CStr())); @@ -1310,133 +1040,48 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromSingleSourceAuthoringPr fs::remove_all(projectRoot); } -TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromLegacyBackendSplitAuthoringPreservesKeywords) { - namespace fs = std::filesystem; - - const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_legacy_keyword_artifact"; - const fs::path shaderDir = projectRoot / "Assets" / "Shaders"; - const fs::path stageDir = shaderDir / "stages"; - const fs::path shaderPath = shaderDir / "legacy_keywords.shader"; - - fs::remove_all(projectRoot); - fs::create_directories(stageDir); - - WriteTextFile(stageDir / "legacy_keywords.vs.hlsl", "float4 MainVS() : SV_POSITION { return 0; }\n"); - WriteTextFile( - stageDir / "legacy_keywords.ps.hlsl", - "float4 MainPS() : SV_TARGET { return float4(1.0, 0.0, 0.0, 1.0); } // LEGACY_ARTIFACT_PS\n"); - - WriteTextFile( - shaderPath, - R"(Shader "LegacyArtifactKeywords" -{ - SubShader - { - Pass - { - Name "ForwardLit" - HLSLPROGRAM - #pragma vertex MainVS - #pragma fragment MainPS - #pragma multi_compile _ XC_MAIN_LIGHT_SHADOWS - #pragma multi_compile_local _ XC_ALPHA_TEST - #pragma backend D3D12 HLSL "stages/legacy_keywords.vs.hlsl" "stages/legacy_keywords.ps.hlsl" vs_5_0 ps_5_0 - ENDHLSL - } - } -} -)"); - - AssetDatabase database; - database.Initialize(projectRoot.string().c_str()); - - AssetDatabase::ResolvedAsset resolvedAsset; - ASSERT_TRUE(database.EnsureArtifact("Assets/Shaders/legacy_keywords.shader", ResourceType::Shader, resolvedAsset)); - ASSERT_TRUE(resolvedAsset.artifactReady); - EXPECT_TRUE(fs::exists(resolvedAsset.artifactMainPath.CStr())); - - ShaderLoader loader; - LoadResult result = loader.Load(resolvedAsset.artifactMainPath.CStr()); - ASSERT_TRUE(result); - ASSERT_NE(result.resource, nullptr); - - auto* shader = static_cast(result.resource); - ASSERT_NE(shader, nullptr); - ASSERT_TRUE(shader->DeclaresKeyword("XC_MAIN_LIGHT_SHADOWS")); - ASSERT_TRUE(shader->DeclaresKeyword("XC_ALPHA_TEST")); - - const ShaderPass* pass = shader->FindPass("ForwardLit"); - ASSERT_NE(pass, nullptr); - ASSERT_EQ(pass->keywordDeclarations.Size(), 2u); - EXPECT_EQ(pass->keywordDeclarations[0].type, ShaderKeywordDeclarationType::MultiCompile); - EXPECT_EQ(pass->keywordDeclarations[1].type, ShaderKeywordDeclarationType::MultiCompileLocal); - EXPECT_TRUE(pass->keywordDeclarations[1].IsLocal()); - ASSERT_EQ(pass->variants.Size(), 8u); - - ShaderKeywordSet enabledKeywords = {}; - enabledKeywords.enabledKeywords.PushBack("XC_ALPHA_TEST"); - enabledKeywords.enabledKeywords.PushBack("XC_MAIN_LIGHT_SHADOWS"); - - const ShaderStageVariant* keywordFragmentVariant = - shader->FindVariant( - "ForwardLit", - ShaderType::Fragment, - ShaderBackend::D3D12, - enabledKeywords); - ASSERT_NE(keywordFragmentVariant, nullptr); - ASSERT_EQ(keywordFragmentVariant->requiredKeywords.enabledKeywords.Size(), 2u); - EXPECT_NE( - std::string(keywordFragmentVariant->sourceCode.CStr()).find("#define XC_MAIN_LIGHT_SHADOWS 1"), - std::string::npos); - EXPECT_NE( - std::string(keywordFragmentVariant->sourceCode.CStr()).find("#define XC_ALPHA_TEST 1"), - std::string::npos); - EXPECT_NE( - std::string(keywordFragmentVariant->sourceCode.CStr()).find("LEGACY_ARTIFACT_PS"), - std::string::npos); - - delete shader; - database.Shutdown(); - fs::remove_all(projectRoot); -} - -TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromUnityLikeAuthoringAndTracksStageDependencies) { +TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromAuthoringAndTracksIncludeDependencies) { namespace fs = std::filesystem; using namespace std::chrono_literals; const fs::path projectRoot = fs::temp_directory_path() / "xc_shader_authoring_artifact_test"; const fs::path shaderDir = projectRoot / "Assets" / "Shaders"; - const fs::path stageDir = shaderDir / "stages"; + const fs::path includeDir = shaderDir / "shaderlib"; const fs::path shaderPath = shaderDir / "lit.shader"; - const fs::path fragmentPath = stageDir / "lit.frag.glsl"; + const fs::path includePath = includeDir / "shared.hlsl"; fs::remove_all(projectRoot); - fs::create_directories(stageDir); + fs::create_directories(includeDir); - WriteTextFile(stageDir / "lit.vert.glsl", "#version 430\n// AUTHORING_ARTIFACT_GL_VS\nvoid main() {}\n"); - WriteTextFile(fragmentPath, "#version 430\n// AUTHORING_ARTIFACT_GL_PS\nvoid main() {}\n"); + WriteTextFile(includePath, "// AUTHORING_ARTIFACT_SHARED_INCLUDE\n"); WriteTextFile( shaderPath, R"(Shader "ArtifactAuthoringShader" { - Properties + HLSLINCLUDE + #include "shaderlib/shared.hlsl" + struct VSInput { - _MainTex ("Main Tex", 2D) = "white" [Semantic(BaseColorTexture)] - } + float3 positionOS : POSITION; + }; + ENDHLSL SubShader { Pass { Name "ForwardLit" Tags { "LightMode" = "ForwardBase" } - Resources - { - BaseColorTexture (Texture2D, 3, 0) [Semantic(BaseColorTexture)] - } HLSLPROGRAM - #pragma vertex main - #pragma fragment main - #pragma backend OpenGL GLSL "stages/lit.vert.glsl" "stages/lit.frag.glsl" + #pragma vertex Vert + #pragma fragment Frag + float4 Vert(VSInput input) : SV_POSITION + { + return float4(input.positionOS, 1.0); + } + float4 Frag() : SV_TARGET + { + return float4(1.0, 0.0, 0.0, 1.0); + } ENDHLSL } } @@ -1460,9 +1105,11 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromUnityLikeAuthoringAndTr ASSERT_NE(firstShader, nullptr); EXPECT_EQ(firstShader->GetName(), "ArtifactAuthoringShader"); const ShaderStageVariant* firstFragment = - firstShader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::OpenGL); + firstShader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::D3D12); ASSERT_NE(firstFragment, nullptr); - EXPECT_NE(std::string(firstFragment->sourceCode.CStr()).find("AUTHORING_ARTIFACT_GL_PS"), std::string::npos); + EXPECT_NE( + std::string(firstFragment->sourceCode.CStr()).find("#include \"shaderlib/shared.hlsl\""), + std::string::npos); delete firstShader; const String firstArtifactPath = firstResolve.artifactMainPath; @@ -1470,10 +1117,10 @@ TEST(ShaderLoader, AssetDatabaseCreatesShaderArtifactFromUnityLikeAuthoringAndTr std::this_thread::sleep_for(50ms); { - std::ofstream fragmentFile(fragmentPath, std::ios::app); - ASSERT_TRUE(fragmentFile.is_open()); - fragmentFile << "\n// force authoring dependency reimport\n"; - ASSERT_TRUE(static_cast(fragmentFile)); + std::ofstream includeFile(includePath, std::ios::app); + ASSERT_TRUE(includeFile.is_open()); + includeFile << "\n// force authoring dependency reimport\n"; + ASSERT_TRUE(static_cast(includeFile)); } database.Initialize(projectRoot.string().c_str()); @@ -1547,7 +1194,7 @@ TEST(ShaderLoader, AssetDatabaseReimportsShaderWhenStageDependencyChanges) { fs::remove_all(projectRoot); } -TEST(ShaderLoader, LoadBuiltinForwardLitShaderBuildsUnityStyleSingleSourceVariants) { +TEST(ShaderLoader, LoadBuiltinForwardLitShaderBuildsAuthoringVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinForwardLitShaderPath()); ASSERT_TRUE(result); @@ -1722,7 +1369,7 @@ TEST(ShaderLoader, LoadBuiltinForwardLitShaderBuildsUnityStyleSingleSourceVarian delete shader; } -TEST(ShaderLoader, LoadBuiltinUnlitShaderBuildsUnityStyleSingleSourceVariants) { +TEST(ShaderLoader, LoadBuiltinUnlitShaderBuildsAuthoringVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinUnlitShaderPath()); ASSERT_TRUE(result); @@ -1800,7 +1447,7 @@ TEST(ShaderLoader, LoadBuiltinUnlitShaderBuildsUnityStyleSingleSourceVariants) { delete shader; } -TEST(ShaderLoader, LoadBuiltinObjectIdShaderBuildsUnityStyleSingleSourceVariants) { +TEST(ShaderLoader, LoadBuiltinObjectIdShaderBuildsAuthoringVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinObjectIdShaderPath()); ASSERT_TRUE(result); @@ -1865,7 +1512,7 @@ TEST(ShaderLoader, LoadBuiltinObjectIdShaderBuildsUnityStyleSingleSourceVariants delete shader; } -TEST(ShaderLoader, LoadBuiltinDepthOnlyShaderBuildsUnityStyleSingleSourceVariants) { +TEST(ShaderLoader, LoadBuiltinDepthOnlyShaderBuildsAuthoringVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinDepthOnlyShaderPath()); ASSERT_TRUE(result); @@ -1991,7 +1638,7 @@ TEST(ShaderLoader, LoadBuiltinDepthOnlyShaderBuildsUnityStyleSingleSourceVariant delete shader; } -TEST(ShaderLoader, LoadBuiltinShadowCasterShaderBuildsUnityStyleSingleSourceVariants) { +TEST(ShaderLoader, LoadBuiltinShadowCasterShaderBuildsAuthoringVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinShadowCasterShaderPath()); ASSERT_TRUE(result); @@ -2117,7 +1764,7 @@ TEST(ShaderLoader, LoadBuiltinShadowCasterShaderBuildsUnityStyleSingleSourceVari delete shader; } -TEST(ShaderLoader, LoadBuiltinFinalColorShaderBuildsUnityStyleSingleSourceVariants) { +TEST(ShaderLoader, LoadBuiltinFinalColorShaderBuildsAuthoringVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinFinalColorShaderPath()); ASSERT_TRUE(result); @@ -2200,7 +1847,7 @@ TEST(ShaderLoader, LoadBuiltinFinalColorShaderBuildsUnityStyleSingleSourceVarian delete shader; } -TEST(ShaderLoader, LoadBuiltinColorScalePostProcessShaderBuildsUnityStyleSingleSourceVariants) { +TEST(ShaderLoader, LoadBuiltinColorScalePostProcessShaderBuildsAuthoringVariants) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinColorScalePostProcessShaderPath()); ASSERT_TRUE(result);