From 383ec854008a6e6d4e66b4be84cd947f43e062f3 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sat, 3 May 2025 22:50:41 +0800 Subject: [PATCH] [Feat] (ProgramState): Implement automatic GLSL uniform management. - Add SPIRV-Cross/glslang integration for uniform reflection. - Auto-detect and assign locations for uniforms/samplers. - Support most types of uniform. - Implement glUniform* functions with type safety. - Add MG_Util::Program: - GLSL-SPIRV conversion - SPIRV uniform reflection - Program uniform dumping --- CMakeLists.txt | 9 +- MG/Includes.h | 10 + .../GLFuncsDefinitions/GLFuncsDefinitions.cpp | 68 +-- .../Implementations/GL/Program/GL_Program.cpp | 165 ++++++ .../Implementations/GL/Program/GL_Program.h | 33 ++ MG/MG_GL/State/Core/GLState.cpp | 48 ++ MG/MG_GL/State/Core/GLState.h | 32 ++ MG/MG_GL/State/Program/ProgramState.cpp | 532 +++++++++++++----- MG/MG_GL/State/Program/ProgramState.h | 57 ++ MG/MG_GL/State/Program/ShaderObject.cpp | 138 +++++ MG/MG_GL/State/Program/ShaderObject.h | 12 + MG/MG_GL/State/Texture/TextureState.cpp | 10 +- MG/MG_UTIL/Program/DebugTool.cpp | 150 +++++ MG/MG_UTIL/Program/DebugTool.h | 16 + MG/MG_UTIL/Program/GLSLTool.cpp | 405 +++++++++++++ MG/MG_UTIL/Program/GLSLTool.h | 182 ++++++ 16 files changed, 1696 insertions(+), 171 deletions(-) create mode 100644 MG/MG_GL/State/Program/ShaderObject.cpp create mode 100644 MG/MG_GL/State/Program/ShaderObject.h create mode 100644 MG/MG_UTIL/Program/DebugTool.cpp create mode 100644 MG/MG_UTIL/Program/DebugTool.h create mode 100644 MG/MG_UTIL/Program/GLSLTool.cpp create mode 100644 MG/MG_UTIL/Program/GLSLTool.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 87ca0874..29be66e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,8 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MG/MG_GL/State/VertexArray/VertexArrayState.cpp MG/MG_GL/State/Buffer/BufferState.cpp - + + MG/MG_GL/State/Program/ShaderObject.cpp MG/MG_GL/State/Program/ProgramState.cpp # MG_GL/BackendLoader @@ -72,6 +73,10 @@ add_library(${CMAKE_PROJECT_NAME} SHARED # MG_UTIL/Debug MG/MG_UTIL/Debug/Debug.cpp + # MG_UTIL/Program + MG/MG_UTIL/Program/DebugTool.cpp + MG/MG_UTIL/Program/GLSLTool.cpp + # MG_RHI/GLES MG/MG_RHI/GLES/Test/TestDrawing.cpp ) @@ -80,7 +85,7 @@ target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ./includes) target_link_libraries(${CMAKE_PROJECT_NAME} ${CMAKE_SOURCE_DIR}/library/arm64-v8a/libglslang.a - #${CMAKE_SOURCE_DIR}/library/arm64-v8a/libspirv-cross-c-shared.so + ${CMAKE_SOURCE_DIR}/library/arm64-v8a/libspirv-cross-c-shared.so #${CMAKE_SOURCE_DIR}/library/arm64-v8a/libshaderconv.so ${CMAKE_SOURCE_DIR}/library/arm64-v8a/libGenericCodeGen.a ${CMAKE_SOURCE_DIR}/library/arm64-v8a/libglslang-default-resource-limits.a diff --git a/MG/Includes.h b/MG/Includes.h index d0af133a..5ba62c99 100644 --- a/MG/Includes.h +++ b/MG/Includes.h @@ -47,6 +47,9 @@ #ifndef MOBILEGL_BUFFERSTATE_H #include "MG_GL/State/Buffer/BufferState.h" #endif +#ifndef MOBILEGL_SHADEROBJECT_H +#include "MG_GL/State/Program/ShaderObject.h" +#endif #ifndef MOBILEGL_PROGRAMSTATE_H #include "MG_GL/State/Program/ProgramState.h" #endif @@ -56,6 +59,12 @@ #ifndef MOBILEGL_DEBUG_H #include "MG_UTIL/Debug/Debug.h" #endif +#ifndef MOBILEGL_GLSLTOOL_H +#include "MG_UTIL/Program/GLSLTool.h" +#endif +#ifndef MOBILEGL_PROGRAM_DEBUGTOOL_H +#include "MG_UTIL/Program/DebugTool.h" +#endif #ifndef MOBILEGL_GL_COMMON_H #include "MG_GL/Implementations/GL/Common/GL_Common.h" #endif @@ -87,6 +96,7 @@ #include #include #include +#include #include #include #include diff --git a/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp b/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp index 153d00bc..3c9c5c1a 100644 --- a/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp +++ b/MG/MG_GL/Implementations/GL/GLFuncsDefinitions/GLFuncsDefinitions.cpp @@ -53,7 +53,7 @@ DECLARE_GL_FUNCTION_HEAD(void, ClearColor, GLfloat red, GLfloat green, GLfloat b DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearDepthf, GLfloat d) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearDepthf, d) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearStencil, GLint s) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearStencil, s) DECLARE_GL_FUNCTION_STUB_HEAD(void, ColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ColorMask, red,green,blue,alpha) -DECLARE_GL_FUNCTION_STUB_HEAD(void, CompileShader, GLuint shader) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompileShader, shader) +DECLARE_GL_FUNCTION_HEAD(void, CompileShader, GLuint shader) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CompileShader, shader) DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTexImage2D, target,level,internalformat,width,height,border,imageSize,data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTexSubImage2D, target,level,xoffset,yoffset,width,height,format,imageSize,data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTexImage2D, target,level,internalformat,x,y,width,height,border) @@ -143,25 +143,25 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, TexParameterfv, GLenum target, GLenum pname, DECLARE_GL_FUNCTION_HEAD(void, TexParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexParameteri, target,pname,param) DECLARE_GL_FUNCTION_STUB_HEAD(void, TexParameteriv, GLenum target, GLenum pname, const GLint *params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexParameteriv, target,pname,params) DECLARE_GL_FUNCTION_HEAD(void, TexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexSubImage2D, target,level,xoffset,yoffset,width,height,format,type,pixels) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1f, GLint location, GLfloat v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1f, location,v0) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1fv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1i, GLint location, GLint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1i, location,v0) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1iv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2f, GLint location, GLfloat v0, GLfloat v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2f, location,v0,v1) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2fv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2i, GLint location, GLint v0, GLint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2i, location,v0,v1) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2iv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3f, location,v0,v1,v2) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3fv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3i, GLint location, GLint v0, GLint v1, GLint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3i, location,v0,v1,v2) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3iv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4f, location,v0,v1,v2,v3) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4fv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4i, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4i, location,v0,v1,v2,v3) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4iv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix4fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform1f, GLint location, GLfloat v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1f, location,v0) +DECLARE_GL_FUNCTION_HEAD(void, Uniform1fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1fv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform1i, GLint location, GLint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1i, location,v0) +DECLARE_GL_FUNCTION_HEAD(void, Uniform1iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1iv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform2f, GLint location, GLfloat v0, GLfloat v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2f, location,v0,v1) +DECLARE_GL_FUNCTION_HEAD(void, Uniform2fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2fv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform2i, GLint location, GLint v0, GLint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2i, location,v0,v1) +DECLARE_GL_FUNCTION_HEAD(void, Uniform2iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2iv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform3f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3f, location,v0,v1,v2) +DECLARE_GL_FUNCTION_HEAD(void, Uniform3fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3fv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform3i, GLint location, GLint v0, GLint v1, GLint v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3i, location,v0,v1,v2) +DECLARE_GL_FUNCTION_HEAD(void, Uniform3iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3iv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform4f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4f, location,v0,v1,v2,v3) +DECLARE_GL_FUNCTION_HEAD(void, Uniform4fv, GLint location, GLsizei count, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4fv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform4i, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4i, location,v0,v1,v2,v3) +DECLARE_GL_FUNCTION_HEAD(void, Uniform4iv, GLint location, GLsizei count, const GLint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4iv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix2fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix3fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix4fv, location,count,transpose,value) DECLARE_GL_FUNCTION_HEAD(void, UseProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UseProgram, program) DECLARE_GL_FUNCTION_STUB_HEAD(void, ValidateProgram, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ValidateProgram, program) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib1f, GLuint index, GLfloat x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib1f, index,x) @@ -191,12 +191,12 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void **params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferPointerv, target,pname,params) DECLARE_GL_FUNCTION_STUB_HEAD(void, DrawBuffers, GLsizei n, const GLenum *bufs) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DrawBuffers, n,bufs) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x2fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x4fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix4x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix4x2fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x4fv, location,count,transpose,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix4x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix4x3fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix2x3fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix3x2fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix2x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix2x4fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix4x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix4x2fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix3x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix3x4fv, location,count,transpose,value) +DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix4x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix4x3fv, location,count,transpose,value) DECLARE_GL_FUNCTION_STUB_HEAD(void, BlitFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlitFramebuffer, srcX0,srcY0,srcX1,srcY1,dstX0,dstY0,dstX1,dstY1,mask,filter) DECLARE_GL_FUNCTION_STUB_HEAD(void, RenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RenderbufferStorageMultisample, target,samples,internalformat,width,height) DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferTextureLayer, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferTextureLayer, target,attachment,texture,level,layer) @@ -221,14 +221,14 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4iv, GLuint index, const GLint DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4uiv, GLuint index, const GLuint *v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4uiv, index,v) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformuiv, GLuint program, GLint location, GLuint *params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformuiv, program,location,params) DECLARE_GL_FUNCTION_STUB_HEAD(GLint, GetFragDataLocation, GLuint program, const GLchar *name) DECLARE_GL_FUNCTION_STUB_END(GLint, GetFragDataLocation, program,name) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1ui, location,v0) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2ui, location,v0,v1) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3ui, location,v0,v1,v2) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4ui, location,v0,v1,v2,v3) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1uiv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2uiv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3uiv, location,count,value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4uiv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1ui, location,v0) +DECLARE_GL_FUNCTION_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2ui, location,v0,v1) +DECLARE_GL_FUNCTION_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3ui, location,v0,v1,v2) +DECLARE_GL_FUNCTION_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4ui, location,v0,v1,v2,v3) +DECLARE_GL_FUNCTION_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1uiv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2uiv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3uiv, location,count,value) +DECLARE_GL_FUNCTION_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint *value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4uiv, location,count,value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearBufferiv, GLenum buffer, GLint drawbuffer, const GLint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearBufferiv, buffer,drawbuffer,value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearBufferuiv, GLenum buffer, GLint drawbuffer, const GLuint *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearBufferuiv, buffer,drawbuffer,value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearBufferfv, GLenum buffer, GLint drawbuffer, const GLfloat *value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearBufferfv, buffer,drawbuffer,value) diff --git a/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp b/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp index 267db769..09e51c10 100644 --- a/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp +++ b/MG/MG_GL/Implementations/GL/Program/GL_Program.cpp @@ -130,4 +130,169 @@ namespace MG_GL::GL { MG_State::SetError(result); MG_Util::Debug::LogE("Error getting shader param: %s", MG_Util::Debug::GLEnumToString(result)); } + + void Uniform1f(GLint location, GLfloat v0) { + MG_Util::Debug::LogD("glUniform1f, location: %d, v0: %f", location, v0); + MG_State::UpdateProgramUniformFloat1(location, v0); + } + + void Uniform2f(GLint location, GLfloat v0, GLfloat v1) { + MG_Util::Debug::LogD("glUniform2f, location: %d, v0: %f, v1: %f", location, v0, v1); + MG_State::UpdateProgramUniformFloat2(location, v0, v1); + } + + void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + MG_Util::Debug::LogD("glUniform3f, location: %d, v0: %f, v1: %f, v2: %f", location, v0, v1, v2); + MG_State::UpdateProgramUniformFloat3(location, v0, v1, v2); + } + + void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { + MG_Util::Debug::LogD("glUniform4f, location: %d, v0: %f, v1: %f, v2: %f, v3: %f", location, v0, v1, v2, v3); + MG_State::UpdateProgramUniformFloat4(location, v0, v1, v2, v3); + } + + void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) { + MG_Util::Debug::LogD("glUniform1fv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformFloatVector1(location, count, value); + } + + void Uniform2fv(GLint location, GLsizei count, const GLfloat* value) { + MG_Util::Debug::LogD("glUniform2fv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformFloatVector2(location, count, value); + } + + void Uniform3fv(GLint location, GLsizei count, const GLfloat* value) { + MG_Util::Debug::LogD("glUniform3fv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformFloatVector3(location, count, value); + } + + void Uniform4fv(GLint location, GLsizei count, const GLfloat* value) { + MG_Util::Debug::LogD("glUniform4fv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformFloatVector4(location, count, value); + } + + void Uniform1i(GLint location, GLint v0) { + MG_Util::Debug::LogD("glUniform1i, location: %d, v0: %d", location, v0); + MG_State::UpdateProgramUniformInt1(location, v0); + } + + void Uniform2i(GLint location, GLint v0, GLint v1) { + MG_Util::Debug::LogD("glUniform2i, location: %d, v0: %d, v1: %d", location, v0, v1); + MG_State::UpdateProgramUniformInt2(location, v0, v1); + } + + void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2) { + MG_Util::Debug::LogD("glUniform3i, location: %d, v0: %d, v1: %d, v2: %d", location, v0, v1, v2); + MG_State::UpdateProgramUniformInt3(location, v0, v1, v2); + } + + void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { + MG_Util::Debug::LogD("glUniform4i, location: %d, v0: %d, v1: %d, v2: %d, v3: %d", location, v0, v1, v2, v3); + MG_State::UpdateProgramUniformInt4(location, v0, v1, v2, v3); + } + + void Uniform1iv(GLint location, GLsizei count, const GLint* value) { + MG_Util::Debug::LogD("glUniform1iv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformIntVector1(location, count, value); + } + + void Uniform2iv(GLint location, GLsizei count, const GLint* value) { + MG_Util::Debug::LogD("glUniform2iv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformIntVector2(location, count, value); + } + + void Uniform3iv(GLint location, GLsizei count, const GLint* value) { + MG_Util::Debug::LogD("glUniform3iv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformIntVector3(location, count, value); + } + + void Uniform4iv(GLint location, GLsizei count, const GLint* value) { + MG_Util::Debug::LogD("glUniform4iv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformIntVector4(location, count, value); + } + + void Uniform1ui(GLint location, GLuint v0) { + MG_Util::Debug::LogD("glUniform1ui, location: %d, v0: %u", location, v0); + MG_State::UpdateProgramUniformUInt1(location, v0); + } + + void Uniform2ui(GLint location, GLuint v0, GLuint v1) { + MG_Util::Debug::LogD("glUniform2ui, location: %d, v0: %u, v1: %u", location, v0, v1); + MG_State::UpdateProgramUniformUInt2(location, v0, v1); + } + + void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) { + MG_Util::Debug::LogD("glUniform3ui, location: %d, v0: %u, v1: %u, v2: %u", location, v0, v1, v2); + MG_State::UpdateProgramUniformUInt3(location, v0, v1, v2); + } + + void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { + MG_Util::Debug::LogD("glUniform4ui, location: %d, v0: %u, v1: %u, v2: %u, v3: %u", location, v0, v1, v2, v3); + MG_State::UpdateProgramUniformUInt4(location, v0, v1, v2, v3); + } + + void Uniform1uiv(GLint location, GLsizei count, const GLuint* value) { + MG_Util::Debug::LogD("glUniform1uiv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformUIntVector1(location, count, value); + } + + void Uniform2uiv(GLint location, GLsizei count, const GLuint* value) { + MG_Util::Debug::LogD("glUniform2uiv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformUIntVector2(location, count, value); + } + + void Uniform3uiv(GLint location, GLsizei count, const GLuint* value) { + MG_Util::Debug::LogD("glUniform3uiv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformUIntVector3(location, count, value); + } + + void Uniform4uiv(GLint location, GLsizei count, const GLuint* value) { + MG_Util::Debug::LogD("glUniform4uiv, location: %d, count: %d", location, count); + MG_State::UpdateProgramUniformUIntVector4(location, count, value); + } + + void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix2fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix2x2Vector(location, count, transpose, value); + } + + void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix3fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix3x3Vector(location, count, transpose, value); + } + + void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix4fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix4x4Vector(location, count, transpose, value); + } + + void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix2x3fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix2x3Vector(location, count, transpose, value); + } + + void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix2x4fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix2x4Vector(location, count, transpose, value); + } + + void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix3x2fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix3x2Vector(location, count, transpose, value); + } + + void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix3x4fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix3x4Vector(location, count, transpose, value); + } + + void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix4x2fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix4x2Vector(location, count, transpose, value); + } + + void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { + MG_Util::Debug::LogD("glUniformMatrix4x3fv, location: %d, count: %d, transpose: %d", location, count, transpose); + MG_State::UpdateProgramUniformMatrix4x3Vector(location, count, transpose, value); + } } \ No newline at end of file diff --git a/MG/MG_GL/Implementations/GL/Program/GL_Program.h b/MG/MG_GL/Implementations/GL/Program/GL_Program.h index 53039296..23bb8a62 100644 --- a/MG/MG_GL/Implementations/GL/Program/GL_Program.h +++ b/MG/MG_GL/Implementations/GL/Program/GL_Program.h @@ -22,6 +22,39 @@ namespace MG_GL::GL { GLint GetUniformLocation(GLuint program, const GLchar* name); void GetProgramiv(GLuint program, GLenum pname, GLint* params); void GetShaderiv(GLuint shader, GLenum pname, GLint* params); + void Uniform1f(GLint location, GLfloat v0); + void Uniform2f(GLint location, GLfloat v0, GLfloat v1); + void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); + void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + void Uniform1fv(GLint location, GLsizei count, const GLfloat* value); + void Uniform2fv(GLint location, GLsizei count, const GLfloat* value); + void Uniform3fv(GLint location, GLsizei count, const GLfloat* value); + void Uniform4fv(GLint location, GLsizei count, const GLfloat* value); + void Uniform1i(GLint location, GLint v0); + void Uniform2i(GLint location, GLint v0, GLint v1); + void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2); + void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + void Uniform1iv(GLint location, GLsizei count, const GLint* value); + void Uniform2iv(GLint location, GLsizei count, const GLint* value); + void Uniform3iv(GLint location, GLsizei count, const GLint* value); + void Uniform4iv(GLint location, GLsizei count, const GLint* value); + void Uniform1ui(GLint location, GLuint v0); + void Uniform2ui(GLint location, GLuint v0, GLuint v1); + void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); + void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); + void Uniform1uiv(GLint location, GLsizei count, const GLuint* value); + void Uniform2uiv(GLint location, GLsizei count, const GLuint* value); + void Uniform3uiv(GLint location, GLsizei count, const GLuint* value); + void Uniform4uiv(GLint location, GLsizei count, const GLuint* value); + void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); } #endif //MOBILEGL_GL_PROGRAM_H diff --git a/MG/MG_GL/State/Core/GLState.cpp b/MG/MG_GL/State/Core/GLState.cpp index ce86134f..dff2f3dd 100644 --- a/MG/MG_GL/State/Core/GLState.cpp +++ b/MG/MG_GL/State/Core/GLState.cpp @@ -240,6 +240,54 @@ namespace MG_State { GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params) { return MG_State_T::programState->QueryShaderStateIntVector(shader, pname, params); } + +#define IMPLEMENT_UNIFORM_FUNCTIONS(type, suffix, vecType) \ +void UpdateProgramUniform##suffix##1(GLint location, type v0) { \ + MG_State_T::programState->UpdateUniform##suffix##1(location, v0); \ +} \ +void UpdateProgramUniform##suffix##2(GLint location, type v0, type v1) { \ + MG_State_T::programState->UpdateUniform##suffix##2(location, v0, v1); \ +} \ +void UpdateProgramUniform##suffix##3(GLint location, type v0, type v1, type v2) { \ + MG_State_T::programState->UpdateUniform##suffix##3(location, v0, v1, v2); \ +} \ +void UpdateProgramUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3) { \ + MG_State_T::programState->UpdateUniform##suffix##4(location, v0, v1, v2, v3); \ + } \ +void UpdateProgramUniform##suffix##Vector1(GLint location, GLsizei count, const type* value) { \ + MG_State_T::programState->UpdateUniform##suffix##Vector1(location, count,value); \ + } \ +void UpdateProgramUniform##suffix##Vector2(GLint location, GLsizei count, const type* value) { \ + MG_State_T::programState->UpdateUniform##suffix##Vector2(location, count, value); \ + } \ +void UpdateProgramUniform##suffix##Vector3(GLint location, GLsizei count, const type* value) { \ + MG_State_T::programState->UpdateUniform##suffix##Vector3(location, count, value); \ + } \ +void UpdateProgramUniform##suffix##Vector4(GLint location, GLsizei count, const type* value) { \ + MG_State_T::programState->UpdateUniform##suffix##Vector4(location, count, value); \ + } + + IMPLEMENT_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT_VEC4) + IMPLEMENT_UNIFORM_FUNCTIONS(GLint, Int, GL_INT_VEC4) + IMPLEMENT_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT_VEC4) + IMPLEMENT_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL_VEC4) +#undef IMPLEMENT_UNIFORM_FUNCTIONS + +#define IMPLEMENT_MATRIX_FUNCTIONS(suffix, matrixType) \ +void UpdateProgramUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { \ + MG_State_T::programState->UpdateUniformMatrix##suffix##Vector(location, count, transpose, value); \ +} + + IMPLEMENT_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2) + IMPLEMENT_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3) + IMPLEMENT_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4) + IMPLEMENT_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3) + IMPLEMENT_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4) + IMPLEMENT_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2) + IMPLEMENT_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4) + IMPLEMENT_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2) + IMPLEMENT_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3) +#undef IMPLEMENT_MATRIX_FUNCTIONS GLuint GetCurrentProgram() { return MG_State_T::programState->GetCurrentProgram(); diff --git a/MG/MG_GL/State/Core/GLState.h b/MG/MG_GL/State/Core/GLState.h index f31e0661..818b2b61 100644 --- a/MG/MG_GL/State/Core/GLState.h +++ b/MG/MG_GL/State/Core/GLState.h @@ -81,6 +81,38 @@ namespace MG_State { GLint QueryProgramUniformLocation(GLuint program, const GLchar* name); GLenum QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params); GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params); + template + GLenum SetUniform(GLuint program, GLint location, GLsizei count, const T* value, GLenum type); + + template + GLenum SetUniformMatrix(GLuint program, GLint location, GLsizei count, GLboolean transpose, const T* value, GLenum matrixType); + +#define DECLARE_UNIFORM_FUNCTIONS(type, suffix, vecType) \ + void UpdateProgramUniform##suffix##1(GLint location, type v0); \ + void UpdateProgramUniform##suffix##2(GLint location, type v0, type v1); \ + void UpdateProgramUniform##suffix##3(GLint location, type v0, type v1, type v2); \ + void UpdateProgramUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3); \ + void UpdateProgramUniform##suffix##Vector1(GLint location, GLsizei count, const type* value); \ + void UpdateProgramUniform##suffix##Vector2(GLint location, GLsizei count, const type* value); \ + void UpdateProgramUniform##suffix##Vector3(GLint location, GLsizei count, const type* value); \ + void UpdateProgramUniform##suffix##Vector4(GLint location, GLsizei count, const type* value); + DECLARE_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT) + DECLARE_UNIFORM_FUNCTIONS(GLint, Int, GL_INT) + DECLARE_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT) + DECLARE_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL) +#undef DECLARE_UNIFORM_FUNCTIONS +#define DECLARE_MATRIX_FUNCTIONS(suffix, matrixType) \ + void UpdateProgramUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + DECLARE_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2) + DECLARE_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3) + DECLARE_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4) + DECLARE_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3) + DECLARE_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4) + DECLARE_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2) + DECLARE_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4) + DECLARE_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2) + DECLARE_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3) +#undef DECLARE_MATRIX_FUNCTIONS GLuint GetCurrentProgram(); bool SetProgramStatus(GLuint program, GLboolean status); diff --git a/MG/MG_GL/State/Program/ProgramState.cpp b/MG/MG_GL/State/Program/ProgramState.cpp index 02aecf29..6a0a11e0 100644 --- a/MG/MG_GL/State/Program/ProgramState.cpp +++ b/MG/MG_GL/State/Program/ProgramState.cpp @@ -1,258 +1,530 @@ // // Created by BZLZHH on 2025/5/1. -// // TODO: Add more gl error check for buffer state manager. // TODO: Check if the state machine really meets up to OpenGL 3 standard. #include "ProgramState.h" -GLenum ProgramState::CreateShader(GLenum type, GLuint* shader) { - if (!shader) return GL_INVALID_VALUE; - if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) - return GL_INVALID_ENUM; +// Re-Include Includes.h, cuz of the absence of Program/DebugTool.h and Program/GLSLTool.cpp. +#undef MOBILEGL_GLSLTOOL_H +#undef MOBILEGL_PROGRAM_DEBUGTOOL_H +#include "../../../Includes.h" - GLuint id = freeShaderIds_.empty() ? ++lastShaderId_ : *freeShaderIds_.begin(); - if (!freeShaderIds_.empty()) freeShaderIds_.erase(freeShaderIds_.begin()); +ProgramState::ProgramState() { + glslang::InitializeProcess(); +} - ShaderObject obj; - obj.type = type; - obj.compiled = UncertainBool::False; - obj.markedForDeletion = false; - shaders_[id] = obj; - *shader = id; - return GL_NO_ERROR; +ProgramState::~ProgramState() { + glslang::FinalizeProcess(); } GLenum ProgramState::CreateProgram(GLuint* program) { - if (!program) return GL_INVALID_VALUE; + MG_Util::Debug::LogD("MG_State: Program: CreateProgram called, program ptr=%p", program); + if (!program) { + MG_Util::Debug::LogE("MG_State: Program: CreateProgram error: program pointer is null"); + return GL_INVALID_VALUE; + } GLuint id = freeProgramIds_.empty() ? ++lastProgramId_ : *freeProgramIds_.begin(); - if (!freeProgramIds_.empty()) freeProgramIds_.erase(freeProgramIds_.begin()); + if (!freeProgramIds_.empty()) + freeProgramIds_.erase(freeProgramIds_.begin()); ProgramObject obj; - obj.linked = UncertainBool::False; + obj.linked = {UncertainBool::Unknown, UncertainBool::False}; + obj.linkStatus = GL_FALSE; obj.markedForDeletion = false; programs_[id] = obj; *program = id; - return GL_NO_ERROR; -} - -GLenum ProgramState::DeleteShader(GLuint shader) { - if (!ValidateShader_(shader)) return GL_INVALID_VALUE; - - if (shaders_[shader].markedForDeletion) return GL_NO_ERROR; - - bool inUse = false; - for (auto& [progId, program] : programs_) { - auto it = std::find(program.attachedShaders.begin(), - program.attachedShaders.end(), shader); - if (it != program.attachedShaders.end()) { - inUse = true; - break; - } - } - - if (inUse) { - shaders_[shader].markedForDeletion = true; - } else { - shaders_.erase(shader); - freeShaderIds_.insert(shader); - } + MG_Util::Debug::LogD("MG_State: Program: CreateProgram success, new id=%u", id); return GL_NO_ERROR; } GLenum ProgramState::DeleteProgram(GLuint program) { - if (!ValidateProgram_(program)) return GL_INVALID_VALUE; + MG_Util::Debug::LogD("MG_State: Program: DeleteProgram called, id=%u", program); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: DeleteProgram error: invalid program id %u", program); + return GL_INVALID_VALUE; + } programs_.erase(program); freeProgramIds_.insert(program); if (currentProgram_ == program) currentProgram_ = 0; + MG_Util::Debug::LogD("MG_State: Program: DeleteProgram success, id=%u", program); return GL_NO_ERROR; } GLenum ProgramState::LinkShaderToProgram(GLuint program, GLuint shader) { - if (!ValidateProgram_(program) || !ValidateShader_(shader)) + MG_Util::Debug::LogD("MG_State: Program: LinkShaderToProgram called, program=%u, shader=%u", + program, shader); + if (!ValidateProgram_(program) || !ValidateShader_(shader)) { + MG_Util::Debug::LogE("MG_State: Program: LinkShaderToProgram error: invalid ids program=%u shader=%u", + program, shader); return GL_INVALID_VALUE; + } auto& prog = programs_[program]; if (std::find(prog.attachedShaders.begin(), - prog.attachedShaders.end(), shader) != prog.attachedShaders.end()) + prog.attachedShaders.end(), shader) != prog.attachedShaders.end()) { + MG_Util::Debug::LogW("MG_State: Program: LinkShaderToProgram warning: shader %u already attached to program %u", + shader, program); return GL_INVALID_OPERATION; + } prog.attachedShaders.push_back(shader); - return GL_NO_ERROR; -} - -GLenum ProgramState::UploadShaderSource(GLuint shader, GLsizei count, - const GLchar** string, const GLint* length) { - if (!ValidateShader_(shader)) return GL_INVALID_VALUE; - if (count < 0) return GL_INVALID_VALUE; - - std::string source; - for (GLsizei i = 0; i < count; ++i) { - const GLchar* str = string[i]; - GLint len = (length && length[i] >= 0) ? length[i] : strlen(str); - source.append(str, len); - } - shaders_[shader].source = std::move(source); - return GL_NO_ERROR; -} - -GLenum ProgramState::BuildShaderStage(GLuint shader) { - if (!ValidateShader_(shader)) return GL_INVALID_VALUE; - - auto& obj = shaders_[shader]; - // TODO: Add glslang to convert it to SPIR-V first, and then check it in the actual backend. - obj.compiled = {UncertainBool::Unknown, UncertainBool::True}; - obj.compileStatus = GL_TRUE; - obj.infoLog.clear(); - + MG_Util::Debug::LogD("MG_State: Program: LinkShaderToProgram success: shader %u attached to program %u", + shader, program); return GL_NO_ERROR; } GLenum ProgramState::FinalizeProgramPipeline(GLuint program) { - if (!ValidateProgram_(program)) return GL_INVALID_VALUE; + MG_Util::Debug::LogD("MG_State: Program: FinalizeProgramPipeline called, id=%u", program); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: invalid program id %u", program); + return GL_INVALID_VALUE; + } auto& prog = programs_[program]; for (GLuint shader : prog.attachedShaders) { - if (!shaders_[shader].compiled.toBool()) + if (!shaders_[shader].compiled.toBool()) { + MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: shader %u not compiled", shader); return GL_INVALID_OPERATION; + } } - // TODO: Check the actual program linking status. - // We might consider using a program emulator (or real backend checking?) or something better in the future. - prog.linked = {UncertainBool::Unknown, UncertainBool::True}; - prog.linkStatus = GL_TRUE; prog.infoLog.clear(); + + for (GLuint shaderId : prog.attachedShaders) { + auto& shader = shaders_[shaderId]; + if (!shader.compiled.toBool() || shader.compiledSpirv.empty()) { + prog.infoLog = "Program linking failed: \n" + + MG_Util::Program::GetShaderTypeName(shader.type) + " is not compiled."; + prog.linked = UncertainBool::False; + prog.linkStatus = GL_FALSE; + MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: %s", prog.infoLog.c_str()); + return GL_INVALID_OPERATION; + } + } + + std::vector> allSpirv = + MG_Util::Program::CompileMultipleShadersToSPIRV(*this, prog, prog.infoLog); + + MG_Util::Program::ReflectSPIRVUniforms(allSpirv, prog, prog.infoLog); + if (!prog.infoLog.empty()) { + prog.linked = UncertainBool::False; + prog.linkStatus = GL_FALSE; + prog.infoLog = "Program linking failed: " + prog.infoLog; + MG_Util::Debug::LogE("MG_State: Program: FinalizeProgramPipeline error: %s", prog.infoLog.c_str()); + return GL_INVALID_OPERATION; + } for (auto& [name, index] : prog.attribBindings) { prog.attribLocations[name] = index; } - + + prog.linked = {UncertainBool::Unknown, UncertainBool::True}; + prog.linkStatus = GL_TRUE; + CleanupShaders_(); + + MG_Util::Program::DumpUniforms(*this, program); + MG_Util::Debug::LogD("MG_State: Program: FinalizeProgramPipeline success, id=%u", program); return GL_NO_ERROR; } GLenum ProgramState::ActivateRenderProgram(GLuint program) { - if (program != 0 && !ValidateProgram_(program)) + MG_Util::Debug::LogD("MG_State: Program: ActivateRenderProgram called, id=%u", program); + if (program != 0 && !ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: ActivateRenderProgram error: invalid program id %u", program); return GL_INVALID_VALUE; + } + MG_Util::Program::DumpCurrentUniforms(*this); currentProgram_ = program; + MG_Util::Program::DumpCurrentUniforms(*this); + MG_Util::Debug::LogD("MG_State: Program: ActivateRenderProgram success, current program=%u", currentProgram_); return GL_NO_ERROR; } GLenum ProgramState::DefineProgramAttributeBinding(GLuint program, GLuint index, const GLchar* name) { - if (!ValidateProgram_(program)) return GL_INVALID_VALUE; - if (index >= GL_MAX_VERTEX_ATTRIBS) return GL_INVALID_VALUE; + MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeBinding called, program=%u, index=%u, name=%s", + program, index, name); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeBinding error: invalid program id %u", program); + return GL_INVALID_VALUE; + } + if (index >= GL_MAX_VERTEX_ATTRIBS) { + MG_Util::Debug::LogE("MG_State: Program: DefineProgramAttributeBinding error: index %u out of range", index); + return GL_INVALID_VALUE; + } programs_[program].attribBindings[name] = index; + MG_Util::Debug::LogD("MG_State: Program: DefineProgramAttributeBinding success: %s -> %u", name, index); return GL_NO_ERROR; } GLint ProgramState::QueryProgramAttributeBinding(GLuint program, const GLchar* name) { - if (!ValidateProgram_(program)) return -1; + MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeBinding called, program=%u, name=%s", + program, name); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: QueryProgramAttributeBinding error: invalid program id %u", program); + return -1; + } auto& prog = programs_[program]; - if (prog.attribLocations.count(name)) - return prog.attribLocations[name]; - return -1; -} - -GLint ProgramState::QueryProgramUniformLocation(GLuint program, const GLchar* name) { - if (!ValidateProgram_(program)) return -1; - - auto& prog = programs_[program]; - if (prog.uniformLocations.count(name)) - return prog.uniformLocations[name]; + auto it = prog.attribLocations.find(name); + if (it != prog.attribLocations.end()) { + GLint loc = it->second; + MG_Util::Debug::LogD("MG_State: Program: QueryProgramAttributeBinding success: %s -> %d", name, loc); + return loc; + } + MG_Util::Debug::LogW("MG_State: Program: QueryProgramAttributeBinding warning: name '%s' not found", name); return -1; } GLenum ProgramState::QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params) { - if (!ValidateProgram_(program)) return GL_INVALID_VALUE; + MG_Util::Debug::LogD("MG_State: Program: QueryProgramStateIntVector called, program=%u, pname=0x%X", + program, pname); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: QueryProgramStateIntVector error: invalid program id %u", program); + return GL_INVALID_VALUE; + } auto& prog = programs_[program]; switch (pname) { - case GL_LINK_STATUS: *params = prog.linkStatus; break; - case GL_DELETE_STATUS: *params = prog.markedForDeletion; break; - case GL_ATTACHED_SHADERS: *params = (GLint)prog.attachedShaders.size(); break; - default: return GL_INVALID_ENUM; + case GL_LINK_STATUS: *params = prog.linkStatus; break; + case GL_DELETE_STATUS: *params = prog.markedForDeletion; break; + case GL_ATTACHED_SHADERS:*params = (GLint)prog.attachedShaders.size(); break; + default: + MG_Util::Debug::LogE("MG_State: Program: QueryProgramStateIntVector error: invalid pname 0x%X", pname); + return GL_INVALID_ENUM; } + MG_Util::Debug::LogD("MG_State: Program: QueryProgramStateIntVector success: value=%d", *params); return GL_NO_ERROR; } GLenum ProgramState::QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params) { - if (!ValidateShader_(shader)) return GL_INVALID_VALUE; + MG_Util::Debug::LogD("MG_State: Program: QueryShaderStateIntVector called, shader=%u, pname=0x%X", + shader, pname); + if (!ValidateShader_(shader)) { + MG_Util::Debug::LogE("MG_State: Program: QueryShaderStateIntVector error: invalid shader id %u", shader); + return GL_INVALID_VALUE; + } auto& obj = shaders_[shader]; switch (pname) { case GL_COMPILE_STATUS: *params = obj.compileStatus; break; - case GL_DELETE_STATUS: *params = obj.markedForDeletion; break; - case GL_SHADER_TYPE: *params = obj.type; break; - default: return GL_INVALID_ENUM; + case GL_DELETE_STATUS: *params = obj.markedForDeletion; break; + case GL_SHADER_TYPE: *params = obj.type; break; + default: + MG_Util::Debug::LogE("MG_State: Program: QueryShaderStateIntVector error: invalid pname 0x%X", pname); + return GL_INVALID_ENUM; } + MG_Util::Debug::LogD("MG_State: Program: QueryShaderStateIntVector success: value=%d", *params); return GL_NO_ERROR; } -bool ProgramState::SetProgramStatus(GLuint program, GLboolean status) { - if (!ValidateProgram_(program)) return false; +template +GLenum ProgramState::SetUniform(GLuint program, GLint location, GLsizei count, const T* value, GLenum type) { + MG_Util::Debug::LogD("MG_State: Program: SetUniform called, program=%u, location=%d, count=%d, type=0x%X", + program, location, count, type); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: SetUniform error: invalid program id %u", program); + return GL_INVALID_VALUE; + } + if (location < -1) { + MG_Util::Debug::LogE("MG_State: Program: SetUniform error: invalid location %d", location); + return GL_INVALID_VALUE; + } + if (count < 0) { + MG_Util::Debug::LogE("MG_State: Program: SetUniform error: invalid count %d", count); + return GL_INVALID_VALUE; + } + if (location == -1) { + MG_Util::Debug::LogW("MG_State: Program: SetUniform warning: location -1, no-op"); + return GL_NO_ERROR; + } + + ProgramObject& prog = programs_[program]; + std::string uniformName; + for (const auto& pair : prog.uniformLocations) { + if (pair.second == location) { + uniformName = pair.first; + break; + } + } + if (uniformName.empty()) { + MG_Util::Debug::LogE("MG_State: Program: SetUniform error: no uniform at location %d in program %u", + location, program); + return GL_INVALID_OPERATION; + } + + UniformValue& uniform = prog.uniformValues[uniformName]; + uniform.setData(type, count, value); + MG_Util::Debug::LogD("MG_State: Program: SetUniform success: %s set", uniformName.c_str()); + return GL_NO_ERROR; +} + +template +GLenum ProgramState::SetUniformMatrix(GLuint program, GLint location, GLsizei count, GLboolean transpose, const T* value, GLenum matrixType) { + MG_Util::Debug::LogD("MG_State: Program: SetUniformMatrix called, program=%u, location=%d, count=%d, matrixType=0x%X", + program, location, count, matrixType); + (void)transpose; + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: invalid program id %u", program); + return GL_INVALID_VALUE; + } + if (location < -1) { + MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: invalid location %d", location); + return GL_INVALID_VALUE; + } + if (count < 0) { + MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: invalid count %d", count); + return GL_INVALID_VALUE; + } + if (location == -1) { + MG_Util::Debug::LogW("MG_State: Program: SetUniformMatrix warning: location -1, no-op"); + return GL_NO_ERROR; + } + + ProgramObject& prog = programs_[program]; + std::string uniformName; + for (const auto& pair : prog.uniformLocations) { + if (pair.second == location) { + uniformName = pair.first; + break; + } + } + if (uniformName.empty()) { + MG_Util::Debug::LogE("MG_State: Program: SetUniformMatrix error: no uniform at location %d in program %u", + location, program); + return GL_INVALID_OPERATION; + } + + UniformValue& uniform = prog.uniformValues[uniformName]; + uniform.setData(matrixType, count * MG_Util::Program::GetMatrixElementCount(matrixType), value); + MG_Util::Debug::LogD("MG_State: Program: SetUniformMatrix success: %s set", uniformName.c_str()); + return GL_NO_ERROR; +} + +#define IMPLEMENT_UNIFORM_FUNCTIONS(type, suffix, vecType) \ +void ProgramState::UpdateUniform##suffix##1(GLint location, type v0) { \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "1 called, location=%d", location); \ + SetUniform(currentProgram_, location, 1, &v0, vecType); \ +} \ +void ProgramState::UpdateUniform##suffix##2(GLint location, type v0, type v1) { \ + type values[2] = {v0, v1}; \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "2 called, location=%d", location); \ + SetUniform(currentProgram_, location, 1, values, vecType); \ +} \ +void ProgramState::UpdateUniform##suffix##3(GLint location, type v0, type v1, type v2) { \ + type values[3] = {v0, v1, v2}; \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "3 called, location=%d", location); \ + SetUniform(currentProgram_, location, 1, values, vecType); \ +} \ +void ProgramState::UpdateUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3) { \ + type values[4] = {v0, v1, v2, v3}; \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "4 called, location=%d", location); \ + SetUniform(currentProgram_, location, 1, values, vecType); \ + } \ +void ProgramState::UpdateUniform##suffix##Vector1(GLint location, GLsizei count, const type* value) { \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector1 called, location=%d, count=%d", location, count); \ + SetUniform(currentProgram_, location, count, value, vecType); \ + } \ +void ProgramState::UpdateUniform##suffix##Vector2(GLint location, GLsizei count, const type* value) { \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector2 called, location=%d, count=%d", location, count); \ + SetUniform(currentProgram_, location, count * 2, value, vecType); \ + } \ +void ProgramState::UpdateUniform##suffix##Vector3(GLint location, GLsizei count, const type* value) { \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector3 called, location=%d, count=%d", location, count); \ + SetUniform(currentProgram_, location, count * 3, value, vecType); \ + } \ +void ProgramState::UpdateUniform##suffix##Vector4(GLint location, GLsizei count, const type* value) { \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniform" #suffix "Vector4 called, location=%d, count=%d", location, count); \ + SetUniform(currentProgram_, location, count * 4, value, vecType); \ + } + +IMPLEMENT_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT_VEC4) +IMPLEMENT_UNIFORM_FUNCTIONS(GLint, Int, GL_INT_VEC4) +IMPLEMENT_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT_VEC4) +IMPLEMENT_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL_VEC4) +#undef IMPLEMENT_UNIFORM_FUNCTIONS + +#define IMPLEMENT_MATRIX_FUNCTIONS(suffix, matrixType) \ +void ProgramState::UpdateUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { \ + MG_Util::Debug::LogD("MG_State: Program: UpdateUniformMatrix" #suffix "Vector called, location=%d, count=%d", location, count); \ + SetUniformMatrix(currentProgram_, location, count, transpose, value, matrixType); \ +} + +IMPLEMENT_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2) +IMPLEMENT_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3) +IMPLEMENT_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4) +IMPLEMENT_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3) +IMPLEMENT_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4) +IMPLEMENT_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2) +IMPLEMENT_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4) +IMPLEMENT_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2) +IMPLEMENT_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3) +#undef IMPLEMENT_MATRIX_FUNCTIONS + +GLint ProgramState::QueryProgramUniformLocation(GLuint program, const GLchar* name) { + MG_Util::Debug::LogD("MG_State: Program: QueryProgramUniformLocation called, program=%u, name=%s", program, name); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: QueryProgramUniformLocation error: invalid program id %u", program); + return -1; + } auto& prog = programs_[program]; - if (prog.linked && status != GL_TRUE) { + auto it = prog.uniformLocations.find(name); + if (it != prog.uniformLocations.end()) { + GLint loc = it->second; + MG_Util::Debug::LogD("MG_State: Program: QueryProgramUniformLocation success: %s -> %d", name, loc); + return loc; + } + MG_Util::Debug::LogW("MG_State: Program: QueryProgramUniformLocation warning: name '%s' not found", name); + return -1; +} + +bool ProgramState::SetProgramStatus(GLuint program, GLboolean status) { + MG_Util::Debug::LogD("MG_State: Program: SetProgramStatus called, program=%u, status=%d", program, status); + if (!ValidateProgram_(program)) { + MG_Util::Debug::LogE("MG_State: Program: SetProgramStatus error: invalid program id %u", program); return false; } - if (status == GL_TRUE) - prog.linked = true; - else - prog.linked = false; + auto& prog = programs_[program]; + if (prog.linked.getValue() != UncertainBool::Unknown) { + MG_Util::Debug::LogW("MG_State: Program: SetProgramStatus warning: link state already known"); + return false; + } + prog.linked = (status == GL_TRUE) ? UncertainBool::True : UncertainBool::False; prog.linkStatus = status; + MG_Util::Debug::LogD("MG_State: Program: SetProgramStatus success, status=%d", status); return true; } -bool ProgramState::SetShaderStatus(GLuint shader, GLboolean status) { - if (!ValidateShader_(shader)) return false; - auto& obj = shaders_[shader]; - if (status == GL_TRUE) - obj.compiled = true; - else - obj.compiled = false; - obj.compileStatus = status; - return true; +GLuint ProgramState::GetCurrentProgram() const { + MG_Util::Debug::LogD("MG_State: Program: GetCurrentProgram called, returning %u", currentProgram_); + return currentProgram_; } -bool ProgramState::ValidateShader_(GLuint shader) { - return shaders_.count(shader) && !shaders_[shader].markedForDeletion; +ShaderObject ProgramState::GetShaderObject(GLuint shader) const { + MG_Util::Debug::LogD("MG_State: Program: GetShaderObject called, shader=%u", shader); + auto it = shaders_.find(shader); + if (it == shaders_.end()) { + MG_Util::Debug::LogW("MG_State: Program: GetShaderObject warning: invalid shader id %u", shader); + return ShaderObject(); + } + MG_Util::Debug::LogD("MG_State: Program: GetShaderObject success, returning object"); + return it->second; +} + +ProgramObject ProgramState::GetProgramObject(GLuint program) const { + MG_Util::Debug::LogD("MG_State: Program: GetProgramObject called, program=%u", program); + auto it = programs_.find(program); + if (it == programs_.end()) { + MG_Util::Debug::LogW("MG_State: Program: GetProgramObject warning: invalid program id %u", program); + return ProgramObject(); + } + MG_Util::Debug::LogD("MG_State: Program: GetProgramObject success, returning object"); + return it->second; } bool ProgramState::ValidateProgram_(GLuint program) { - return programs_.count(program) && !programs_[program].markedForDeletion; + bool ok = programs_.count(program) && !programs_[program].markedForDeletion; + MG_Util::Debug::LogD("MG_State: Program: ValidateProgram_ called, program=%u, result=%d", program, ok); + return ok; } void ProgramState::CleanupShaders_() { + MG_Util::Debug::LogD("MG_State: Program: CleanupShaders_ start"); auto it = shaders_.begin(); while (it != shaders_.end()) { if (it->second.markedForDeletion) { bool inUse = false; for (auto& [progId, program] : programs_) { if (std::find(program.attachedShaders.begin(), - program.attachedShaders.end(), it->first) - != program.attachedShaders.end()) { + program.attachedShaders.end(), it->first) != program.attachedShaders.end()) { inUse = true; break; } } if (!inUse) { + MG_Util::Debug::LogD("MG_State: Program: CleanupShaders_ deleting shader %u", it->first); freeShaderIds_.insert(it->first); it = shaders_.erase(it); - } else { - ++it; + continue; } - } else { - ++it; } + ++it; } + MG_Util::Debug::LogD("MG_State: Program: CleanupShaders_ end"); } -GLuint ProgramState::GetCurrentProgram() const { - return currentProgram_; -} \ No newline at end of file +// UniformValue +template +void UniformValue::setData(GLenum uniformType, GLsizei numElements, const T* values) { + MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData called, type=0x%X, count=%d", uniformType, numElements); + type = uniformType; + count = numElements; + + floatData.clear(); + intData.clear(); + uintData.clear(); + boolData.clear(); + + for (GLsizei i = 0; i < numElements; ++i) { + switch (uniformType) { + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + floatData.push_back(static_cast(values[i])); + break; + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_1D_ARRAY_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_BUFFER: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + intData.push_back(static_cast(values[i])); + break; + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_VEC2: + case GL_UNSIGNED_INT_VEC3: + case GL_UNSIGNED_INT_VEC4: + uintData.push_back(static_cast(values[i])); + break; + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + boolData.push_back(values[i] ? GL_TRUE : GL_FALSE); + break; + default: + MG_Util::Debug::LogW("MG_State: Program: UniformValue::setData warning: unsupported type 0x%X", uniformType); + break; + } + } + MG_Util::Debug::LogD("MG_State: Program: UniformValue::setData end"); +} diff --git a/MG/MG_GL/State/Program/ProgramState.h b/MG/MG_GL/State/Program/ProgramState.h index 6fc292c5..5ea2ce7c 100644 --- a/MG/MG_GL/State/Program/ProgramState.h +++ b/MG/MG_GL/State/Program/ProgramState.h @@ -5,18 +5,35 @@ #ifndef MOBILEGL_PROGRAMSTATE_H #define MOBILEGL_PROGRAMSTATE_H #define MOBILEGL_GLSTATE_H +#define MOBILEGL_PROGRAM_DEBUGTOOL_H +#define MOBILEGL_GLSLTOOL_H #include "../../../Includes.h" struct ShaderObject { GLenum type; std::string source; + std::vector compiledSpirv; UncertainBool compiled; GLint compileStatus; std::string infoLog; bool markedForDeletion; }; +struct UniformValue { + GLenum type; + std::vector floatData; + std::vector intData; + std::vector uintData; + std::vector boolData; + GLsizei count; + + UniformValue() : type(0), count(0) {} + + template + void setData(GLenum uniformType, GLsizei numElements, const T* values); +}; + struct ProgramObject { std::vector attachedShaders; UncertainBool linked; @@ -25,6 +42,7 @@ struct ProgramObject { std::unordered_map attribBindings; std::unordered_map attribLocations; std::unordered_map uniformLocations; + std::unordered_map uniformValues; bool markedForDeletion; }; @@ -39,6 +57,9 @@ private: GLuint currentProgram_ = 0; public: + ProgramState(); + ~ProgramState(); + // Return: the validity of the operation, according to OpenGL 3 standard GLenum CreateShader(GLenum type, GLuint* shader); GLenum CreateProgram(GLuint* program); @@ -54,7 +75,42 @@ public: GLint QueryProgramUniformLocation(GLuint program, const GLchar* name); GLenum QueryProgramStateIntVector(GLuint program, GLenum pname, GLint* params); GLenum QueryShaderStateIntVector(GLuint shader, GLenum pname, GLint* params); + + template + GLenum SetUniform(GLuint program, GLint location, GLsizei count, const T* value, GLenum type); + + template + GLenum SetUniformMatrix(GLuint program, GLint location, GLsizei count, GLboolean transpose, const T* value, GLenum matrixType); +#define DECLARE_UNIFORM_FUNCTIONS(type, suffix, vecType) \ + void UpdateUniform##suffix##1(GLint location, type v0); \ + void UpdateUniform##suffix##2(GLint location, type v0, type v1); \ + void UpdateUniform##suffix##3(GLint location, type v0, type v1, type v2); \ + void UpdateUniform##suffix##4(GLint location, type v0, type v1, type v2, type v3); \ + void UpdateUniform##suffix##Vector1(GLint location, GLsizei count, const type* value); \ + void UpdateUniform##suffix##Vector2(GLint location, GLsizei count, const type* value); \ + void UpdateUniform##suffix##Vector3(GLint location, GLsizei count, const type* value); \ + void UpdateUniform##suffix##Vector4(GLint location, GLsizei count, const type* value); + DECLARE_UNIFORM_FUNCTIONS(GLfloat, Float, GL_FLOAT) + DECLARE_UNIFORM_FUNCTIONS(GLint, Int, GL_INT) + DECLARE_UNIFORM_FUNCTIONS(GLuint, UInt, GL_UNSIGNED_INT) + DECLARE_UNIFORM_FUNCTIONS(GLboolean, Bool, GL_BOOL) +#undef DECLARE_UNIFORM_FUNCTIONS +#define DECLARE_MATRIX_FUNCTIONS(suffix, matrixType) \ + void UpdateUniformMatrix##suffix##Vector(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + DECLARE_MATRIX_FUNCTIONS(2x2, GL_FLOAT_MAT2) + DECLARE_MATRIX_FUNCTIONS(3x3, GL_FLOAT_MAT3) + DECLARE_MATRIX_FUNCTIONS(4x4, GL_FLOAT_MAT4) + DECLARE_MATRIX_FUNCTIONS(2x3, GL_FLOAT_MAT2x3) + DECLARE_MATRIX_FUNCTIONS(2x4, GL_FLOAT_MAT2x4) + DECLARE_MATRIX_FUNCTIONS(3x2, GL_FLOAT_MAT3x2) + DECLARE_MATRIX_FUNCTIONS(3x4, GL_FLOAT_MAT3x4) + DECLARE_MATRIX_FUNCTIONS(4x2, GL_FLOAT_MAT4x2) + DECLARE_MATRIX_FUNCTIONS(4x3, GL_FLOAT_MAT4x3) +#undef DECLARE_MATRIX_FUNCTIONS + + ProgramObject GetProgramObject(GLuint program) const; + ShaderObject GetShaderObject(GLuint program) const; GLuint GetCurrentProgram() const; bool SetProgramStatus(GLuint program, GLboolean status); bool SetShaderStatus(GLuint shader, GLboolean status); @@ -63,6 +119,7 @@ private: bool ValidateShader_(GLuint shader); bool ValidateProgram_(GLuint program); void CleanupShaders_(); + GLint GetUniformLocation_(GLuint program, GLint location, const GLchar* name); }; #endif // MOBILEGL_PROGRAMSTATE_H diff --git a/MG/MG_GL/State/Program/ShaderObject.cpp b/MG/MG_GL/State/Program/ShaderObject.cpp new file mode 100644 index 00000000..0928a551 --- /dev/null +++ b/MG/MG_GL/State/Program/ShaderObject.cpp @@ -0,0 +1,138 @@ +// +// Created by BZLZHH on 2025/5/3. +// + +#include "ShaderObject.h" + +// Re-Include Includes.h, cuz of the absence of Program/DebugTool.h and Program/GLSLTool.cpp. +#undef MOBILEGL_GLSLTOOL_H +#undef MOBILEGL_PROGRAM_DEBUGTOOL_H +#include "../../../Includes.h" + +GLenum ProgramState::CreateShader(GLenum type, GLuint* shader) { + MG_Util::Debug::LogD("MG_State: Program: CreateShader called, type=0x%X, shader ptr=%p", type, shader); + if (!shader) { + MG_Util::Debug::LogE("MG_State: Program: CreateShader error: shader pointer is null"); + return GL_INVALID_VALUE; + } + if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) { + MG_Util::Debug::LogE("MG_State: Program: CreateShader error: invalid shader type 0x%X", type); + return GL_INVALID_ENUM; + } + + GLuint id = freeShaderIds_.empty() ? ++lastShaderId_ : *freeShaderIds_.begin(); + if (!freeShaderIds_.empty()) + freeShaderIds_.erase(freeShaderIds_.begin()); + + ShaderObject obj; + obj.type = type; + obj.compiled = {UncertainBool::Unknown, UncertainBool::False}; + obj.compiledSpirv = {}; + obj.markedForDeletion = false; + obj.compileStatus = GL_FALSE; + shaders_[id] = obj; + *shader = id; + MG_Util::Debug::LogD("MG_State: Program: CreateShader success, new shader id=%u", id); + return GL_NO_ERROR; +} + +GLenum ProgramState::DeleteShader(GLuint shader) { + MG_Util::Debug::LogD("MG_State: Program: DeleteShader called, shader id=%u", shader); + if (!ValidateShader_(shader)) { + MG_Util::Debug::LogE("MG_State: Program: DeleteShader error: invalid shader id %u", shader); + return GL_INVALID_VALUE; + } + if (shaders_[shader].markedForDeletion) { + MG_Util::Debug::LogW("MG_State: Program: DeleteShader warning: shader %u already marked for deletion", shader); + return GL_NO_ERROR; + } + + bool inUse = false; + for (auto& [progId, program] : programs_) { + if (std::find(program.attachedShaders.begin(), + program.attachedShaders.end(), shader) != program.attachedShaders.end()) { + inUse = true; + break; + } + } + if (inUse) { + shaders_[shader].markedForDeletion = true; + MG_Util::Debug::LogD("MG_State: Program: DeleteShader info: shader %u marked for deferred deletion (in use)", shader); + } else { + shaders_.erase(shader); + freeShaderIds_.insert(shader); + MG_Util::Debug::LogD("MG_State: Program: DeleteShader success: shader %u deleted immediately", shader); + } + return GL_NO_ERROR; +} + +GLenum ProgramState::UploadShaderSource(GLuint shader, GLsizei count, + const GLchar** string, const GLint* length) { + MG_Util::Debug::LogD("MG_State: Program: UploadShaderSource called, shader id=%u, count=%d", shader, count); + if (!ValidateShader_(shader)) { + MG_Util::Debug::LogE("MG_State: Program: UploadShaderSource error: invalid shader id %u", shader); + return GL_INVALID_VALUE; + } + if (count < 0) { + MG_Util::Debug::LogE("MG_State: Program: UploadShaderSource error: negative count %d", count); + return GL_INVALID_VALUE; + } + + std::string source; + for (GLsizei i = 0; i < count; ++i) { + const GLchar* str = string[i]; + GLint len = (length && length[i] >= 0) ? length[i] : strlen(str); + source.append(str, len); + } + shaders_[shader].source = std::move(source); + MG_Util::Debug::LogD("MG_State: Program: UploadShaderSource success: source uploaded (length=%zu)", shaders_[shader].source.size()); + return GL_NO_ERROR; +} + +GLenum ProgramState::BuildShaderStage(GLuint shader) { + MG_Util::Debug::LogD("MG_State: Program: BuildShaderStage called, shader id=%u", shader); + if (!ValidateShader_(shader)) { + MG_Util::Debug::LogE("MG_State: Program: BuildShaderStage error: invalid shader id %u", shader); + return GL_INVALID_VALUE; + } + auto& obj = shaders_[shader]; + + std::string compilationLog; + auto spirv = MG_Util::Program::CompileGLSLToSPIRV(obj.type, obj.source, compilationLog); + if (spirv.empty()) { + obj.infoLog = "Shader compilation failed: " + compilationLog; + obj.compiled = UncertainBool::False; + obj.compileStatus = GL_FALSE; + MG_Util::Debug::LogE("MG_State: Program: BuildShaderStage error: %s", compilationLog.c_str()); + return GL_INVALID_OPERATION; + } + obj.compiledSpirv = spirv; + obj.compiled = {UncertainBool::Unknown, UncertainBool::True}; + obj.compileStatus = GL_TRUE; + obj.infoLog.clear(); + MG_Util::Debug::LogD("MG_State: Program: BuildShaderStage success: shader %u compiled to SPIR-V (size=%zu bytes)", shader, spirv.size() * sizeof(unsigned)); + return GL_NO_ERROR; +} + +bool ProgramState::SetShaderStatus(GLuint shader, GLboolean status) { + MG_Util::Debug::LogD("MG_State: Program: SetShaderStatus called, shader id=%u, status=%d", shader, status); + if (!ValidateShader_(shader)) { + MG_Util::Debug::LogE("MG_State: Program: SetShaderStatus error: invalid shader id %u", shader); + return false; + } + auto& obj = shaders_[shader]; + if (obj.compiled.getValue() != UncertainBool::Unknown) { + MG_Util::Debug::LogW("MG_State: Program: SetShaderStatus warning: shader %u status already set", shader); + return false; + } + obj.compiled = (status == GL_TRUE) ? UncertainBool::True : UncertainBool::False; + obj.compileStatus = status; + MG_Util::Debug::LogD("MG_State: Program: SetShaderStatus success: shader %u status=%d", shader, status); + return true; +} + +bool ProgramState::ValidateShader_(GLuint shader) { + bool valid = shaders_.count(shader) && !shaders_[shader].markedForDeletion; + MG_Util::Debug::LogD("MG_State: Program: ValidateShader_ called, shader id=%u, result=%d", shader, valid); + return valid; +} diff --git a/MG/MG_GL/State/Program/ShaderObject.h b/MG/MG_GL/State/Program/ShaderObject.h new file mode 100644 index 00000000..7c2f1555 --- /dev/null +++ b/MG/MG_GL/State/Program/ShaderObject.h @@ -0,0 +1,12 @@ +// +// Created by BZLZHH on 2025/5/3. +// + +#ifndef MOBILEGL_SHADEROBJECT_H +#define MOBILEGL_SHADEROBJECT_H + +#define MOBILEGL_GLSTATE_H + +#include "../../../Includes.h" + +#endif //MOBILEGL_SHADEROBJECT_H diff --git a/MG/MG_GL/State/Texture/TextureState.cpp b/MG/MG_GL/State/Texture/TextureState.cpp index 0c2c48d2..3a9c70ab 100644 --- a/MG/MG_GL/State/Texture/TextureState.cpp +++ b/MG/MG_GL/State/Texture/TextureState.cpp @@ -139,7 +139,7 @@ GLenum TextureState::Bind(GLenum target, GLuint texture) { } auto texObjIt = textures.find(texture); - if(texObjIt != textures.end()){ + if (texObjIt != textures.end()){ if (texObjIt->second.target != target && texObjIt->second.target != GL_NONE) { MG_Util::Debug::LogE("MG_State: Texture: Bind texture %u bound to different target 0x%x", texture, texObjIt->second.target); return GL_INVALID_OPERATION; @@ -443,19 +443,19 @@ GLenum TextureState::SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloa case GL_TEXTURE_BORDER_COLOR: break; case GL_TEXTURE_MIN_LOD: - if(param < -1000.0f){ + if (param < -1000.0f){ MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyFloat param for GL_TEXTURE_MIN_LOD too low: %f", param); return GL_INVALID_VALUE; } break; case GL_TEXTURE_MAX_LOD: - if(param > 1000.0f){ + if (param > 1000.0f){ MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyFloat param for GL_TEXTURE_MAX_LOD too high: %f", param); return GL_INVALID_VALUE; } break; case GL_TEXTURE_LOD_BIAS: - if(param < -1000.0f || param > 1000.0f) { + if (param < -1000.0f || param > 1000.0f) { MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyFloat param for GL_TEXTURE_LOD_BIAS out of range: %f", param); return GL_INVALID_VALUE; } @@ -514,7 +514,7 @@ GLenum TextureState::SetTexturePropertyInt(GLenum target, GLenum pname, GLint pa case GL_TEXTURE_SWIZZLE_G: case GL_TEXTURE_SWIZZLE_B: case GL_TEXTURE_SWIZZLE_A: - if(param != GL_ZERO && param != GL_ONE && param != GL_RED && param != GL_GREEN && param != GL_BLUE && param != GL_ALPHA){ + if (param != GL_ZERO && param != GL_ONE && param != GL_RED && param != GL_GREEN && param != GL_BLUE && param != GL_ALPHA){ MG_Util::Debug::LogE("MG_State: Texture: SetTexturePropertyInt invalid swizzle param=%d", param); return GL_INVALID_ENUM; } diff --git a/MG/MG_UTIL/Program/DebugTool.cpp b/MG/MG_UTIL/Program/DebugTool.cpp new file mode 100644 index 00000000..608b9495 --- /dev/null +++ b/MG/MG_UTIL/Program/DebugTool.cpp @@ -0,0 +1,150 @@ +// +// Created by BZLZHH on 2025/5/3. +// + +#include "DebugTool.h" + +namespace MG_Util::Program { + std::string GLTypeToString(GLenum type) { + switch(type) { + case GL_FLOAT: return "float"; + case GL_FLOAT_VEC2: return "vec2"; + case GL_FLOAT_VEC3: return "vec3"; + case GL_FLOAT_VEC4: return "vec4"; + case GL_INT: return "int"; + case GL_INT_VEC2: return "ivec2"; + case GL_INT_VEC3: return "ivec3"; + case GL_INT_VEC4: return "ivec4"; + case GL_UNSIGNED_INT: return "uint"; + case GL_UNSIGNED_INT_VEC2: return "uvec2"; + case GL_UNSIGNED_INT_VEC3: return "uvec3"; + case GL_UNSIGNED_INT_VEC4: return "uvec4"; + case GL_BOOL: return "bool"; + case GL_BOOL_VEC2: return "bvec2"; + case GL_BOOL_VEC3: return "bvec3"; + case GL_BOOL_VEC4: return "bvec4"; + case GL_FLOAT_MAT2: return "mat2"; + case GL_FLOAT_MAT3: return "mat3"; + case GL_FLOAT_MAT4: return "mat4"; + case GL_FLOAT_MAT2x3: return "mat2x3"; + case GL_FLOAT_MAT2x4: return "mat2x4"; + case GL_FLOAT_MAT3x2: return "mat3x2"; + case GL_FLOAT_MAT3x4: return "mat3x4"; + case GL_FLOAT_MAT4x2: return "mat4x2"; + case GL_FLOAT_MAT4x3: return "mat4x3"; + case GL_SAMPLER_1D: return "sampler1D"; + case GL_SAMPLER_2D: return "sampler2D"; + case GL_SAMPLER_3D: return "sampler3D"; + case GL_SAMPLER_CUBE: return "samplerCube"; + case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow"; + case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow"; + case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow"; + case GL_SAMPLER_1D_ARRAY: return "sampler1DArray"; + case GL_SAMPLER_2D_ARRAY: return "sampler2DArray"; + case GL_SAMPLER_1D_ARRAY_SHADOW: return "sampler1DArrayShadow"; + case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow"; + case GL_SAMPLER_BUFFER: return "samplerBuffer"; + case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS"; + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray"; + default: return "UnknownType(0x" + std::to_string(type) + ")"; + } + } + + std::string FormatUniformValue(const UniformValue& value) { + std::ostringstream ss; + ss << "["; + + const size_t elemCount = std::min(value.count, 16); // 限制最大显示元素 + + switch(value.type) { + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + for(size_t i=0; i 0) ss << ", "; + ss << (i < value.floatData.size() ? value.floatData[i] : 0.0f); + } + break; + + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + for(size_t i=0; i 0) ss << ", "; + ss << (i < value.intData.size() ? value.intData[i] : 0); + } + break; + + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_VEC2: + case GL_UNSIGNED_INT_VEC3: + case GL_UNSIGNED_INT_VEC4: + for(size_t i=0; i 0) ss << ", "; + ss << (i < value.uintData.size() ? value.uintData[i] : 0); + } + break; + + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + for(size_t i=0; i 0) ss << ", "; + ss << (i < value.boolData.size() ? (value.boolData[i] ? "true" : "false") : "false"); + } + break; + + default: + ss << "N/A"; + } + + if (value.count > elemCount) ss << ", ..."; + ss << "]"; + return ss.str(); + } + + void DumpUniforms(const ProgramState& state, GLuint program) { + if (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG) + return; + + auto prog = (ProgramObject)state.GetProgramObject(program); + if (!prog.linked.toBool()) { + MG_Util::Debug::LogE("Program %u not linked", program); + return; + } + MG_Util::Debug::LogD("=== Dumping uniforms for program %u ===", program); + for(const auto& [name, loc] : prog.uniformLocations) { + const auto& value = prog.uniformValues.at(name); + MG_Util::Debug::LogD("Uniform: %-24s Location: %-4d Type: %-16s Count: %-3d Value: %s", + name.c_str(), + loc, + GLTypeToString(value.type).c_str(), + value.count, + FormatUniformValue(value).c_str()); + } + } + + void DumpCurrentUniforms(const ProgramState& state) { + if (MG_Global::Common::LogLevel > MG_Constants::Common::LOG_LEVEL_DEBUG) + return; + + GLuint current = state.GetCurrentProgram(); + if (current == 0) { + MG_Util::Debug::LogE("No active program"); + return; + } + DumpUniforms(state, current); + } +} \ No newline at end of file diff --git a/MG/MG_UTIL/Program/DebugTool.h b/MG/MG_UTIL/Program/DebugTool.h new file mode 100644 index 00000000..e052257f --- /dev/null +++ b/MG/MG_UTIL/Program/DebugTool.h @@ -0,0 +1,16 @@ +// +// Created by BZLZHH on 2025/5/3. +// + +#ifndef MOBILEGL_PROGRAM_DEBUGTOOL_H +#define MOBILEGL_PROGRAM_DEBUGTOOL_H +#include "../../Includes.h" + +namespace MG_Util::Program { + std::string GLTypeToString(GLenum type); + std::string FormatUniformValue(const UniformValue& value); + void DumpUniforms(const ProgramState& state, GLuint program); + void DumpCurrentUniforms(const ProgramState& state); +} + +#endif //MOBILEGL_PROGRAM_DEBUGTOOL_H diff --git a/MG/MG_UTIL/Program/GLSLTool.cpp b/MG/MG_UTIL/Program/GLSLTool.cpp new file mode 100644 index 00000000..91a77e9d --- /dev/null +++ b/MG/MG_UTIL/Program/GLSLTool.cpp @@ -0,0 +1,405 @@ +// +// Created by BZLZHH on 2025/5/3. +// + +#include "GLSLTool.h" + +namespace MG_Util::Program { + std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader) { + std::string infoLog; + using namespace glslang; + + int glslVersion = QueryGLSLVersion(source); + EShLanguage language = GetEShLanguageByShaderType(shaderType); + if (language == EShLanguage::EShLangCount) { + infoLog += "Error: [Preprocess] Unsupported shader type: " + + std::to_string(shaderType); + TShader tmpShader(EShLanguage::EShLangVertex); + return infoLog; + } + + shader = new TShader(language); + const char *src = source.c_str(); + shader->setStrings(&src, 1); + shader->setEnvInput(EShSourceGlsl, language, EShClientVulkan, glslVersion); + shader->setEnvClient(EShClientOpenGL, EShTargetOpenGL_450); + shader->setEnvTarget(EShTargetSpv, EShTargetSpv_1_6); + shader->setAutoMapLocations(true); + shader->setAutoMapBindings(true); + + // Is InitResources() really correct? + TBuiltInResource resources = InitResources(); + + if (!shader->parse(&resources, glslVersion, true, EShMsgDefault)) { + infoLog += "Error: [glslang] Cannot compile the " + GetShaderTypeName(shaderType) + ":\n" + + std::to_string(shader->getInfoLog()); + return infoLog; + } + + return {}; + } + + std::vector> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog) { + using namespace glslang; + + std::vector usedShaderTypes; + TProgram program; + for (GLuint shaderId : prog.attachedShaders) { + auto shaderObject = state.GetShaderObject(shaderId); + EShLanguage shLanguage = GetEShLanguageByShaderType(shaderObject.type); + TShader* shader = nullptr; + std::string infoLogOfShader = CompileGLSLToTShader(shaderObject.type, shaderObject.source, shader); + if (!infoLogOfShader.empty()) { + infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderObject.type) + + " :\n" + infoLogOfShader; + return {}; + } + program.addShader(shader); + usedShaderTypes.push_back(shLanguage); + } + if (!program.link(EShMsgDefault)) { + infoLog = "Error: [glslang] Cannot link the program:\n" + std::to_string(program.getInfoLog()); + return {}; + } + + SpvOptions spvOptions; + spvOptions.disableOptimizer = false; + + std::vector> allSpirv; + for(auto type : usedShaderTypes) { + std::vector spirv; + GlslangToSpv(*program.getIntermediate(type), spirv, &spvOptions); + allSpirv.push_back(spirv); + } + + return allSpirv; + } + + std::vector CompileGLSLToSPIRV(GLenum shaderType, const std::string &source, std::string &infoLog) { + using namespace glslang; + + TShader* shader = nullptr; + std::string infoLogOfShader = CompileGLSLToTShader(shaderType, source, shader); + if (!infoLogOfShader.empty()) { + infoLog = "Error: [glslang] Cannot compile " + GetShaderTypeName(shaderType) + ":\n" + infoLogOfShader; + return {}; + } + TProgram program; + program.addShader(shader); + if (!program.link(EShMsgDefault)) { + infoLog = "Error: [glslang] Cannot link the program of the single shader:\n" + std::to_string(program.getInfoLog()); + return {}; + } + std::vector spirv; + + SpvOptions spvOptions; + spvOptions.disableOptimizer = false; + EShLanguage language = GetEShLanguageByShaderType(shaderType); + GlslangToSpv(*program.getIntermediate(language), spirv, &spvOptions); + + return spirv; + } + + void ReflectSPIRVUniforms(const std::vector>& allSpirv, ProgramObject& prog, std::string& infoLog) { + spvc_context context = nullptr; + + if (spvc_context_create(&context) != SPVC_SUCCESS) { + infoLog = "Failed to create SPIRV-Cross context"; + return; + } + + std::unordered_set used_locations; + GLint auto_location = 0; + for (auto spirv: allSpirv) { + spvc_parsed_ir ir = nullptr; + spvc_compiler compiler = nullptr; + spvc_resources resources = nullptr; + + spvc_result result = spvc_context_parse_spirv(context, spirv.data(), spirv.size(), &ir); + if (result != SPVC_SUCCESS) { + infoLog = "SPIR-V parsing failed"; + spvc_context_destroy(context); + return; + } + + result = spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, + SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler); + if (result != SPVC_SUCCESS) { + infoLog = "Failed to create SPIRV-Cross compiler"; + spvc_context_destroy(context); + return; + } + + result = spvc_compiler_create_shader_resources(compiler, &resources); + if (result != SPVC_SUCCESS) { + infoLog = "Failed to get shader resources"; + spvc_context_destroy(context); + return; + } + + const spvc_reflected_resource *uniform_buffers = nullptr; + const spvc_reflected_resource *uniform_vars = nullptr; + const spvc_reflected_resource *sampled_images = nullptr; + size_t uniform_buffer_count = 0; + size_t uniform_var_count = 0; + size_t sampled_image_count = 0; + + spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, + &uniform_buffers, &uniform_buffer_count); + spvc_resources_get_resource_list_for_type(resources, + SPVC_RESOURCE_TYPE_GL_PLAIN_UNIFORM, + &uniform_vars, &uniform_var_count); + spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, + &sampled_images, &sampled_image_count); + + std::vector all_resources; + for (size_t i = 0; i < uniform_buffer_count; ++i) + all_resources.push_back(&uniform_buffers[i]); + for (size_t i = 0; i < uniform_var_count; ++i) + all_resources.push_back(&uniform_vars[i]); + for (size_t i = 0; i < sampled_image_count; ++i) + all_resources.push_back(&sampled_images[i]); + + for (const auto res_ptr: all_resources) { + const spvc_reflected_resource &res = *res_ptr; + const char *name = res.name; + if (name[0] == '_') continue; + + unsigned spirv_location = spvc_compiler_get_decoration(compiler, res.id, + SpvDecorationLocation); + GLint final_location; + + if (spirv_location > 0) { + if (used_locations.find(spirv_location) != used_locations.end()) { + infoLog += "\nLocation conflict for uniform: " + std::string(name); + continue; + } + final_location = spirv_location; + } else { + while (used_locations.find(auto_location) != used_locations.end()) { + auto_location++; + } + final_location = auto_location; + } + + used_locations.insert(final_location); + + spvc_type_id type_id = res.type_id; + spvc_type type = spvc_compiler_get_type_handle(compiler, type_id); + spvc_basetype base_type = spvc_type_get_basetype(type); + GLenum gl_type = GL_NONE; + + if (base_type == SPVC_BASETYPE_SAMPLED_IMAGE) { + SpvDim dim = spvc_type_get_image_dimension(type); + bool is_array = spvc_type_get_image_arrayed(type); + bool is_shadow = spvc_type_get_image_is_depth(type); + bool is_ms = spvc_type_get_image_multisampled(type); + + switch (dim) { + case SpvDim1D: + gl_type = is_array ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D; + if (is_shadow) + gl_type = is_array ? GL_SAMPLER_1D_ARRAY_SHADOW + : GL_SAMPLER_1D_SHADOW; + break; + case SpvDim2D: + if (is_ms) { + gl_type = is_array ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY + : GL_SAMPLER_2D_MULTISAMPLE; + } else { + gl_type = is_array ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D; + if (is_shadow) + gl_type = is_array ? GL_SAMPLER_2D_ARRAY_SHADOW + : GL_SAMPLER_2D_SHADOW; + } + break; + case SpvDim3D: + gl_type = GL_SAMPLER_3D; + break; + case SpvDimCube: + gl_type = is_array ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE; + if (is_shadow) + gl_type = is_array ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW + : GL_SAMPLER_CUBE_SHADOW; + break; + case SpvDimRect: + gl_type = is_shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT; + break; + case SpvDimBuffer: + gl_type = GL_SAMPLER_BUFFER; + break; + default: + gl_type = GL_SAMPLER_2D; + } + + spvc_basetype sampled_base = spvc_type_get_basetype(type); + if (sampled_base == SPVC_BASETYPE_INT32) { + switch (gl_type) { + case GL_SAMPLER_1D: + gl_type = GL_INT_SAMPLER_1D; + break; + case GL_SAMPLER_2D: + gl_type = GL_INT_SAMPLER_2D; + break; + case GL_SAMPLER_3D: + gl_type = GL_INT_SAMPLER_3D; + break; + case GL_SAMPLER_CUBE: + gl_type = GL_INT_SAMPLER_CUBE; + break; + case GL_SAMPLER_1D_ARRAY: + gl_type = GL_INT_SAMPLER_1D_ARRAY; + break; + case GL_SAMPLER_2D_ARRAY: + gl_type = GL_INT_SAMPLER_2D_ARRAY; + break; + case GL_SAMPLER_CUBE_MAP_ARRAY: + gl_type = GL_INT_SAMPLER_CUBE_MAP_ARRAY; + break; + case GL_SAMPLER_2D_RECT: + gl_type = GL_INT_SAMPLER_2D_RECT; + break; + case GL_SAMPLER_BUFFER: + gl_type = GL_INT_SAMPLER_BUFFER; + break; + case GL_SAMPLER_2D_MULTISAMPLE: + gl_type = GL_INT_SAMPLER_2D_MULTISAMPLE; + break; + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + gl_type = GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY; + break; + } + } else if (sampled_base == SPVC_BASETYPE_UINT32) { + switch (gl_type) { + case GL_SAMPLER_1D: + gl_type = GL_UNSIGNED_INT_SAMPLER_1D; + break; + case GL_SAMPLER_2D: + gl_type = GL_UNSIGNED_INT_SAMPLER_2D; + break; + case GL_SAMPLER_3D: + gl_type = GL_UNSIGNED_INT_SAMPLER_3D; + break; + case GL_SAMPLER_CUBE: + gl_type = GL_UNSIGNED_INT_SAMPLER_CUBE; + break; + case GL_SAMPLER_1D_ARRAY: + gl_type = GL_UNSIGNED_INT_SAMPLER_1D_ARRAY; + break; + case GL_SAMPLER_2D_ARRAY: + gl_type = GL_UNSIGNED_INT_SAMPLER_2D_ARRAY; + break; + case GL_SAMPLER_CUBE_MAP_ARRAY: + gl_type = GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY; + break; + case GL_SAMPLER_2D_RECT: + gl_type = GL_UNSIGNED_INT_SAMPLER_2D_RECT; + break; + case GL_SAMPLER_BUFFER: + gl_type = GL_UNSIGNED_INT_SAMPLER_BUFFER; + break; + case GL_SAMPLER_2D_MULTISAMPLE: + gl_type = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE; + break; + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + gl_type = GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY; + break; + } + } + } else { + unsigned vec_size = spvc_type_get_vector_size(type); + unsigned columns = spvc_type_get_columns(type); + + switch (base_type) { + case SPVC_BASETYPE_FP32: + if (columns > 1) { + if (vec_size == 2 && columns == 2) gl_type = GL_FLOAT_MAT2; + else if (vec_size == 3 && columns == 3) gl_type = GL_FLOAT_MAT3; + else if (vec_size == 4 && columns == 4) gl_type = GL_FLOAT_MAT4; + else if (vec_size == 3 && columns == 2) gl_type = GL_FLOAT_MAT2x3; + else if (vec_size == 4 && columns == 2) gl_type = GL_FLOAT_MAT2x4; + else if (vec_size == 2 && columns == 3) gl_type = GL_FLOAT_MAT3x2; + else if (vec_size == 4 && columns == 3) gl_type = GL_FLOAT_MAT3x4; + else if (vec_size == 2 && columns == 4) gl_type = GL_FLOAT_MAT4x2; + else if (vec_size == 3 && columns == 4) gl_type = GL_FLOAT_MAT4x3; + } else { + switch (vec_size) { + case 1: + gl_type = GL_FLOAT; + break; + case 2: + gl_type = GL_FLOAT_VEC2; + break; + case 3: + gl_type = GL_FLOAT_VEC3; + break; + case 4: + gl_type = GL_FLOAT_VEC4; + break; + } + } + break; + case SPVC_BASETYPE_INT32: + switch (vec_size) { + case 1: + gl_type = GL_INT; + break; + case 2: + gl_type = GL_INT_VEC2; + break; + case 3: + gl_type = GL_INT_VEC3; + break; + case 4: + gl_type = GL_INT_VEC4; + break; + } + break; + case SPVC_BASETYPE_UINT32: + switch (vec_size) { + case 1: + gl_type = GL_UNSIGNED_INT; + break; + case 2: + gl_type = GL_UNSIGNED_INT_VEC2; + break; + case 3: + gl_type = GL_UNSIGNED_INT_VEC3; + break; + case 4: + gl_type = GL_UNSIGNED_INT_VEC4; + break; + } + break; + case SPVC_BASETYPE_BOOLEAN: + switch (vec_size) { + case 1: + gl_type = GL_BOOL; + break; + case 2: + gl_type = GL_BOOL_VEC2; + break; + case 3: + gl_type = GL_BOOL_VEC3; + break; + case 4: + gl_type = GL_BOOL_VEC4; + break; + } + break; + default: + continue; + } + } + + prog.uniformLocations[name] = final_location; + UniformValue uniformValue; + uniformValue.type = gl_type; + uniformValue.count = spvc_type_get_array_dimension(type, 0) > 0 ? + spvc_type_get_array_dimension(type, 0) : 1; + prog.uniformValues[name] = uniformValue; + } + } + spvc_context_destroy(context); + } +} \ No newline at end of file diff --git a/MG/MG_UTIL/Program/GLSLTool.h b/MG/MG_UTIL/Program/GLSLTool.h new file mode 100644 index 00000000..3d6812e7 --- /dev/null +++ b/MG/MG_UTIL/Program/GLSLTool.h @@ -0,0 +1,182 @@ +// +// Created by BZLZHH on 2025/5/3. +// + +#ifndef MOBILEGL_GLSLTOOL_H +#define MOBILEGL_GLSLTOOL_H + +#include "../../Includes.h" + +namespace MG_Util::Program { + inline static TBuiltInResource InitResources() + { + 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; + } + + inline int QueryGLSLVersion(const std::string& code) { + static std::regex version_pattern(R"(#version\s+(\d{3}))"); + std::smatch match; + if (std::regex_search(code, match, version_pattern)) { + return std::stoi(match[1].str()); + } + + return -1; + } + + inline GLsizei GetMatrixElementCount(GLenum matrixType) { + switch(matrixType) { + case GL_FLOAT_MAT2: return 4; + case GL_FLOAT_MAT3: return 9; + case GL_FLOAT_MAT4: return 16; + case GL_FLOAT_MAT2x3: return 6; + case GL_FLOAT_MAT2x4: return 8; + case GL_FLOAT_MAT3x2: return 6; + case GL_FLOAT_MAT3x4: return 12; + case GL_FLOAT_MAT4x2: return 8; + case GL_FLOAT_MAT4x3: return 12; + default: return 0; + } + } + + inline std::string GetShaderTypeName(GLenum shaderType) { + switch(shaderType) { + case GL_VERTEX_SHADER: return "Vertex Shader"; + case GL_FRAGMENT_SHADER: return "Fragment Shader"; + case GL_GEOMETRY_SHADER: return "Geometry Shader"; + case GL_TESS_CONTROL_SHADER: return "Tessellation Control Shader"; + case GL_TESS_EVALUATION_SHADER: return "Tessellation Evaluation Shader"; + case GL_COMPUTE_SHADER: return "Compute Shader"; + default: return "Unknown Shader Type (" + std::to_string(shaderType) + ")"; + } + } + + inline 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; + } + } + + std::vector CompileGLSLToSPIRV(GLenum shaderType, const std::string& source, std::string& infoLog); + std::string CompileGLSLToTShader(GLenum shaderType, const std::string& source, glslang::TShader *&shader); + std::vector> CompileMultipleShadersToSPIRV(const ProgramState& state, ProgramObject& prog, std::string& infoLog); + void ReflectSPIRVUniforms(const std::vector>& allSpirv, ProgramObject& prog, std::string& infoLog); +} + +#endif //MOBILEGL_GLSLTOOL_H