diff --git a/CMakeLists.txt b/CMakeLists.txt index 131ac6dc..58897115 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,8 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MobileGL/MG_Backend/Init.cpp - MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp + MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.cpp + MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.cpp ) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE diff --git a/MobileGL/Includes.h b/MobileGL/Includes.h index 0afe6273..f412367f 100644 --- a/MobileGL/Includes.h +++ b/MobileGL/Includes.h @@ -87,6 +87,6 @@ #include "MG_Impl/GLImpl/Getter/GL_Getter.h" -#include "MG_Util/Pipelines/Pipeline.hpp" +#include "MG_Util/Pipelines/PipelineExecutor.hpp" -#include "MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.h" +#include "MG_Util/Pipelines/ShaderCompilationPipeline.h" diff --git a/MobileGL/Init.cpp b/MobileGL/Init.cpp index 8b949991..36eeaf68 100644 --- a/MobileGL/Init.cpp +++ b/MobileGL/Init.cpp @@ -5,10 +5,12 @@ namespace MobileGL { MG_Util::Debug::InitFile(); MGLOG_I("MobileGL Initializing..."); MG_Backend::Init(); + glslang::InitializeProcess(); } void MG_Destroy() { MGLOG_I("MobileGL Closing..."); + glslang::FinalizeProcess(); MG_Util::Debug::Close(); } diff --git a/MobileGL/MG_Util/Pipelines/Pipeline.hpp b/MobileGL/MG_Util/Pipelines/PipelineExecutor.hpp similarity index 70% rename from MobileGL/MG_Util/Pipelines/Pipeline.hpp rename to MobileGL/MG_Util/Pipelines/PipelineExecutor.hpp index 7f935247..e4a56945 100644 --- a/MobileGL/MG_Util/Pipelines/Pipeline.hpp +++ b/MobileGL/MG_Util/Pipelines/PipelineExecutor.hpp @@ -1,48 +1,48 @@ #pragma once -#ifndef MG_PIPELINE_HPP -#define MG_PIPELINE_HPP +#ifndef MG_PIPELINEEXECUTOR_HPP +#define MG_PIPELINEEXECUTOR_HPP namespace MobileGL { namespace MG_Util { namespace Pipeline { using next_t = std::function; - using next_ptr_t = std::shared_ptr; + using next_ptr_t = SharedPtr; template class Stage { protected: - using T_ptr = std::shared_ptr; + using T_ptr = SharedPtr; using callback_t = std::function; public: virtual callback_t handler() = 0; }; template - class Pipeline { + class PipelineExecutor { protected: - using T_ptr = std::shared_ptr; + using T_ptr = SharedPtr; using callback_t = std::function; - using middleware_ptr_t = std::shared_ptr>; + using middleware_ptr_t = SharedPtr>; public: - explicit Pipeline(std::function callback) : + explicit PipelineExecutor(std::function callback) : callback_(Move(callback)) {} - Pipeline &Register(callback_t middleware) { + PipelineExecutor &Register(callback_t middleware) { middlewares_.emplace_back(Move(middleware)); return *this; } - Pipeline &Register(middleware_ptr_t middleware) { + PipelineExecutor &Register(middleware_ptr_t middleware) { middleware_storage_.emplace_back(middleware); Register(middleware->handler()); return *this; } void Process(T_ptr payload) { - auto it_ptr = std::make_shared::iterator>( + auto it_ptr = MakeShared::iterator>( middlewares_.begin()); - auto next = std::make_shared(); + auto next = MakeShared(); auto weak_next = std::weak_ptr(next); // setup next callback @@ -66,12 +66,12 @@ namespace MobileGL { } private: - std::vector middlewares_; - std::vector middleware_storage_; + Vector middlewares_; + Vector middleware_storage_; std::function callback_; }; } } } -#endif //MG_PIPELINE_HPP +#endif //MG_PIPELINEEXECUTOR_HPP diff --git a/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.cpp b/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.cpp new file mode 100644 index 00000000..d666eded --- /dev/null +++ b/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.cpp @@ -0,0 +1,57 @@ +// +// Created by Swung 0x48 on 2025/7/16. +// + +#include "ProgramLinkingPipeline.h" + +namespace MobileGL { +namespace MG_Util { +namespace Pipeline { + ProgramLinkingPipeline::ProgramLinkingPipeline(std::function callback): + executor_(Move(callback)) { + executor_ + .Register([](SharedPtr payload, auto next) { + // Link TShader to TProgram + auto& shaders = payload->shadersToLink; + auto& program = payload->linkedProgram; + + for (auto& shader : shaders) { + program.addShader(shader.get()); + } + + if (!program.link(EShMsgDefault)) { + payload->log += "Error: [glslang] Cannot link the program:\n" + std::to_string(program.getInfoLog()); + payload->errc = -1; + + return; + } + + (*next)(); + }) + .Register([](auto payload, auto next) { + auto& types = payload->shaderTypes; + auto& program = payload->linkedProgram; + auto& programSpirv = payload->programSpirv; + + glslang::SpvOptions spvOptions; + spvOptions.disableOptimizer = false; + + for (auto type : types) { + std::vector spirv; + + auto lang = GetEShLanguageByShaderType(type); + GlslangToSpv(*program.getIntermediate(lang), spirv, &spvOptions); + programSpirv.emplace_back(std::move(spirv)); + } + + (*next)(); + }) + ; + } + + void ProgramLinkingPipeline::Invoke(SharedPtr payload) { + executor_.Process(Move(payload)); + } +} +} +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.h b/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.h new file mode 100644 index 00000000..766f1338 --- /dev/null +++ b/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.h @@ -0,0 +1,24 @@ +// +// Created by Swung 0x48 on 2025/7/16. +// + +#ifndef MG_UTIL_PIPELINES_PROGRAMLINKINGPIPELINE_H +#define MG_UTIL_PIPELINES_PROGRAMLINKINGPIPELINE_H + +#include "../../Includes.h" + +namespace MobileGL { +namespace MG_Util { +namespace Pipeline { + class ProgramLinkingPipeline: public IPipeline { + explicit ProgramLinkingPipeline(std::function callback); + void Invoke(SharedPtr payload); + private: + PipelineExecutor executor_; + }; +} +} +} + + +#endif //MG_UTIL_PIPELINES_PROGRAMLINKINGPIPELINE_H diff --git a/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp b/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp deleted file mode 100644 index 303d14b5..00000000 --- a/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// -// Created by Swung 0x48 on 2025-07-12. -// - -#include "GLSLtoSPIRVPipeline.h" - -MobileGL::MG_Util::Pipeline::GLSLtoSPIRVPipeline::GLSLtoSPIRVPipeline(std::function callback): - pipeline_(Move(callback)) { - pipeline_ - .Register([this](SharedPtr payload, auto next) { - // source -> glslang TShader - auto& shaderType = payload->shaderType; - auto& sourceStr = payload->sourceStr; - - glslang::InitializeProcess(); - auto lang = GetEShLanguageByShaderType(shaderType); - if (lang == EShLanguage::EShLangCount) { - payload->log += "Error: [Preprocess] Unsupported shader type: " + - ConvertGLEnumToString(shaderType); - payload->errc = -1; - return; - } - - auto& tshader = payload->TShader; - tshader = MakeUnique(lang); - const char* src[] = { sourceStr.c_str() }; - tshader->setStrings(src, 1); - tshader->setInvertY(true); - tshader->setEnvInput(glslang::EShSourceGlsl, lang, glslang::EShClientOpenGL, 150); - tshader->setEnvClient(glslang::EShClientOpenGL, glslang::EShTargetOpenGL_450); - tshader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_6); - tshader->setAutoMapLocations(true); - tshader->setAutoMapBindings(true); - tshader->setEnvInputVulkanRulesRelaxed(); // using EXT_vulkan_glsl_relaxed for gl_VertexID and gl_InstanceID? - - if (!tshader->parse(&GetTBuiltInResourceInstance(), 450, ECoreProfile, - /*forceDefaultVersionAndProfile: */false, - /*forwardCompatible: */true, EShMsgDefault)) { - payload->log += "Error: [glslang] Cannot compile " + ConvertGLEnumToString(shaderType) + ":\n" - + std::to_string(tshader->getInfoLog()); - payload->errc = -2; - return; - } - - (*next)(); - - glslang::FinalizeProcess(); - }) - .Register([this](auto payload, auto next) { - UniformTraverser uniformTraverser(payload->uniforms); - auto root = payload->TShader->getIntermediate()->getTreeRoot(); - root->traverse(&uniformTraverser); - (*next)(); - }) - ; -} - -void MobileGL::MG_Util::Pipeline::GLSLtoSPIRVPipeline::Invoke(SharedPtr payload) { - pipeline_.Process(Move(payload)); -} diff --git a/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.h b/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.h deleted file mode 100644 index 6374d362..00000000 --- a/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.h +++ /dev/null @@ -1,202 +0,0 @@ -// -// Created by Swung 0x48 on 2025-07-12. -// - -#ifndef MG_GLSLTOSPIRVPIPELINE_H -#define MG_GLSLTOSPIRVPIPELINE_H - -#include "../../../Includes.h" - -namespace MobileGL { -namespace MG_Util { -namespace Pipeline { - struct TUniform { - String name; - bool isSampler = false; - - // For isSampler == false - glslang::TStorageQualifier storageQualifier; - Uint layoutLocation = 0; - Uint layoutBinding = 0; - glslang::TLayoutPacking layoutPacking; - - // For isSampler == true - glslang::TSampler sampler; - }; - - struct GLSLtoSPIRVPayload { - GLenum shaderType; - String sourceStr; - UniquePtr TShader; - Vector uniforms; - Int errc = 0; - String log; - }; - - class UniformTraverser : public glslang::TIntermTraverser { - public: - UniformTraverser(Vector& u): uniforms(u) {} - - void visitSymbol(glslang::TIntermSymbol* symbol) override { - const auto& type = symbol->getType(); - if (symbol->getQualifier().isUniform()) { - auto name = symbol->getName(); - auto qualifier = symbol->getQualifier(); - - auto& uniform = uniforms.emplace_back(); - uniform.isSampler = false; - uniform.name = name; - uniform.storageQualifier = qualifier.storage; - uniform.layoutLocation = qualifier.layoutLocation; - uniform.layoutBinding = qualifier.layoutBinding; - uniform.layoutPacking = qualifier.layoutPacking; - } else if (type.getBasicType() == glslang::EbtSampler) { - auto& uniform = uniforms.emplace_back(); - uniform.name = symbol->getName(); - uniform.isSampler = true; - uniform.sampler = type.getSampler(); - } - } - - Vector& uniforms; - }; - - class GLSLtoSPIRVPipeline { - explicit GLSLtoSPIRVPipeline(std::function callback); - void Invoke(SharedPtr payload); - - inline static EShLanguage GetEShLanguageByShaderType(GLenum shaderType) { - switch (shaderType) { - case GL_VERTEX_SHADER: - return EShLanguage::EShLangVertex; - case GL_FRAGMENT_SHADER: - return EShLanguage::EShLangFragment; - case GL_COMPUTE_SHADER: - return EShLanguage::EShLangCompute; - case GL_TESS_CONTROL_SHADER: - return EShLanguage::EShLangTessControl; - case GL_TESS_EVALUATION_SHADER: - return EShLanguage::EShLangTessEvaluation; - case GL_GEOMETRY_SHADER: - return EShLanguage::EShLangGeometry; - default: - return EShLanguage::EShLangCount; - } - } - - static inline TBuiltInResource& GetTBuiltInResourceInstance() { - static TBuiltInResource Resources{}; - Resources.maxLights = 32; - Resources.maxClipPlanes = 6; - Resources.maxTextureUnits = 32; - Resources.maxTextureCoords = 32; - Resources.maxVertexAttribs = 64; - Resources.maxVertexUniformComponents = 4096; - Resources.maxVaryingFloats = 64; - Resources.maxVertexTextureImageUnits = 32; - Resources.maxCombinedTextureImageUnits = 80; - Resources.maxTextureImageUnits = 32; - Resources.maxFragmentUniformComponents = 4096; - Resources.maxDrawBuffers = 32; - Resources.maxVertexUniformVectors = 128; - Resources.maxVaryingVectors = 8; - Resources.maxFragmentUniformVectors = 16; - Resources.maxVertexOutputVectors = 16; - Resources.maxFragmentInputVectors = 15; - Resources.minProgramTexelOffset = -8; - Resources.maxProgramTexelOffset = 7; - Resources.maxClipDistances = 8; - Resources.maxComputeWorkGroupCountX = 65535; - Resources.maxComputeWorkGroupCountY = 65535; - Resources.maxComputeWorkGroupCountZ = 65535; - Resources.maxComputeWorkGroupSizeX = 1024; - Resources.maxComputeWorkGroupSizeY = 1024; - Resources.maxComputeWorkGroupSizeZ = 64; - Resources.maxComputeUniformComponents = 1024; - Resources.maxComputeTextureImageUnits = 16; - Resources.maxComputeImageUniforms = 8; - Resources.maxComputeAtomicCounters = 8; - Resources.maxComputeAtomicCounterBuffers = 1; - Resources.maxVaryingComponents = 60; - Resources.maxVertexOutputComponents = 64; - Resources.maxGeometryInputComponents = 64; - Resources.maxGeometryOutputComponents = 128; - Resources.maxFragmentInputComponents = 128; - Resources.maxImageUnits = 8; - Resources.maxCombinedImageUnitsAndFragmentOutputs = 8; - Resources.maxCombinedShaderOutputResources = 8; - Resources.maxImageSamples = 0; - Resources.maxVertexImageUniforms = 0; - Resources.maxTessControlImageUniforms = 0; - Resources.maxTessEvaluationImageUniforms = 0; - Resources.maxGeometryImageUniforms = 0; - Resources.maxFragmentImageUniforms = 8; - Resources.maxCombinedImageUniforms = 8; - Resources.maxGeometryTextureImageUnits = 16; - Resources.maxGeometryOutputVertices = 256; - Resources.maxGeometryTotalOutputComponents = 1024; - Resources.maxGeometryUniformComponents = 1024; - Resources.maxGeometryVaryingComponents = 64; - Resources.maxTessControlInputComponents = 128; - Resources.maxTessControlOutputComponents = 128; - Resources.maxTessControlTextureImageUnits = 16; - Resources.maxTessControlUniformComponents = 1024; - Resources.maxTessControlTotalOutputComponents = 4096; - Resources.maxTessEvaluationInputComponents = 128; - Resources.maxTessEvaluationOutputComponents = 128; - Resources.maxTessEvaluationTextureImageUnits = 16; - Resources.maxTessEvaluationUniformComponents = 1024; - Resources.maxTessPatchComponents = 120; - Resources.maxPatchVertices = 32; - Resources.maxTessGenLevel = 64; - Resources.maxViewports = 16; - Resources.maxVertexAtomicCounters = 0; - Resources.maxTessControlAtomicCounters = 0; - Resources.maxTessEvaluationAtomicCounters = 0; - Resources.maxGeometryAtomicCounters = 0; - Resources.maxFragmentAtomicCounters = 8; - Resources.maxCombinedAtomicCounters = 8; - Resources.maxAtomicCounterBindings = 1; - Resources.maxVertexAtomicCounterBuffers = 0; - Resources.maxTessControlAtomicCounterBuffers = 0; - Resources.maxTessEvaluationAtomicCounterBuffers = 0; - Resources.maxGeometryAtomicCounterBuffers = 0; - Resources.maxFragmentAtomicCounterBuffers = 1; - Resources.maxCombinedAtomicCounterBuffers = 1; - Resources.maxAtomicCounterBufferSize = 16384; - Resources.maxTransformFeedbackBuffers = 4; - Resources.maxTransformFeedbackInterleavedComponents = 64; - Resources.maxCullDistances = 8; - Resources.maxCombinedClipAndCullDistances = 8; - Resources.maxSamples = 4; - Resources.maxMeshOutputVerticesNV = 256; - Resources.maxMeshOutputPrimitivesNV = 512; - Resources.maxMeshWorkGroupSizeX_NV = 32; - Resources.maxMeshWorkGroupSizeY_NV = 1; - Resources.maxMeshWorkGroupSizeZ_NV = 1; - Resources.maxTaskWorkGroupSizeX_NV = 32; - Resources.maxTaskWorkGroupSizeY_NV = 1; - Resources.maxTaskWorkGroupSizeZ_NV = 1; - Resources.maxMeshViewCountNV = 4; - - Resources.limits.nonInductiveForLoops = true; - Resources.limits.whileLoops = true; - Resources.limits.doWhileLoops = true; - Resources.limits.generalUniformIndexing = true; - Resources.limits.generalAttributeMatrixVectorIndexing = true; - Resources.limits.generalVaryingIndexing = true; - Resources.limits.generalSamplerIndexing = true; - Resources.limits.generalVariableIndexing = true; - Resources.limits.generalConstantMatrixVectorIndexing = true; - - return Resources; - } - private: - Pipeline pipeline_; - }; -} -} -} - - -#endif //MG_GLSLTOSPIRVPIPELINE_H diff --git a/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.cpp b/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.cpp new file mode 100644 index 00000000..eaf07d59 --- /dev/null +++ b/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.cpp @@ -0,0 +1,172 @@ +// +// Created by Swung 0x48 on 2025-07-12. +// + +#include "ShaderCompilationPipeline.h" + +namespace MobileGL { +namespace MG_Util { +namespace Pipeline { + TBuiltInResource& ShaderCompilationPipeline::GetTBuiltInResourceInstance() + { + static TBuiltInResource Resources{}; + Resources.maxLights = 32; + Resources.maxClipPlanes = 6; + Resources.maxTextureUnits = 32; + Resources.maxTextureCoords = 32; + Resources.maxVertexAttribs = 64; + Resources.maxVertexUniformComponents = 4096; + Resources.maxVaryingFloats = 64; + Resources.maxVertexTextureImageUnits = 32; + Resources.maxCombinedTextureImageUnits = 80; + Resources.maxTextureImageUnits = 32; + Resources.maxFragmentUniformComponents = 4096; + Resources.maxDrawBuffers = 32; + Resources.maxVertexUniformVectors = 128; + Resources.maxVaryingVectors = 8; + Resources.maxFragmentUniformVectors = 16; + Resources.maxVertexOutputVectors = 16; + Resources.maxFragmentInputVectors = 15; + Resources.minProgramTexelOffset = -8; + Resources.maxProgramTexelOffset = 7; + Resources.maxClipDistances = 8; + Resources.maxComputeWorkGroupCountX = 65535; + Resources.maxComputeWorkGroupCountY = 65535; + Resources.maxComputeWorkGroupCountZ = 65535; + Resources.maxComputeWorkGroupSizeX = 1024; + Resources.maxComputeWorkGroupSizeY = 1024; + Resources.maxComputeWorkGroupSizeZ = 64; + Resources.maxComputeUniformComponents = 1024; + Resources.maxComputeTextureImageUnits = 16; + Resources.maxComputeImageUniforms = 8; + Resources.maxComputeAtomicCounters = 8; + Resources.maxComputeAtomicCounterBuffers = 1; + Resources.maxVaryingComponents = 60; + Resources.maxVertexOutputComponents = 64; + Resources.maxGeometryInputComponents = 64; + Resources.maxGeometryOutputComponents = 128; + Resources.maxFragmentInputComponents = 128; + Resources.maxImageUnits = 8; + Resources.maxCombinedImageUnitsAndFragmentOutputs = 8; + Resources.maxCombinedShaderOutputResources = 8; + Resources.maxImageSamples = 0; + Resources.maxVertexImageUniforms = 0; + Resources.maxTessControlImageUniforms = 0; + Resources.maxTessEvaluationImageUniforms = 0; + Resources.maxGeometryImageUniforms = 0; + Resources.maxFragmentImageUniforms = 8; + Resources.maxCombinedImageUniforms = 8; + Resources.maxGeometryTextureImageUnits = 16; + Resources.maxGeometryOutputVertices = 256; + Resources.maxGeometryTotalOutputComponents = 1024; + Resources.maxGeometryUniformComponents = 1024; + Resources.maxGeometryVaryingComponents = 64; + Resources.maxTessControlInputComponents = 128; + Resources.maxTessControlOutputComponents = 128; + Resources.maxTessControlTextureImageUnits = 16; + Resources.maxTessControlUniformComponents = 1024; + Resources.maxTessControlTotalOutputComponents = 4096; + Resources.maxTessEvaluationInputComponents = 128; + Resources.maxTessEvaluationOutputComponents = 128; + Resources.maxTessEvaluationTextureImageUnits = 16; + Resources.maxTessEvaluationUniformComponents = 1024; + Resources.maxTessPatchComponents = 120; + Resources.maxPatchVertices = 32; + Resources.maxTessGenLevel = 64; + Resources.maxViewports = 16; + Resources.maxVertexAtomicCounters = 0; + Resources.maxTessControlAtomicCounters = 0; + Resources.maxTessEvaluationAtomicCounters = 0; + Resources.maxGeometryAtomicCounters = 0; + Resources.maxFragmentAtomicCounters = 8; + Resources.maxCombinedAtomicCounters = 8; + Resources.maxAtomicCounterBindings = 1; + Resources.maxVertexAtomicCounterBuffers = 0; + Resources.maxTessControlAtomicCounterBuffers = 0; + Resources.maxTessEvaluationAtomicCounterBuffers = 0; + Resources.maxGeometryAtomicCounterBuffers = 0; + Resources.maxFragmentAtomicCounterBuffers = 1; + Resources.maxCombinedAtomicCounterBuffers = 1; + Resources.maxAtomicCounterBufferSize = 16384; + Resources.maxTransformFeedbackBuffers = 4; + Resources.maxTransformFeedbackInterleavedComponents = 64; + Resources.maxCullDistances = 8; + Resources.maxCombinedClipAndCullDistances = 8; + Resources.maxSamples = 4; + Resources.maxMeshOutputVerticesNV = 256; + Resources.maxMeshOutputPrimitivesNV = 512; + Resources.maxMeshWorkGroupSizeX_NV = 32; + Resources.maxMeshWorkGroupSizeY_NV = 1; + Resources.maxMeshWorkGroupSizeZ_NV = 1; + Resources.maxTaskWorkGroupSizeX_NV = 32; + Resources.maxTaskWorkGroupSizeY_NV = 1; + Resources.maxTaskWorkGroupSizeZ_NV = 1; + Resources.maxMeshViewCountNV = 4; + + Resources.limits.nonInductiveForLoops = true; + Resources.limits.whileLoops = true; + Resources.limits.doWhileLoops = true; + Resources.limits.generalUniformIndexing = true; + Resources.limits.generalAttributeMatrixVectorIndexing = true; + Resources.limits.generalVaryingIndexing = true; + Resources.limits.generalSamplerIndexing = true; + Resources.limits.generalVariableIndexing = true; + Resources.limits.generalConstantMatrixVectorIndexing = true; + + return Resources; + } + + ShaderCompilationPipeline::ShaderCompilationPipeline(std::function callback): + executor_(Move(callback)) { + executor_ + .Register([this](SharedPtr payload, auto next) { + // source -> glslang TShader + auto& shaderType = payload->shaderType; + auto& sourceStr = payload->sourceStr; + + auto lang = GetEShLanguageByShaderType(shaderType); + if (lang == EShLanguage::EShLangCount) { + payload->log += "Error: [Preprocess] Unsupported shader type: " + + ConvertGLEnumToString(shaderType); + payload->errc = -1; + return; + } + + auto& tshader = payload->TShader; + tshader = MakeUnique(lang); + const char* src[] = { sourceStr.c_str() }; + tshader->setStrings(src, 1); + tshader->setInvertY(true); + tshader->setEnvInput(glslang::EShSourceGlsl, lang, glslang::EShClientOpenGL, 150); + tshader->setEnvClient(glslang::EShClientOpenGL, glslang::EShTargetOpenGL_450); + tshader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_6); + tshader->setAutoMapLocations(true); + tshader->setAutoMapBindings(true); + tshader->setEnvInputVulkanRulesRelaxed(); // using EXT_vulkan_glsl_relaxed for gl_VertexID and gl_InstanceID? + + if (!tshader->parse(&GetTBuiltInResourceInstance(), 450, ECoreProfile, + /*forceDefaultVersionAndProfile: */false, + /*forwardCompatible: */true, EShMsgDefault)) { + payload->log += "Error: [glslang] Cannot compile " + ConvertGLEnumToString(shaderType) + ":\n" + + std::to_string(tshader->getInfoLog()); + payload->errc = -2; + return; + } + + (*next)(); + }) + .Register([this](auto payload, auto next) { + UniformTraverser uniformTraverser(payload->uniforms, payload->samplers); + auto root = payload->TShader->getIntermediate()->getTreeRoot(); + root->traverse(&uniformTraverser); + (*next)(); + }) + ; + } + + void ShaderCompilationPipeline::Invoke(SharedPtr payload) { + executor_.Process(Move(payload)); + } +} +} +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.h b/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.h new file mode 100644 index 00000000..23161eb9 --- /dev/null +++ b/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.h @@ -0,0 +1,53 @@ +// +// Created by Swung 0x48 on 2025-07-12. +// + +#ifndef MG_UTIL_PIPELINES_SHADERCOMPILATIONPIPELINE_H +#define MG_UTIL_PIPELINES_SHADERCOMPILATIONPIPELINE_H + +#include "../../Includes.h" + +namespace MobileGL { +namespace MG_Util { +namespace Pipeline { + class UniformTraverser : public glslang::TIntermTraverser { + public: + UniformTraverser(Vector>& u, Vector>& s): uniforms(u), samplers(s) {} + + void visitSymbol(glslang::TIntermSymbol* symbol) override { + const auto& type = symbol->getType(); + if (symbol->getQualifier().isUniform()) { + auto name = symbol->getName(); + auto qualifier = symbol->getQualifier(); + + auto& uniform = uniforms.emplace_back(); + uniform.name = name; + uniform.storageQualifier = qualifier.storage; + uniform.layoutLocation = qualifier.layoutLocation; + uniform.layoutBinding = qualifier.layoutBinding; + uniform.layoutPacking = qualifier.layoutPacking; + } else if (type.getBasicType() == glslang::EbtSampler) { + auto& uniform = samplers.emplace_back(); + uniform.name = symbol->getName(); + uniform.sampler = type.getSampler(); + } + } + + Vector>& uniforms; + Vector>& samplers; + }; + + class ShaderCompilationPipeline: public IPipeline { + explicit ShaderCompilationPipeline(std::function callback); + void Invoke(SharedPtr payload); + + static TBuiltInResource& GetTBuiltInResourceInstance(); + private: + PipelineExecutor executor_; + }; +} +} +} + + +#endif //MG_UTIL_PIPELINES_SHADERCOMPILATIONPIPELINE_H diff --git a/MobileGL/MG_Util/Pipelines/Types.h b/MobileGL/MG_Util/Pipelines/Types.h new file mode 100644 index 00000000..5b4b57c6 --- /dev/null +++ b/MobileGL/MG_Util/Pipelines/Types.h @@ -0,0 +1,93 @@ +// +// Created by Swung 0x48 on 2025/7/16. +// +#pragma once + +#ifndef MG_UTIL_PIPELINES_TYPES_H +#define MG_UTIL_PIPELINES_TYPES_H + +namespace MobileGL { +namespace MG_Util { +namespace Pipeline { + template + class IPipeline { + void Invoke(SharedPtr payload) { + static_cast(this)->Invoke(payload); + } + }; + + enum class TUniformType { + Uniform, + Sampler + }; + + template + struct TUniform { + static_assert(false, "TUniform does not accept this enum"); + }; + + template <> + struct TUniform { + String name; + + glslang::TStorageQualifier storageQualifier; + Uint layoutLocation = 0; + Uint layoutBinding = 0; + glslang::TLayoutPacking layoutPacking; + }; + + template <> + struct TUniform { + String name; + + glslang::TSampler sampler; + }; + + struct ShaderPayload { + // In + GLenum shaderType; + String sourceStr; + + // Out + UniquePtr TShader; + Vector> uniforms; + Vector> samplers; + Int errc = 0; + String log; + }; + + struct ProgramPayload { + // In + Vector shaderTypes; + Vector> shadersToLink; + + // Out + glslang::TProgram linkedProgram; + Vector> programSpirv; + Int errc = 0; + String log; + }; + + inline static EShLanguage GetEShLanguageByShaderType(GLenum shaderType) { + switch (shaderType) { + case GL_VERTEX_SHADER: + return EShLanguage::EShLangVertex; + case GL_FRAGMENT_SHADER: + return EShLanguage::EShLangFragment; + case GL_COMPUTE_SHADER: + return EShLanguage::EShLangCompute; + case GL_TESS_CONTROL_SHADER: + return EShLanguage::EShLangTessControl; + case GL_TESS_EVALUATION_SHADER: + return EShLanguage::EShLangTessEvaluation; + case GL_GEOMETRY_SHADER: + return EShLanguage::EShLangGeometry; + default: + return EShLanguage::EShLangCount; + } + } +} +} +} + +#endif //MG_UTIL_PIPELINES_TYPES_H diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index 3bb8e16f..eac981d0 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -88,4 +88,6 @@ namespace MobileGL { GLInfo RendererGLInfo; BackendCap BackendCapability; }; -} \ No newline at end of file +} + +#include "Pipelines/Types.h" \ No newline at end of file