diff --git a/CMakeLists.txt b/CMakeLists.txt index 584de828..7e864e06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project("MobileGL") enable_language(CXX) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -21,6 +21,7 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp MobileGL/MG_Util/Converters/MGToStr/GLExtensionConverter.cpp + MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp MobileGL/MG_Impl/GLXImpl/Exporting/Definitions.cpp MobileGL/MG_Impl/GLXImpl/LookUp/LookUp.cpp @@ -35,7 +36,9 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.cpp MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.cpp - + + MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp + MobileGL/MG_State/GLState/Core.cpp MobileGL/MG_State/GLState/BufferState/BufferState.cpp ) diff --git a/MobileGL/Includes.h b/MobileGL/Includes.h index c8cec43f..b6bc78fb 100644 --- a/MobileGL/Includes.h +++ b/MobileGL/Includes.h @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include #include @@ -97,6 +99,7 @@ int __android_log_print(int prio, const char *tag, const char *fmt, ...); #include "MG_Util/Debug/Log.h" #include "MG_Util/Converters/GLToStr/GLEnumConverter.h" #include "MG_Util/Converters/MGToStr/GLExtensionConverter.h" +#include "MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h" #include "MG_Backend/Backends.h" @@ -107,9 +110,11 @@ int __android_log_print(int prio, const char *tag, const char *fmt, ...); #include "MG_Impl/GLImpl/Getter/GL_Getter.h" -#include "MG_Util/Pipelines/PipelineExecutor.hpp" +//#include "MG_Util/Pipelines/PipelineExecutor.hpp" -#include "MG_Util/Pipelines/ShaderCompilationPipeline.h" +//#include "MG_Util/Pipelines/ShaderCompilationPipeline.h" + +#include "MG_Util/ShaderTranspiler/glslang/UniformTraverser.h" #include "MG_State/GLState/BufferState/BufferObject.h" #include "MG_State/GLState/BufferState/BufferState.h" diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index e7ee702e..6c3bcac3 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -1,8 +1,7 @@ cmake_minimum_required(VERSION 3.14) project(MobileGLTest) -# GoogleTest requires at least C++17 -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) include(FetchContent) @@ -31,4 +30,4 @@ include(GoogleTest) gtest_discover_tests(SanityTest) add_subdirectory(Buffer) -#add_subdirectory(Program) +add_subdirectory(Program) diff --git a/MobileGL/MG_Test/Program/CMakeLists.txt b/MobileGL/MG_Test/Program/CMakeLists.txt index 6ff72d88..a703e5bb 100644 --- a/MobileGL/MG_Test/Program/CMakeLists.txt +++ b/MobileGL/MG_Test/Program/CMakeLists.txt @@ -12,8 +12,10 @@ add_executable( ProgramTest.cpp ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp - ${MGL_ROOT}/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.cpp - ${MGL_ROOT}/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.cpp +# ${MGL_ROOT}/MobileGL/MG_Util/Pipelines/ShaderCompilationPipeline.cpp +# ${MGL_ROOT}/MobileGL/MG_Util/Pipelines/ProgramLinkingPipeline.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp ) target_include_directories(ProgramTest PRIVATE diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index a1f1673a..e5644e6c 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -14,3 +14,35 @@ protected: TEST_F(ProgramTest, Sanity) { ASSERT_TRUE(true); } + +const char* vs = R"(#version 150 + +in vec3 Position; +in vec2 UV; +in vec4 Color; + +uniform mat4 ModelViewMat; +uniform mat4 ProjMat; + +out vec2 texCoord; +out vec4 vertexColor; + +void main() { + gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); + + texCoord = UV; + vertexColor = Color; +})"; + +TEST_F(ProgramTest, CompileSimpleVertexShader) { + using namespace MG_Util::ShaderTranspiler; + ShaderAttrib attrib { + .shaderType = GL_VERTEX_SHADER, + .sourceStr = vs + }; + auto res = ShaderCompiler::CompileShader(attrib); + if (!res) { + ASSERT_NE(res.error().errc, 0); + FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log; + } +} diff --git a/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp new file mode 100644 index 00000000..77c5d54e --- /dev/null +++ b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp @@ -0,0 +1,28 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#include "Includes.h" + +namespace MobileGL { + namespace MG_Util { + EShLanguage ConvertGLEnumToEShLanguage(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; + } + } + } +} \ No newline at end of file diff --git a/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h new file mode 100644 index 00000000..03cc400f --- /dev/null +++ b/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.h @@ -0,0 +1,15 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#ifndef MOBILEGL_GLSHADERLANGCONVERTER_H +#define MOBILEGL_GLSHADERLANGCONVERTER_H + +namespace MobileGL { + namespace MG_Util { + EShLanguage ConvertGLEnumToEShLanguage(GLenum shaderType); + } +} + + +#endif //MOBILEGL_GLSHADERLANGCONVERTER_H diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp new file mode 100644 index 00000000..f4797b6d --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -0,0 +1,158 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#include "Includes.h" + +namespace MobileGL { + namespace MG_Util { + namespace ShaderTranspiler { + 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; + } + + CompilerResult ShaderCompiler::CompileShader(const ShaderAttrib& attrib) { + auto shaderType = attrib.shaderType; + auto sourceStr = attrib.sourceStr; + + auto lang = GetEShLanguageByShaderType(shaderType); + if (lang == EShLanguage::EShLangCount) { + ShaderCompileResult r; + r.log += "Error: [Preprocess] Unsupported shader type: " + + ConvertGLEnumToString(shaderType); + r.errc = -1; + return std::unexpected(r); + } + + ShaderCompileResult res; + auto& tshader = res.TShader; + tshader = MakeUnique(lang); + const char* src[] = { sourceStr.c_str() }; + tshader->setStrings(src, 1); + tshader->setInvertY(true); + tshader->setEnvInput(glslang::EShSourceGlsl, lang, glslang::EShClientVulkan, 450); + 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(), 150, ECompatibilityProfile, + /*forceDefaultVersionAndProfile: */false, + /*forwardCompatible: */true, EShMsgDefault)) { + ShaderCompileResult r; + r.log += "Error: [glslang] Cannot compile " + ConvertGLEnumToString(shaderType) + ":\n" + + std::string(tshader->getInfoLog()); + r.errc = -2; + return std::unexpected(r); + } + + return res; + } + } + } +} diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h new file mode 100644 index 00000000..2d05e0c6 --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h @@ -0,0 +1,20 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#ifndef MOBILEGLTEST_SHADERCOMPILER_H +#define MOBILEGLTEST_SHADERCOMPILER_H + +namespace MobileGL { +namespace MG_Util { +namespace ShaderTranspiler { + class ShaderCompiler { + public: + static CompilerResult CompileShader(const ShaderAttrib& attrib); + }; +} +} +} + + +#endif //MOBILEGLTEST_SHADERCOMPILER_H diff --git a/MobileGL/MG_Util/ShaderTranspiler/Types.h b/MobileGL/MG_Util/ShaderTranspiler/Types.h new file mode 100644 index 00000000..cafe488d --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/Types.h @@ -0,0 +1,109 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#ifndef MG_UTIL_SHADERTRANSPILER_TYPES_H +#define MG_UTIL_SHADERTRANSPILER_TYPES_H + +namespace MobileGL { + namespace MG_Util { + namespace ShaderTranspiler { + 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 EmptyType {}; + + struct ShaderAttrib { + GLenum shaderType; + String sourceStr; + }; + + struct CompiledTShader { + UniquePtr TShader; + Vector> uniforms; + Vector> samplers; + }; + + template + struct ShaderCompileResult: + public std::conditional_t { + Int errc = 0; + String log; + }; + + using CompilerResult = std::expected, ShaderCompileResult>; + + 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; + } + } + } + } +} + +#include "ShaderCompiler.h" + +#endif //MG_UTIL_SHADERTRANSPILER_TYPES_H diff --git a/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp new file mode 100644 index 00000000..0146ca4e --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp @@ -0,0 +1,30 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#include "Includes.h" + +namespace MobileGL { +namespace MG_Util { +namespace ShaderTranspiler { + void UniformTraverser::visitSymbol(glslang::TIntermSymbol *symbol) { + 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(); + } + } +} +} +} diff --git a/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.h b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.h new file mode 100644 index 00000000..f6c46a6d --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.h @@ -0,0 +1,25 @@ +// +// Created by Swung 0x48 on 2025/7/20. +// + +#ifndef MOBILEGL_UNIFORMTRAVERSER_H +#define MOBILEGL_UNIFORMTRAVERSER_H + +namespace MobileGL { +namespace MG_Util { +namespace ShaderTranspiler { + class UniformTraverser : public glslang::TIntermTraverser { + public: + UniformTraverser(Vector> &u, Vector> &s) + : uniforms(u), samplers(s) {} + + void visitSymbol(glslang::TIntermSymbol *symbol) override; + + Vector> &uniforms; + Vector> &samplers; + }; +} +} +} + +#endif //MOBILEGL_UNIFORMTRAVERSER_H diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index a35da81c..9080bbd7 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -162,4 +162,4 @@ namespace MobileGL { }; } -#include "Pipelines/Types.h" \ No newline at end of file +#include "MG_Util/ShaderTranspiler/Types.h"