diff --git a/CMakeLists.txt b/CMakeLists.txt index 59214f83..131ac6dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,8 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp MobileGL/MG_Backend/Init.cpp - + + MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp ) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE diff --git a/MobileGL/Includes.h b/MobileGL/Includes.h index 8755007e..b490c052 100644 --- a/MobileGL/Includes.h +++ b/MobileGL/Includes.h @@ -39,11 +39,15 @@ #include #include #include +#include + #include #include #include #include #include +#include +#include #include #include #include @@ -82,3 +86,7 @@ #include "MG_Impl/EGLImpl/Temporary/TemporaryEGLImpl.h" #include "MG_Impl/GLImpl/Getter/GL_Getter.h" + +#include "MG_Util/Pipelines/Pipeline.hpp" + +#include "MG_Util/Pipelines/Pipelines/Shader/GLSLtoSPIRVPipeline.h" diff --git a/MobileGL/MG_Util/Pipelines/Pipeline.hpp b/MobileGL/MG_Util/Pipelines/Pipeline.hpp index 6fc2c634..7f935247 100644 --- a/MobileGL/MG_Util/Pipelines/Pipeline.hpp +++ b/MobileGL/MG_Util/Pipelines/Pipeline.hpp @@ -1,70 +1,77 @@ -#ifndef AMMOPROTOCOL_MIDDLEWARE_HPP -#define AMMOPROTOCOL_MIDDLEWARE_HPP + #pragma once -#include -#include -#include +#ifndef MG_PIPELINE_HPP +#define MG_PIPELINE_HPP -using next_t = std::function; -using next_ptr_t = std::shared_ptr; +namespace MobileGL { + namespace MG_Util { + namespace Pipeline { + using next_t = std::function; + using next_ptr_t = std::shared_ptr; -template -class middleware { -protected: - using T_ptr = std::shared_ptr; - using callback_t = std::function; -public: - virtual callback_t handler() = 0; -}; + template + class Stage { + protected: + using T_ptr = std::shared_ptr; + using callback_t = std::function; + public: + virtual callback_t handler() = 0; + }; -template -class middleware_manager { -protected: - using T_ptr = std::shared_ptr; - using callback_t = std::function; - using middleware_ptr_t = std::shared_ptr>; -public: - explicit middleware_manager(std::function callback): - callback_(std::move(callback)) {} + template + class Pipeline { + protected: + using T_ptr = std::shared_ptr; + using callback_t = std::function; + using middleware_ptr_t = std::shared_ptr>; + public: + explicit Pipeline(std::function callback) : + callback_(Move(callback)) {} - void use(callback_t middleware) { - middlewares_.emplace_back(std::move(middleware)); + Pipeline &Register(callback_t middleware) { + middlewares_.emplace_back(Move(middleware)); + return *this; + } + + Pipeline &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>( + middlewares_.begin()); + auto next = std::make_shared(); + auto weak_next = std::weak_ptr(next); + + // setup next callback + *next = [this, it_ptr, weak_next, payload] { + auto &it = *it_ptr; + + // if there's something to do + if (it != middlewares_.end()) { + auto &func = *it; + // advance the iterator to the next Stage + ++it; + auto next = weak_next.lock(); + func(payload, next); + // proceed with post-Stage logic + } else { + callback_(*payload); + } + }; + // bootstrap the whole thing + (*next)(); + } + + private: + std::vector middlewares_; + std::vector middleware_storage_; + std::function callback_; + }; + } } +} - void use(middleware_ptr_t middleware) { - middleware_storage_.emplace_back(middleware); - use(middleware->handler()); - } - - void process(T_ptr payload) { - auto it_ptr = std::make_shared::iterator>(middlewares_.begin()); - auto next = std::make_shared(); - auto weak_next = std::weak_ptr(next); - - // setup next callback - *next = [this, it_ptr, weak_next, payload] { - auto& it = *it_ptr; - - // if there's something to do - if (it != middlewares_.end()) { - auto& func = *it; - // advance the iterator to the next middleware - ++it; - auto next = weak_next.lock(); - func(payload, next); - // proceed with post-middleware logic - } else { - callback_(*payload); - } - }; - // bootstrap the whole thing - (*next)(); - } - -private: - std::vector middlewares_; - std::vector middleware_storage_; - std::function callback_; -}; - -#endif //AMMOPROTOCOL_MIDDLEWARE_HPP +#endif //MG_PIPELINE_HPP diff --git a/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp b/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp index 28a5d256..303d14b5 100644 --- a/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp +++ b/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.cpp @@ -3,3 +3,58 @@ // #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 index 89cac17f..6374d362 100644 --- a/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.h +++ b/MobileGL/MG_Util/Pipelines/Shader/GLSLtoSPIRVPipeline.h @@ -2,15 +2,201 @@ // Created by Swung 0x48 on 2025-07-12. // -#ifndef FOLD_CRAFT_LAUNCHER_GLSLTOSPIRVPIPELINE_H -#define FOLD_CRAFT_LAUNCHER_GLSLTOSPIRVPIPELINE_H +#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_; + }; +} +} +} - -class GLSLtoSPIRVPipeline { - -}; - - - -#endif //FOLD_CRAFT_LAUNCHER_GLSLTOSPIRVPIPELINE_H +#endif //MG_GLSLTOSPIRVPIPELINE_H diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index feb60ccc..3bb8e16f 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -47,6 +47,8 @@ namespace MobileGL { using NulloptT = std::nullopt_t; const NulloptT Nullopt = std::nullopt; + using std::format; + using Data = Vector; struct DataPtr { void* data;