From 1c87650fb33e3f10e47c926fef4a95810e539b3b Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 7 Apr 2026 11:16:02 +0800 Subject: [PATCH] resources: share shader source parsing utilities --- engine/CMakeLists.txt | 2 + .../Shader/ShaderAuthoringParser.cpp | 197 +-------------- engine/src/Resources/Shader/ShaderLoader.cpp | 231 +---------------- .../Resources/Shader/ShaderSourceUtils.cpp | 238 ++++++++++++++++++ .../src/Resources/Shader/ShaderSourceUtils.h | 33 +++ 5 files changed, 279 insertions(+), 422 deletions(-) create mode 100644 engine/src/Resources/Shader/ShaderSourceUtils.cpp create mode 100644 engine/src/Resources/Shader/ShaderSourceUtils.h diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 9b345d2a..b68d62a8 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -387,6 +387,8 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Material/MaterialLoader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Shader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderLoader.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 ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderAuthoringParser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioClip/AudioClip.cpp diff --git a/engine/src/Resources/Shader/ShaderAuthoringParser.cpp b/engine/src/Resources/Shader/ShaderAuthoringParser.cpp index 10fe881d..7a372053 100644 --- a/engine/src/Resources/Shader/ShaderAuthoringParser.cpp +++ b/engine/src/Resources/Shader/ShaderAuthoringParser.cpp @@ -1,9 +1,6 @@ #include "ShaderAuthoringParser.h" +#include "ShaderSourceUtils.h" -#include - -#include -#include #include #include #include @@ -12,198 +9,6 @@ namespace XCEngine { namespace Resources { -std::string ToStdString(const Containers::String& value) { - return std::string(value.CStr()); -} - -Containers::String NormalizePathString(const std::filesystem::path& path) { - return Containers::String(path.lexically_normal().generic_string().c_str()); -} - -size_t SkipWhitespace(const std::string& text, size_t pos) { - while (pos < text.size() && std::isspace(static_cast(text[pos])) != 0) { - ++pos; - } - return pos; -} - -std::string TrimCopy(const std::string& text) { - const size_t first = SkipWhitespace(text, 0); - if (first >= text.size()) { - return std::string(); - } - - size_t last = text.size(); - while (last > first && std::isspace(static_cast(text[last - 1])) != 0) { - --last; - } - - return text.substr(first, last - first); -} - -bool ParseQuotedString( - const std::string& text, - size_t quotePos, - Containers::String& outValue, - size_t* nextPos = nullptr) { - if (quotePos >= text.size() || text[quotePos] != '"') { - return false; - } - - std::string parsed; - ++quotePos; - - while (quotePos < text.size()) { - const char ch = text[quotePos]; - if (ch == '\\') { - if (quotePos + 1 >= text.size()) { - return false; - } - - parsed.push_back(text[quotePos + 1]); - quotePos += 2; - continue; - } - - if (ch == '"') { - outValue = parsed.c_str(); - if (nextPos != nullptr) { - *nextPos = quotePos + 1; - } - return true; - } - - parsed.push_back(ch); - ++quotePos; - } - - return false; -} - -bool TryParseShaderLanguage(const Containers::String& value, ShaderLanguage& outLanguage) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "glsl") { - outLanguage = ShaderLanguage::GLSL; - return true; - } - if (normalized == "hlsl") { - outLanguage = ShaderLanguage::HLSL; - return true; - } - if (normalized == "spirv" || normalized == "spv") { - outLanguage = ShaderLanguage::SPIRV; - return true; - } - - return false; -} - -bool TryParseShaderBackend(const Containers::String& value, ShaderBackend& outBackend) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "generic") { - outBackend = ShaderBackend::Generic; - return true; - } - if (normalized == "d3d12" || normalized == "dx12") { - outBackend = ShaderBackend::D3D12; - return true; - } - if (normalized == "opengl" || normalized == "gl") { - outBackend = ShaderBackend::OpenGL; - return true; - } - if (normalized == "vulkan" || normalized == "vk") { - outBackend = ShaderBackend::Vulkan; - return true; - } - - return false; -} - -bool TryParseShaderPropertyType(const Containers::String& value, ShaderPropertyType& outType) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "float") { - outType = ShaderPropertyType::Float; - return true; - } - if (normalized == "range") { - outType = ShaderPropertyType::Range; - return true; - } - if (normalized == "int" || normalized == "integer") { - outType = ShaderPropertyType::Int; - return true; - } - if (normalized == "vector" || normalized == "float4") { - outType = ShaderPropertyType::Vector; - return true; - } - if (normalized == "color") { - outType = ShaderPropertyType::Color; - return true; - } - if (normalized == "2d" || normalized == "texture2d" || normalized == "texture") { - outType = ShaderPropertyType::Texture2D; - return true; - } - if (normalized == "cube" || normalized == "cubemap" || normalized == "texturecube") { - outType = ShaderPropertyType::TextureCube; - return true; - } - - return false; -} - -bool TryParseShaderResourceType(const Containers::String& value, ShaderResourceType& outType) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "constantbuffer" || normalized == "cbuffer" || normalized == "cbv") { - outType = ShaderResourceType::ConstantBuffer; - return true; - } - if (normalized == "texture2d" || normalized == "texture" || normalized == "srvtexture2d") { - outType = ShaderResourceType::Texture2D; - return true; - } - if (normalized == "texturecube" || normalized == "cubemap") { - outType = ShaderResourceType::TextureCube; - return true; - } - if (normalized == "sampler" || normalized == "samplerstate") { - outType = ShaderResourceType::Sampler; - return true; - } - - return false; -} - -Containers::String ResolveShaderDependencyPath( - const Containers::String& dependencyPath, - const Containers::String& sourcePath) { - if (dependencyPath.Empty()) { - return dependencyPath; - } - - const std::filesystem::path dependencyFsPath(dependencyPath.CStr()); - if (dependencyFsPath.is_absolute()) { - return NormalizePathString(dependencyFsPath); - } - - const std::filesystem::path sourceFsPath(sourcePath.CStr()); - if (sourceFsPath.is_absolute()) { - return NormalizePathString(sourceFsPath.parent_path() / dependencyFsPath); - } - - const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot(); - if (!resourceRoot.Empty()) { - return NormalizePathString( - std::filesystem::path(resourceRoot.CStr()) / - sourceFsPath.parent_path() / - dependencyFsPath); - } - - return NormalizePathString(sourceFsPath.parent_path() / dependencyFsPath); -} - struct ExtractedProgramBlock { enum class Kind { SharedInclude, diff --git a/engine/src/Resources/Shader/ShaderLoader.cpp b/engine/src/Resources/Shader/ShaderLoader.cpp index bb5e19e3..194601ef 100644 --- a/engine/src/Resources/Shader/ShaderLoader.cpp +++ b/engine/src/Resources/Shader/ShaderLoader.cpp @@ -1,5 +1,6 @@ #include #include "ShaderAuthoringParser.h" +#include "ShaderSourceUtils.h" #include #include @@ -22,14 +23,10 @@ namespace Resources { namespace { -std::string ToStdString(const Containers::Array& data) { +std::string ToStdStringFromBytes(const Containers::Array& data) { return std::string(reinterpret_cast(data.Data()), data.Size()); } -std::string ToStdString(const Containers::String& value) { - return std::string(value.CStr()); -} - Containers::Array TryReadFileData( const std::filesystem::path& filePath, bool& opened) { @@ -72,10 +69,6 @@ Containers::Array ReadShaderFileData(const Containers::String& path return TryReadFileData(std::filesystem::path(resourceRoot.CStr()) / inputPath, opened); } -Containers::String NormalizePathString(const std::filesystem::path& path) { - return Containers::String(path.lexically_normal().generic_string().c_str()); -} - Containers::String GetPathExtension(const Containers::String& path) { size_t dotPos = Containers::String::npos; for (size_t i = path.Length(); i > 0; --i) { @@ -92,27 +85,6 @@ Containers::String GetPathExtension(const Containers::String& path) { return path.Substring(dotPos + 1); } -size_t SkipWhitespace(const std::string& text, size_t pos) { - while (pos < text.size() && std::isspace(static_cast(text[pos])) != 0) { - ++pos; - } - return pos; -} - -std::string TrimCopy(const std::string& text) { - const size_t first = SkipWhitespace(text, 0); - if (first >= text.size()) { - return std::string(); - } - - size_t last = text.size(); - while (last > first && std::isspace(static_cast(text[last - 1])) != 0) { - --last; - } - - return text.substr(first, last - first); -} - bool FindValueStart(const std::string& json, const char* key, size_t& valuePos) { const std::string token = std::string("\"") + key + "\""; const size_t keyPos = json.find(token); @@ -129,45 +101,6 @@ bool FindValueStart(const std::string& json, const char* key, size_t& valuePos) return valuePos < json.size(); } -bool ParseQuotedString( - const std::string& text, - size_t quotePos, - Containers::String& outValue, - size_t* nextPos = nullptr) { - if (quotePos >= text.size() || text[quotePos] != '"') { - return false; - } - - std::string parsed; - ++quotePos; - - while (quotePos < text.size()) { - const char ch = text[quotePos]; - if (ch == '\\') { - if (quotePos + 1 >= text.size()) { - return false; - } - - parsed.push_back(text[quotePos + 1]); - quotePos += 2; - continue; - } - - if (ch == '"') { - outValue = parsed.c_str(); - if (nextPos != nullptr) { - *nextPos = quotePos + 1; - } - return true; - } - - parsed.push_back(ch); - ++quotePos; - } - - return false; -} - bool TryParseStringValue(const std::string& json, const char* key, Containers::String& outValue) { size_t valuePos = 0; if (!FindValueStart(json, key, valuePos)) { @@ -399,132 +332,6 @@ bool TryParseShaderKeywordsArray( return true; } -bool TryParseShaderType(const Containers::String& value, ShaderType& outType) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "vertex" || normalized == "vs") { - outType = ShaderType::Vertex; - return true; - } - if (normalized == "fragment" || normalized == "pixel" || normalized == "ps") { - outType = ShaderType::Fragment; - return true; - } - if (normalized == "geometry" || normalized == "gs") { - outType = ShaderType::Geometry; - return true; - } - if (normalized == "compute" || normalized == "cs") { - outType = ShaderType::Compute; - return true; - } - if (normalized == "hull" || normalized == "hs") { - outType = ShaderType::Hull; - return true; - } - if (normalized == "domain" || normalized == "ds") { - outType = ShaderType::Domain; - return true; - } - - return false; -} - -bool TryParseShaderLanguage(const Containers::String& value, ShaderLanguage& outLanguage) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "glsl") { - outLanguage = ShaderLanguage::GLSL; - return true; - } - if (normalized == "hlsl") { - outLanguage = ShaderLanguage::HLSL; - return true; - } - if (normalized == "spirv" || normalized == "spv") { - outLanguage = ShaderLanguage::SPIRV; - return true; - } - - return false; -} - -bool TryParseShaderBackend(const Containers::String& value, ShaderBackend& outBackend) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "generic") { - outBackend = ShaderBackend::Generic; - return true; - } - if (normalized == "d3d12" || normalized == "dx12") { - outBackend = ShaderBackend::D3D12; - return true; - } - if (normalized == "opengl" || normalized == "gl") { - outBackend = ShaderBackend::OpenGL; - return true; - } - if (normalized == "vulkan" || normalized == "vk") { - outBackend = ShaderBackend::Vulkan; - return true; - } - - return false; -} - -bool TryParseShaderPropertyType(const Containers::String& value, ShaderPropertyType& outType) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "float") { - outType = ShaderPropertyType::Float; - return true; - } - if (normalized == "range") { - outType = ShaderPropertyType::Range; - return true; - } - if (normalized == "int" || normalized == "integer") { - outType = ShaderPropertyType::Int; - return true; - } - if (normalized == "vector" || normalized == "float4") { - outType = ShaderPropertyType::Vector; - return true; - } - if (normalized == "color") { - outType = ShaderPropertyType::Color; - return true; - } - if (normalized == "2d" || normalized == "texture2d" || normalized == "texture") { - outType = ShaderPropertyType::Texture2D; - return true; - } - if (normalized == "cube" || normalized == "cubemap" || normalized == "texturecube") { - outType = ShaderPropertyType::TextureCube; - return true; - } - - return false; -} - -bool TryParseShaderResourceType(const Containers::String& value, ShaderResourceType& outType) { - const Containers::String normalized = value.Trim().ToLower(); - if (normalized == "constantbuffer" || normalized == "cbuffer" || normalized == "cbv") { - outType = ShaderResourceType::ConstantBuffer; - return true; - } - if (normalized == "texture2d" || normalized == "texture" || normalized == "srvtexture2d") { - outType = ShaderResourceType::Texture2D; - return true; - } - if (normalized == "texturecube" || normalized == "cubemap") { - outType = ShaderResourceType::TextureCube; - return true; - } - if (normalized == "sampler" || normalized == "samplerstate") { - outType = ShaderResourceType::Sampler; - return true; - } - - return false; -} - Containers::String GetDefaultEntryPoint(ShaderLanguage language, ShaderType stage) { if (language != ShaderLanguage::HLSL) { return Containers::String("main"); @@ -576,41 +383,13 @@ Containers::String GetDefaultProfile( } } -Containers::String ResolveShaderDependencyPath( - const Containers::String& dependencyPath, - const Containers::String& sourcePath) { - if (dependencyPath.Empty()) { - return dependencyPath; - } - - const std::filesystem::path dependencyFsPath(dependencyPath.CStr()); - if (dependencyFsPath.is_absolute()) { - return NormalizePathString(dependencyFsPath); - } - - const std::filesystem::path sourceFsPath(sourcePath.CStr()); - if (sourceFsPath.is_absolute()) { - return NormalizePathString(sourceFsPath.parent_path() / dependencyFsPath); - } - - const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot(); - if (!resourceRoot.Empty()) { - return NormalizePathString( - std::filesystem::path(resourceRoot.CStr()) / - sourceFsPath.parent_path() / - dependencyFsPath); - } - - return NormalizePathString(sourceFsPath.parent_path() / dependencyFsPath); -} - bool ReadTextFile(const Containers::String& path, Containers::String& outText) { const Containers::Array data = ReadShaderFileData(path); if (data.Empty()) { return false; } - outText = ToStdString(data).c_str(); + outText = ToStdStringFromBytes(data).c_str(); return true; } @@ -1498,7 +1277,7 @@ LoadResult ShaderLoader::Load(const Containers::String& path, const ImportSettin return LoadResult("Failed to read shader file: " + path); } - const std::string sourceText = ToStdString(data); + const std::string sourceText = ToStdStringFromBytes(data); if (ext == "shader" && LooksLikeShaderManifest(sourceText)) { return LoadShaderManifest(path, sourceText); } @@ -1539,7 +1318,7 @@ bool ShaderLoader::CollectSourceDependencies(const Containers::String& path, return false; } - const std::string sourceText = ToStdString(data); + const std::string sourceText = ToStdStringFromBytes(data); if (!LooksLikeShaderManifest(sourceText)) { switch (DetectShaderAuthoringStyle(sourceText)) { case ShaderAuthoringStyle::LegacyBackendSplit: diff --git a/engine/src/Resources/Shader/ShaderSourceUtils.cpp b/engine/src/Resources/Shader/ShaderSourceUtils.cpp new file mode 100644 index 00000000..a9c029f1 --- /dev/null +++ b/engine/src/Resources/Shader/ShaderSourceUtils.cpp @@ -0,0 +1,238 @@ +#include "ShaderSourceUtils.h" + +#include + +#include +#include + +namespace XCEngine { +namespace Resources { + +std::string ToStdString(const Containers::String& value) { + return std::string(value.CStr()); +} + +namespace { + +Containers::String NormalizePathString(const std::filesystem::path& path) { + return Containers::String(path.lexically_normal().generic_string().c_str()); +} + +} // namespace + +size_t SkipWhitespace(const std::string& text, size_t pos) { + while (pos < text.size() && std::isspace(static_cast(text[pos])) != 0) { + ++pos; + } + return pos; +} + +std::string TrimCopy(const std::string& text) { + const size_t first = SkipWhitespace(text, 0); + if (first >= text.size()) { + return std::string(); + } + + size_t last = text.size(); + while (last > first && std::isspace(static_cast(text[last - 1])) != 0) { + --last; + } + + return text.substr(first, last - first); +} + +bool ParseQuotedString( + const std::string& text, + size_t quotePos, + Containers::String& outValue, + size_t* nextPos) { + if (quotePos >= text.size() || text[quotePos] != '"') { + return false; + } + + std::string parsed; + ++quotePos; + + while (quotePos < text.size()) { + const char ch = text[quotePos]; + if (ch == '\\') { + if (quotePos + 1 >= text.size()) { + return false; + } + + parsed.push_back(text[quotePos + 1]); + quotePos += 2; + continue; + } + + if (ch == '"') { + outValue = parsed.c_str(); + if (nextPos != nullptr) { + *nextPos = quotePos + 1; + } + return true; + } + + parsed.push_back(ch); + ++quotePos; + } + + return false; +} + +bool TryParseShaderType(const Containers::String& value, ShaderType& outType) { + const Containers::String normalized = value.Trim().ToLower(); + if (normalized == "vertex" || normalized == "vs") { + outType = ShaderType::Vertex; + return true; + } + if (normalized == "fragment" || normalized == "pixel" || normalized == "ps") { + outType = ShaderType::Fragment; + return true; + } + if (normalized == "geometry" || normalized == "gs") { + outType = ShaderType::Geometry; + return true; + } + if (normalized == "compute" || normalized == "cs") { + outType = ShaderType::Compute; + return true; + } + if (normalized == "hull" || normalized == "hs") { + outType = ShaderType::Hull; + return true; + } + if (normalized == "domain" || normalized == "ds") { + outType = ShaderType::Domain; + return true; + } + + return false; +} + +bool TryParseShaderLanguage(const Containers::String& value, ShaderLanguage& outLanguage) { + const Containers::String normalized = value.Trim().ToLower(); + if (normalized == "glsl") { + outLanguage = ShaderLanguage::GLSL; + return true; + } + if (normalized == "hlsl") { + outLanguage = ShaderLanguage::HLSL; + return true; + } + if (normalized == "spirv" || normalized == "spv") { + outLanguage = ShaderLanguage::SPIRV; + return true; + } + + return false; +} + +bool TryParseShaderBackend(const Containers::String& value, ShaderBackend& outBackend) { + const Containers::String normalized = value.Trim().ToLower(); + if (normalized == "generic") { + outBackend = ShaderBackend::Generic; + return true; + } + if (normalized == "d3d12" || normalized == "dx12") { + outBackend = ShaderBackend::D3D12; + return true; + } + if (normalized == "opengl" || normalized == "gl") { + outBackend = ShaderBackend::OpenGL; + return true; + } + if (normalized == "vulkan" || normalized == "vk") { + outBackend = ShaderBackend::Vulkan; + return true; + } + + return false; +} + +bool TryParseShaderPropertyType(const Containers::String& value, ShaderPropertyType& outType) { + const Containers::String normalized = value.Trim().ToLower(); + if (normalized == "float") { + outType = ShaderPropertyType::Float; + return true; + } + if (normalized == "range") { + outType = ShaderPropertyType::Range; + return true; + } + if (normalized == "int" || normalized == "integer") { + outType = ShaderPropertyType::Int; + return true; + } + if (normalized == "vector" || normalized == "float4") { + outType = ShaderPropertyType::Vector; + return true; + } + if (normalized == "color") { + outType = ShaderPropertyType::Color; + return true; + } + if (normalized == "2d" || normalized == "texture2d" || normalized == "texture") { + outType = ShaderPropertyType::Texture2D; + return true; + } + if (normalized == "cube" || normalized == "cubemap" || normalized == "texturecube") { + outType = ShaderPropertyType::TextureCube; + return true; + } + + return false; +} + +bool TryParseShaderResourceType(const Containers::String& value, ShaderResourceType& outType) { + const Containers::String normalized = value.Trim().ToLower(); + if (normalized == "constantbuffer" || normalized == "cbuffer" || normalized == "cbv") { + outType = ShaderResourceType::ConstantBuffer; + return true; + } + if (normalized == "texture2d" || normalized == "texture" || normalized == "srvtexture2d") { + outType = ShaderResourceType::Texture2D; + return true; + } + if (normalized == "texturecube" || normalized == "cubemap") { + outType = ShaderResourceType::TextureCube; + return true; + } + if (normalized == "sampler" || normalized == "samplerstate") { + outType = ShaderResourceType::Sampler; + return true; + } + + return false; +} + +Containers::String ResolveShaderDependencyPath( + const Containers::String& dependencyPath, + const Containers::String& sourcePath) { + if (dependencyPath.Empty()) { + return dependencyPath; + } + + const std::filesystem::path dependencyFsPath(dependencyPath.CStr()); + if (dependencyFsPath.is_absolute()) { + return NormalizePathString(dependencyFsPath); + } + + const std::filesystem::path sourceFsPath(sourcePath.CStr()); + if (sourceFsPath.is_absolute()) { + return NormalizePathString(sourceFsPath.parent_path() / dependencyFsPath); + } + + const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot(); + if (!resourceRoot.Empty()) { + return NormalizePathString( + std::filesystem::path(resourceRoot.CStr()) / + sourceFsPath.parent_path() / + dependencyFsPath); + } + + return NormalizePathString(sourceFsPath.parent_path() / dependencyFsPath); +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Shader/ShaderSourceUtils.h b/engine/src/Resources/Shader/ShaderSourceUtils.h new file mode 100644 index 00000000..5dda50c7 --- /dev/null +++ b/engine/src/Resources/Shader/ShaderSourceUtils.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include + +namespace XCEngine { +namespace Resources { + +std::string ToStdString(const Containers::String& value); + +size_t SkipWhitespace(const std::string& text, size_t pos); +std::string TrimCopy(const std::string& text); + +bool ParseQuotedString( + const std::string& text, + size_t quotePos, + Containers::String& outValue, + size_t* nextPos = nullptr); + +bool TryParseShaderType(const Containers::String& value, ShaderType& outType); +bool TryParseShaderLanguage(const Containers::String& value, ShaderLanguage& outLanguage); +bool TryParseShaderBackend(const Containers::String& value, ShaderBackend& outBackend); +bool TryParseShaderPropertyType(const Containers::String& value, ShaderPropertyType& outType); +bool TryParseShaderResourceType(const Containers::String& value, ShaderResourceType& outType); + +Containers::String ResolveShaderDependencyPath( + const Containers::String& dependencyPath, + const Containers::String& sourcePath); + +} // namespace Resources +} // namespace XCEngine