From 7a7f6a0533b449c349346e8f6d3bfdcc52fc3e0c Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 22 Aug 2025 17:29:25 +0800 Subject: [PATCH 01/12] [Feat] (MG_Util/Metrics): GetGLTypeSize --- MobileGL/MG_Test/Buffer/CMakeLists.txt | 1 + MobileGL/MG_Test/Program/CMakeLists.txt | 1 + MobileGL/MG_Test/VertexArray/CMakeLists.txt | 1 + MobileGL/MG_Util/Metrics/BufferMetrics.cpp | 117 ++++++++++++++++++++ MobileGL/MG_Util/Metrics/BufferMetrics.h | 16 +++ 5 files changed, 136 insertions(+) create mode 100644 MobileGL/MG_Util/Metrics/BufferMetrics.cpp create mode 100644 MobileGL/MG_Util/Metrics/BufferMetrics.h diff --git a/MobileGL/MG_Test/Buffer/CMakeLists.txt b/MobileGL/MG_Test/Buffer/CMakeLists.txt index 9cf1dfda..16c18571 100644 --- a/MobileGL/MG_Test/Buffer/CMakeLists.txt +++ b/MobileGL/MG_Test/Buffer/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/DataTypeConverter.cpp ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/DataTypeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Metrics/BufferMetrics.cpp ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp ${MGL_ROOT}/MobileGL/MG_Backend/Init.cpp diff --git a/MobileGL/MG_Test/Program/CMakeLists.txt b/MobileGL/MG_Test/Program/CMakeLists.txt index 3d828123..9b2aa5d2 100644 --- a/MobileGL/MG_Test/Program/CMakeLists.txt +++ b/MobileGL/MG_Test/Program/CMakeLists.txt @@ -63,6 +63,7 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/DataTypeConverter.cpp ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/DataTypeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Metrics/BufferMetrics.cpp ${MGL_ROOT}/MobileGL/MG_Backend/Init.cpp ${MGL_ROOT}/MobileGL/MG_Util/Debug/Log.cpp ) diff --git a/MobileGL/MG_Test/VertexArray/CMakeLists.txt b/MobileGL/MG_Test/VertexArray/CMakeLists.txt index 2dcac661..dcbdd056 100644 --- a/MobileGL/MG_Test/VertexArray/CMakeLists.txt +++ b/MobileGL/MG_Test/VertexArray/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable( ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/DataTypeConverter.cpp ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/DataTypeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Metrics/BufferMetrics.cpp ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp ${MGL_ROOT}/MobileGL/MG_Backend/Init.cpp diff --git a/MobileGL/MG_Util/Metrics/BufferMetrics.cpp b/MobileGL/MG_Util/Metrics/BufferMetrics.cpp new file mode 100644 index 00000000..5b275112 --- /dev/null +++ b/MobileGL/MG_Util/Metrics/BufferMetrics.cpp @@ -0,0 +1,117 @@ +// +// Created by Swung0x48 on 2025/8/22. +// + +#include "BufferMetrics.h" + +namespace MobileGL { +namespace MG_Util { + SizeT GetGLTypeSize(GLenum type) { + switch (type) { + // Scalars + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_BYTE_3_3_2: + return 1; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_HALF_FLOAT: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + return 2; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + case GL_FIXED: + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + return 4; + case GL_DOUBLE: + #ifdef GL_ARB_gpu_shader_int64 + case GL_UNSIGNED_INT64_ARB: + case GL_INT64_ARB: + #endif + return 8; + + // ---- Vector Types ---- + // 2-component vec + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_UNSIGNED_INT_VEC2: + case GL_BOOL_VEC2: + return 2 * sizeof(GLfloat); // GL_BOOL_VEC2 is also 2 * 4 bytes + case GL_DOUBLE_VEC2: + return 2 * sizeof(GLdouble); + + // 3-component vec + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_UNSIGNED_INT_VEC3: + case GL_BOOL_VEC3: + return 3 * sizeof(GLfloat); + case GL_DOUBLE_VEC3: + return 3 * sizeof(GLdouble); + + // 4-component vec + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_UNSIGNED_INT_VEC4: + case GL_BOOL_VEC4: + return 4 * sizeof(GLfloat); + case GL_DOUBLE_VEC4: + return 4 * sizeof(GLdouble); + + // ---- Matrix Types ---- + // Double non-square + case GL_FLOAT_MAT2: + return 2 * 2 * sizeof(GLfloat); + case GL_FLOAT_MAT3: + return 3 * 3 * sizeof(GLfloat); + case GL_FLOAT_MAT4: + return 4 * 4 * sizeof(GLfloat); + + // Float non-square + case GL_FLOAT_MAT2x3: + return 2 * 3 * sizeof(GLfloat); + case GL_FLOAT_MAT2x4: + return 2 * 4 * sizeof(GLfloat); + case GL_FLOAT_MAT3x2: + return 3 * 2 * sizeof(GLfloat); + case GL_FLOAT_MAT3x4: + return 3 * 4 * sizeof(GLfloat); + case GL_FLOAT_MAT4x2: + return 4 * 2 * sizeof(GLfloat); + case GL_FLOAT_MAT4x3: + return 4 * 3 * sizeof(GLfloat); + + // Double mat + case GL_DOUBLE_MAT2: + return 2 * 2 * sizeof(GLdouble); + case GL_DOUBLE_MAT3: + return 3 * 3 * sizeof(GLdouble); + case GL_DOUBLE_MAT4: + return 4 * 4 * sizeof(GLdouble); + + // Double non-square + case GL_DOUBLE_MAT2x3: + return 2 * 3 * sizeof(GLdouble); + case GL_DOUBLE_MAT2x4: + return 2 * 4 * sizeof(GLdouble); + case GL_DOUBLE_MAT3x2: + return 3 * 2 * sizeof(GLdouble); + case GL_DOUBLE_MAT3x4: + return 3 * 4 * sizeof(GLdouble); + case GL_DOUBLE_MAT4x2: + return 4 * 2 * sizeof(GLdouble); + case GL_DOUBLE_MAT4x3: + return 4 * 3 * sizeof(GLdouble); + + default: + return -1; + } + } +} +} diff --git a/MobileGL/MG_Util/Metrics/BufferMetrics.h b/MobileGL/MG_Util/Metrics/BufferMetrics.h new file mode 100644 index 00000000..8b218978 --- /dev/null +++ b/MobileGL/MG_Util/Metrics/BufferMetrics.h @@ -0,0 +1,16 @@ +// +// Created by Swung0x48 on 2025/8/22. +// + +#ifndef BUFFERMETRICS_H +#define BUFFERMETRICS_H + +#include + +namespace MobileGL { +namespace MG_Util { + SizeT GetGLTypeSize(GLenum type); +} +} + +#endif //BUFFERMETRICS_H From c33056fd8e963802a12c6fa4940ca1e48f675ed7 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 22 Aug 2025 17:29:31 +0800 Subject: [PATCH 02/12] [Feat] (MG_State/Program): glUniformMatrix* with transpose, --- .../MG_Impl/GLImpl/Program/GL_Program.cpp | 133 ++++++++++-- .../GLState/ProgramState/ProgramObject.cpp | 11 +- .../GLState/ProgramState/ProgramObject.h | 7 +- MobileGL/MG_Test/Program/ProgramTest.cpp | 203 +++++++++++++++++- 4 files changed, 322 insertions(+), 32 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 5e389b15..b38dffa1 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -396,13 +396,25 @@ namespace MobileGL { return; } - if (location >= programObject->GetUniformCount() || programObject->GetUniformName(location).empty()) { + // Check if location is valid + if (location < 0 || location > programObject->GetMaxUniformLocation()) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, MakeShared("MG_Impl/GLImpl", __func__, "`location` does not correspond to a valid uniform variable location for the specified program object.")); return; } + + // Check if the location corresponds to an active uniform + const auto& uniformName = programObject->GetUniformName(location); + if (uniformName.empty()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`location` does not correspond to a valid uniform variable location for the specified program object.")); + return; + } + auto isOpaque = programObject->IsUniformOpaqueAtLocation(location); if (!isOpaque) { // TODO: probably handle int/float differences @@ -513,6 +525,74 @@ namespace MobileGL { } } + // Helper function to transpose a 2x2 matrix + void TransposeMatrix2x2(const GLfloat* input, GLfloat* output) { + // Input matrix is in column-major order (OpenGL default) + // [0 2] + // [1 3] + // + // Output matrix should be in row-major order if transpose is true + // [0 1] + // [2 3] + output[0] = input[0]; // 0,0 element stays the same + output[1] = input[2]; // 0,1 element becomes 1,0 + output[2] = input[1]; // 1,0 element becomes 0,1 + output[3] = input[3]; // 1,1 element stays the same + } + + // Helper function to transpose a 3x3 matrix + void TransposeMatrix3x3(const GLfloat* input, GLfloat* output) { + // Input matrix is in column-major order (OpenGL default) + // [0 3 6] + // [1 4 7] + // [2 5 8] + // + // Output matrix should be in row-major order if transpose is true + // [0 1 2] + // [3 4 5] + // [6 7 8] + output[0] = input[0]; // 0,0 element stays the same + output[1] = input[3]; // 0,1 element becomes 1,0 + output[2] = input[6]; // 0,2 element becomes 2,0 + output[3] = input[1]; // 1,0 element becomes 0,1 + output[4] = input[4]; // 1,1 element stays the same + output[5] = input[7]; // 1,2 element becomes 2,1 + output[6] = input[2]; // 2,0 element becomes 0,2 + output[7] = input[5]; // 2,1 element becomes 1,2 + output[8] = input[8]; // 2,2 element stays the same + } + + // Helper function to transpose a 4x4 matrix + void TransposeMatrix4x4(const GLfloat* input, GLfloat* output) { + // Input matrix is in column-major order (OpenGL default) + // [0 4 8 12] + // [1 5 9 13] + // [2 6 10 14] + // [3 7 11 15] + // + // Output matrix should be in row-major order if transpose is true + // [0 1 2 3] + // [4 5 6 7] + // [8 9 10 11] + // [12 13 14 15] + output[0] = input[0]; // 0,0 element stays the same + output[1] = input[4]; // 0,1 element becomes 1,0 + output[2] = input[8]; // 0,2 element becomes 2,0 + output[3] = input[12]; // 0,3 element becomes 3,0 + output[4] = input[1]; // 1,0 element becomes 0,1 + output[5] = input[5]; // 1,1 element stays the same + output[6] = input[9]; // 1,2 element becomes 2,1 + output[7] = input[13]; // 1,3 element becomes 3,1 + output[8] = input[2]; // 2,0 element becomes 0,2 + output[9] = input[6]; // 2,1 element becomes 1,2 + output[10] = input[10]; // 2,2 element stays the same + output[11] = input[14]; // 2,3 element becomes 3,2 + output[12] = input[3]; // 3,0 element becomes 0,3 + output[13] = input[7]; // 3,1 element becomes 1,3 + output[14] = input[11]; // 3,2 element becomes 2,3 + output[15] = input[15]; // 3,3 element stays the same + } + void Uniform1fv_State(GLint location, GLsizei count, const GLfloat* value) { Uniformv_State<1>(location, count, value); } @@ -560,7 +640,7 @@ namespace MobileGL { return; } - if (location >= programObject->GetUniformCount() || location < -1) { + if (location > programObject->GetMaxUniformLocation() || location < -1) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, MakeShared("MG_Impl/GLImpl", __func__, @@ -570,12 +650,15 @@ namespace MobileGL { // For matrix uniforms, we handle each matrix individually for (GLint i = 0; i < count; i++) { - // Note: In this implementation, we're not actually transposing the matrix data - // as we're directly copying to UBO. The transpose parameter is typically used - // in OpenGL to indicate whether the matrix should be transposed before being - // loaded into the uniform variable. In our case, we assume the shader compiler - // has handled the appropriate matrix layout. - Uniform_State<4>(*programObject, location + i, value + i * 4); + if (transpose == GL_TRUE) { + // Transpose the matrix before uploading + GLfloat transposedMatrix[4]; + TransposeMatrix2x2(value + i * 4, transposedMatrix); + Uniform_State<4>(*programObject, location + i, transposedMatrix); + } else { + // No transpose needed, directly copy the matrix data + Uniform_State<4>(*programObject, location + i, value + i * 4); + } } } @@ -594,7 +677,7 @@ namespace MobileGL { return; } - if (location >= programObject->GetUniformCount() || location < -1) { + if (location > programObject->GetMaxUniformLocation() || location < -1) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, MakeShared("MG_Impl/GLImpl", __func__, @@ -604,12 +687,15 @@ namespace MobileGL { // For matrix uniforms, we handle each matrix individually for (GLint i = 0; i < count; i++) { - // Note: In this implementation, we're not actually transposing the matrix data - // as we're directly copying to UBO. The transpose parameter is typically used - // in OpenGL to indicate whether the matrix should be transposed before being - // loaded into the uniform variable. In our case, we assume the shader compiler - // has handled the appropriate matrix layout. - Uniform_State<9>(*programObject, location + i, value + i * 9); + if (transpose == GL_TRUE) { + // Transpose the matrix before uploading + GLfloat transposedMatrix[9]; + TransposeMatrix3x3(value + i * 9, transposedMatrix); + Uniform_State<9>(*programObject, location + i, transposedMatrix); + } else { + // No transpose needed, directly copy the matrix data + Uniform_State<9>(*programObject, location + i, value + i * 9); + } } } @@ -628,7 +714,7 @@ namespace MobileGL { return; } - if (location >= programObject->GetUniformCount() || location < -1) { + if (location > programObject->GetMaxUniformLocation() || location < -1) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, MakeShared("MG_Impl/GLImpl", __func__, @@ -638,12 +724,15 @@ namespace MobileGL { // For matrix uniforms, we handle each matrix individually for (GLint i = 0; i < count; i++) { - // Note: In this implementation, we're not actually transposing the matrix data - // as we're directly copying to UBO. The transpose parameter is typically used - // in OpenGL to indicate whether the matrix should be transposed before being - // loaded into the uniform variable. In our case, we assume the shader compiler - // has handled the appropriate matrix layout. - Uniform_State<16>(*programObject, location + i, value + i * 16); + if (transpose == GL_TRUE) { + // Transpose the matrix before uploading + GLfloat transposedMatrix[16]; + TransposeMatrix4x4(value + i * 16, transposedMatrix); + Uniform_State<16>(*programObject, location + i, transposedMatrix); + } else { + // No transpose needed, directly copy the matrix data + Uniform_State<16>(*programObject, location + i, value + i * 16); + } } } diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 9278ba28..951faaad 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -70,8 +70,8 @@ namespace MobileGL { return; } - auto uniformCount = m_program->getNumUniformVariables(); - for (int i = 0; i < uniformCount; i++) { + m_activeUniformCount = m_program->getNumUniformVariables(); + for (int i = 0; i < m_activeUniformCount; i++) { auto& uniform = m_program->getUniform(i); auto location = uniform.layoutLocation(); m_maxUniformLocation = std::max(m_maxUniformLocation, location); @@ -85,7 +85,7 @@ namespace MobileGL { m_uniformOffsets.resize(m_maxUniformLocation + 1); m_uniformArraySizes.resize(m_maxUniformLocation + 1); - for (int i = 0; i < uniformCount; i++) { + for (int i = 0; i < m_activeUniformCount; i++) { auto& uniform = m_program->getUniform(i); auto location = uniform.layoutLocation(); m_uniformNames[location] = uniform.name; @@ -168,16 +168,17 @@ namespace MobileGL { auto srcResult = ShaderCompiler::DecompileShader(session); assert(srcResult); auto src = srcResult.value(); + printf("decompiled src: \n%s\n", src.c_str()); auto& meta = session.GetMetadata(); auto size = meta.uboSize; m_uboScratch.resize(size); - m_uniformOffsets.resize(meta.plainUniformOffsetsInUBO.size()); + m_uniformOffsets.resize(m_maxUniformLocation + 1); for (const auto& [name, offset] : meta.plainUniformOffsetsInUBO) { if (m_uniformLocations.find(name) != m_uniformLocations.end()) m_uniformOffsets[m_uniformLocations[name]] = offset; } - m_uniformSizesInBytes.resize(meta.plainUniformMemberSizesInBytes.size()); + m_uniformSizesInBytes.resize(m_maxUniformLocation + 1); for (const auto& [name, size] : meta.plainUniformMemberSizesInBytes) { if (m_uniformLocations.find(name) != m_uniformLocations.end()) m_uniformSizesInBytes[m_uniformLocations[name]] = size; diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index dec3b366..afdcca0a 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -1,6 +1,7 @@ #pragma once #include #include "ShaderObject.h" +#include "MG_Util/Metrics/BufferMetrics.h" #include "MG_Util/ShaderTranspiler/SpvcSession.h" namespace MobileGL { @@ -20,7 +21,8 @@ namespace MobileGL { Vector>& GetAttachedShaders(); const String& GetInfoLog() const { return m_infoLog; } Int GetUniformMaxLength() const { return m_uniformNameMaxLength; } - Uint GetUniformCount() { return m_uniformNames.size(); } + Uint GetUniformCount() { return m_activeUniformCount; } + Uint GetMaxUniformLocation() const { return m_maxUniformLocation; } Int GetUniformLocation(const String& name) { const auto it = m_uniformLocations.find(name); return (it == m_uniformLocations.end()) ? -1 : (Int)it->second; @@ -40,7 +42,7 @@ namespace MobileGL { return m_uniformOffsets[location]; } Uint GetUniformSizesInBytes(Uint location) const { - return m_uniformSizesInBytes[location]; + return MG_Util::GetGLTypeSize(m_uniformTypes[location]); } Int GetAttributeLocation(const String& name) { @@ -101,6 +103,7 @@ namespace MobileGL { Vector m_uniformSizesInBytes; Vector m_uboScratch; + Uint m_activeUniformCount = 0; Uint m_maxUniformLocation = 0; Int m_uniformNameMaxLength = 0; Int m_attribInNameMaxLength = 0; diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 1a3d6b87..3eb9d853 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -32,6 +32,8 @@ in float fIn1; in float fIn3; layout(location = 0) uniform mat4 ProjMat; +layout(location = 10) uniform mat3 TestMat3; +layout(location = 20) uniform mat2 TestMat2; uniform vec2 InSize; uniform vec2 OutSize; @@ -42,6 +44,10 @@ void main(){ vec4 outPos = ProjMat * vec4(Position.xy, 0.0, 1.0); gl_Position = vec4(outPos.xy, 0.2, 1.0); + // Use TestMat2 and TestMat3 to prevent optimization + vec2 dummy2 = TestMat2[0]; + vec3 dummy3 = TestMat3[0]; + oneTexel = (1.0 * (fIn1 * fIn2 * fIn3 * fIn4 * fIn5 * fIn6)) / InSize; texCoord = Position.xy / OutSize; @@ -140,7 +146,7 @@ TEST_F(ProgramTest, CompileAndLink) { ASSERT_EQ(GetUniformLocation(program, "Saturation"), 6); GLint uniformCount = 0; GetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount); - ASSERT_EQ(uniformCount, 12); + ASSERT_EQ(uniformCount, 14); GLint uniformNameMaxLength = 0; GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength); ASSERT_EQ(uniformNameMaxLength, 12); @@ -210,7 +216,7 @@ TEST_F(ProgramTest, UniformMatrixFunctions) { auto locProjMat = GetUniformLocation(program, "ProjMat"); ASSERT_NE(locProjMat, -1); - // 4x4 matrix (16 elements) + // 4x4 matrix (16 elements) - identity matrix GLfloat matrix4x4[16] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -218,9 +224,200 @@ TEST_F(ProgramTest, UniformMatrixFunctions) { 0.0f, 0.0f, 0.0f, 1.0f }; - // Test UniformMatrix4fv with count = 1 + // Test UniformMatrix4fv with count = 1 and transpose = GL_FALSE UniformMatrix4fv(locProjMat, 1, GL_FALSE, matrix4x4); + // Test UniformMatrix4fv with count = 1 and transpose = GL_TRUE + UniformMatrix4fv(locProjMat, 1, GL_TRUE, matrix4x4); + + // Test with a non-identity matrix + GLfloat nonIdentityMatrix[16] = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f + }; + + // Test with transpose = GL_FALSE + UniformMatrix4fv(locProjMat, 1, GL_FALSE, nonIdentityMatrix); + + // Test with transpose = GL_TRUE + UniformMatrix4fv(locProjMat, 1, GL_TRUE, nonIdentityMatrix); + + // Test UniformMatrix3fv with a 3x3 matrix + // We would need a 3x3 uniform in the shader for this test + + // Test UniformMatrix2fv with a 2x2 matrix + // We would need a 2x2 uniform in the shader for this test + // Test with multiple matrices (count > 1) // For this test, we would need uniforms that are arrays of matrices } + +TEST_F(ProgramTest, UniformMatrixTranspose) { + char infoLog[1024] = ""; + + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &vsSrc, NULL); + printf("Compiling vertex shader: %s\n", vsSrc); + CompileShader(vs); + GLint vsStatus = GL_FALSE; + GetShaderiv(vs, GL_COMPILE_STATUS, &vsStatus); + GetShaderInfoLog(vs, 1024, nullptr, infoLog); + ASSERT_EQ(vsStatus, GL_TRUE) << infoLog; + printf("Compiled vertex shader.\n"); + + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &fsSrc, NULL); + printf("Compiling fragment shader: %s\n", fsSrc); + CompileShader(fs); + GLint fsStatus = GL_FALSE; + GetShaderiv(fs, GL_COMPILE_STATUS, &fsStatus); + GetShaderInfoLog(fs, 1024, nullptr, infoLog); + ASSERT_EQ(fsStatus, GL_TRUE) << infoLog; + printf("Compiled fragment shader.\n"); + + GLuint program = CreateProgram(); + AttachShader(program, vs); + AttachShader(program, fs); + + BindAttribLocation(program, 1, "fIn1"); + BindAttribLocation(program, 3, "fIn3"); + BindAttribLocation(program, 5, "fIn5"); + printf("Linking program...\n"); + LinkProgram(program); + printf("Program linked.\n"); + + UseProgram(program); + + // Test 2x2 matrix transpose + auto locMat2 = GetUniformLocation(program, "TestMat2"); + if (locMat2 != -1) { + // Test matrix (column-major as expected by OpenGL): + // [1 3] + // [2 4] + GLfloat matrix2x2[4] = { + 1.0f, 2.0f, // First column + 3.0f, 4.0f // Second column + }; + + // Expected values when transpose = GL_FALSE (no transpose): + // [1 3] + // [2 4] + GLfloat expected2x2_no_transpose[4] = {1.0f, 2.0f, 3.0f, 4.0f}; + + // Expected values when transpose = GL_TRUE (transposed): + // [1 2] + // [3 4] + // Stored in column-major order: [1, 3, 2, 4] + GLfloat expected2x2_transpose[4] = {1.0f, 3.0f, 2.0f, 4.0f}; + + // Test with transpose = GL_FALSE + UniformMatrix2fv(locMat2, 1, GL_FALSE, matrix2x2); + GLfloat result2x2_no_transpose[4]; + GetUniformfv(program, locMat2, result2x2_no_transpose); + for (int i = 0; i < 4; i++) { + EXPECT_FLOAT_EQ(result2x2_no_transpose[i], expected2x2_no_transpose[i]); + } + + // Test with transpose = GL_TRUE + UniformMatrix2fv(locMat2, 1, GL_TRUE, matrix2x2); + GLfloat result2x2_transpose[4]; + GetUniformfv(program, locMat2, result2x2_transpose); + for (int i = 0; i < 4; i++) { + EXPECT_FLOAT_EQ(result2x2_transpose[i], expected2x2_transpose[i]); + } + } + + // Test 3x3 matrix transpose + auto locMat3 = GetUniformLocation(program, "TestMat3"); + if (locMat3 != -1) { + // Test matrix (column-major as expected by OpenGL): + // [1 4 7] + // [2 5 8] + // [3 6 9] + GLfloat matrix3x3[9] = { + 1.0f, 2.0f, 3.0f, // First column + 4.0f, 5.0f, 6.0f, // Second column + 7.0f, 8.0f, 9.0f // Third column + }; + + // Expected values when transpose = GL_FALSE (no transpose): + // [1 4 7] + // [2 5 8] + // [3 6 9] + GLfloat expected3x3_no_transpose[9] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}; + + // Expected values when transpose = GL_TRUE (transposed): + // [1 2 3] + // [4 5 6] + // [7 8 9] + // Stored in column-major order: [1, 4, 7, 2, 5, 8, 3, 6, 9] + GLfloat expected3x3_transpose[9] = {1.0f, 4.0f, 7.0f, 2.0f, 5.0f, 8.0f, 3.0f, 6.0f, 9.0f}; + + // Test with transpose = GL_FALSE + UniformMatrix3fv(locMat3, 1, GL_FALSE, matrix3x3); + GLfloat result3x3_no_transpose[9]; + GetUniformfv(program, locMat3, result3x3_no_transpose); + for (int i = 0; i < 9; i++) { + EXPECT_FLOAT_EQ(result3x3_no_transpose[i], expected3x3_no_transpose[i]); + } + + // Test with transpose = GL_TRUE + UniformMatrix3fv(locMat3, 1, GL_TRUE, matrix3x3); + GLfloat result3x3_transpose[9]; + GetUniformfv(program, locMat3, result3x3_transpose); + for (int i = 0; i < 9; i++) { + EXPECT_FLOAT_EQ(result3x3_transpose[i], expected3x3_transpose[i]); + } + } + + // Test 4x4 matrix transpose + auto locProjMat = GetUniformLocation(program, "ProjMat"); + ASSERT_NE(locProjMat, -1); + + // Test matrix (column-major as expected by OpenGL): + // [1 5 9 13] + // [2 6 10 14] + // [3 7 11 15] + // [4 8 12 16] + GLfloat matrix4x4[16] = { + 1.0f, 2.0f, 3.0f, 4.0f, // First column + 5.0f, 6.0f, 7.0f, 8.0f, // Second column + 9.0f, 10.0f, 11.0f, 12.0f, // Third column + 13.0f, 14.0f, 15.0f, 16.0f // Fourth column + }; + + // Expected values when transpose = GL_FALSE (no transpose): + // [1 5 9 13] + // [2 6 10 14] + // [3 7 11 15] + // [4 8 12 16] + GLfloat expected4x4_no_transpose[16] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f}; + + // Expected values when transpose = GL_TRUE (transposed): + // [1 2 3 4] + // [5 6 7 8] + // [9 10 11 12] + // [13 14 15 16] + // Stored in column-major order + GLfloat expected4x4_transpose[16] = {1.0f, 5.0f, 9.0f, 13.0f, 2.0f, 6.0f, 10.0f, 14.0f, + 3.0f, 7.0f, 11.0f, 15.0f, 4.0f, 8.0f, 12.0f, 16.0f}; + + // Test with transpose = GL_FALSE + UniformMatrix4fv(locProjMat, 1, GL_FALSE, matrix4x4); + GLfloat result4x4_no_transpose[16]; + GetUniformfv(program, locProjMat, result4x4_no_transpose); + for (int i = 0; i < 16; i++) { + EXPECT_FLOAT_EQ(result4x4_no_transpose[i], expected4x4_no_transpose[i]); + } + + // Test with transpose = GL_TRUE + UniformMatrix4fv(locProjMat, 1, GL_TRUE, matrix4x4); + GLfloat result4x4_transpose[16]; + GetUniformfv(program, locProjMat, result4x4_transpose); + for (int i = 0; i < 16; i++) { + EXPECT_FLOAT_EQ(result4x4_transpose[i], expected4x4_transpose[i]); + } +} From ee129c4fb6a447501c6d10b5e223a4eb000baf62 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 22 Aug 2025 17:34:13 +0800 Subject: [PATCH 03/12] [Test] (MG_Test/ProgramTest/UniformMatrixTranspose): hard assert that uniforms to be tested exists --- MobileGL/MG_Test/Program/ProgramTest.cpp | 146 +++++++++++------------ 1 file changed, 72 insertions(+), 74 deletions(-) diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 3eb9d853..9cf5bf89 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -292,84 +292,82 @@ TEST_F(ProgramTest, UniformMatrixTranspose) { // Test 2x2 matrix transpose auto locMat2 = GetUniformLocation(program, "TestMat2"); - if (locMat2 != -1) { - // Test matrix (column-major as expected by OpenGL): - // [1 3] - // [2 4] - GLfloat matrix2x2[4] = { - 1.0f, 2.0f, // First column - 3.0f, 4.0f // Second column - }; - - // Expected values when transpose = GL_FALSE (no transpose): - // [1 3] - // [2 4] - GLfloat expected2x2_no_transpose[4] = {1.0f, 2.0f, 3.0f, 4.0f}; - - // Expected values when transpose = GL_TRUE (transposed): - // [1 2] - // [3 4] - // Stored in column-major order: [1, 3, 2, 4] - GLfloat expected2x2_transpose[4] = {1.0f, 3.0f, 2.0f, 4.0f}; - - // Test with transpose = GL_FALSE - UniformMatrix2fv(locMat2, 1, GL_FALSE, matrix2x2); - GLfloat result2x2_no_transpose[4]; - GetUniformfv(program, locMat2, result2x2_no_transpose); - for (int i = 0; i < 4; i++) { - EXPECT_FLOAT_EQ(result2x2_no_transpose[i], expected2x2_no_transpose[i]); - } - - // Test with transpose = GL_TRUE - UniformMatrix2fv(locMat2, 1, GL_TRUE, matrix2x2); - GLfloat result2x2_transpose[4]; - GetUniformfv(program, locMat2, result2x2_transpose); - for (int i = 0; i < 4; i++) { - EXPECT_FLOAT_EQ(result2x2_transpose[i], expected2x2_transpose[i]); - } + ASSERT_NE(locMat2, -1); + // Test matrix (column-major as expected by OpenGL): + // [1 3] + // [2 4] + GLfloat matrix2x2[4] = { + 1.0f, 2.0f, // First column + 3.0f, 4.0f // Second column + }; + + // Expected values when transpose = GL_FALSE (no transpose): + // [1 3] + // [2 4] + GLfloat expected2x2_no_transpose[4] = {1.0f, 2.0f, 3.0f, 4.0f}; + + // Expected values when transpose = GL_TRUE (transposed): + // [1 2] + // [3 4] + // Stored in column-major order: [1, 3, 2, 4] + GLfloat expected2x2_transpose[4] = {1.0f, 3.0f, 2.0f, 4.0f}; + + // Test with transpose = GL_FALSE + UniformMatrix2fv(locMat2, 1, GL_FALSE, matrix2x2); + GLfloat result2x2_no_transpose[4]; + GetUniformfv(program, locMat2, result2x2_no_transpose); + for (int i = 0; i < 4; i++) { + EXPECT_FLOAT_EQ(result2x2_no_transpose[i], expected2x2_no_transpose[i]); + } + + // Test with transpose = GL_TRUE + UniformMatrix2fv(locMat2, 1, GL_TRUE, matrix2x2); + GLfloat result2x2_transpose[4]; + GetUniformfv(program, locMat2, result2x2_transpose); + for (int i = 0; i < 4; i++) { + EXPECT_FLOAT_EQ(result2x2_transpose[i], expected2x2_transpose[i]); } // Test 3x3 matrix transpose auto locMat3 = GetUniformLocation(program, "TestMat3"); - if (locMat3 != -1) { - // Test matrix (column-major as expected by OpenGL): - // [1 4 7] - // [2 5 8] - // [3 6 9] - GLfloat matrix3x3[9] = { - 1.0f, 2.0f, 3.0f, // First column - 4.0f, 5.0f, 6.0f, // Second column - 7.0f, 8.0f, 9.0f // Third column - }; - - // Expected values when transpose = GL_FALSE (no transpose): - // [1 4 7] - // [2 5 8] - // [3 6 9] - GLfloat expected3x3_no_transpose[9] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}; - - // Expected values when transpose = GL_TRUE (transposed): - // [1 2 3] - // [4 5 6] - // [7 8 9] - // Stored in column-major order: [1, 4, 7, 2, 5, 8, 3, 6, 9] - GLfloat expected3x3_transpose[9] = {1.0f, 4.0f, 7.0f, 2.0f, 5.0f, 8.0f, 3.0f, 6.0f, 9.0f}; - - // Test with transpose = GL_FALSE - UniformMatrix3fv(locMat3, 1, GL_FALSE, matrix3x3); - GLfloat result3x3_no_transpose[9]; - GetUniformfv(program, locMat3, result3x3_no_transpose); - for (int i = 0; i < 9; i++) { - EXPECT_FLOAT_EQ(result3x3_no_transpose[i], expected3x3_no_transpose[i]); - } - - // Test with transpose = GL_TRUE - UniformMatrix3fv(locMat3, 1, GL_TRUE, matrix3x3); - GLfloat result3x3_transpose[9]; - GetUniformfv(program, locMat3, result3x3_transpose); - for (int i = 0; i < 9; i++) { - EXPECT_FLOAT_EQ(result3x3_transpose[i], expected3x3_transpose[i]); - } + ASSERT_NE(locMat3, -1); + // Test matrix (column-major as expected by OpenGL): + // [1 4 7] + // [2 5 8] + // [3 6 9] + GLfloat matrix3x3[9] = { + 1.0f, 2.0f, 3.0f, // First column + 4.0f, 5.0f, 6.0f, // Second column + 7.0f, 8.0f, 9.0f // Third column + }; + + // Expected values when transpose = GL_FALSE (no transpose): + // [1 4 7] + // [2 5 8] + // [3 6 9] + GLfloat expected3x3_no_transpose[9] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}; + + // Expected values when transpose = GL_TRUE (transposed): + // [1 2 3] + // [4 5 6] + // [7 8 9] + // Stored in column-major order: [1, 4, 7, 2, 5, 8, 3, 6, 9] + GLfloat expected3x3_transpose[9] = {1.0f, 4.0f, 7.0f, 2.0f, 5.0f, 8.0f, 3.0f, 6.0f, 9.0f}; + + // Test with transpose = GL_FALSE + UniformMatrix3fv(locMat3, 1, GL_FALSE, matrix3x3); + GLfloat result3x3_no_transpose[9]; + GetUniformfv(program, locMat3, result3x3_no_transpose); + for (int i = 0; i < 9; i++) { + EXPECT_FLOAT_EQ(result3x3_no_transpose[i], expected3x3_no_transpose[i]); + } + + // Test with transpose = GL_TRUE + UniformMatrix3fv(locMat3, 1, GL_TRUE, matrix3x3); + GLfloat result3x3_transpose[9]; + GetUniformfv(program, locMat3, result3x3_transpose); + for (int i = 0; i < 9; i++) { + EXPECT_FLOAT_EQ(result3x3_transpose[i], expected3x3_transpose[i]); } // Test 4x4 matrix transpose From 0da2a59e4d089e670a6f5ea00d3ea5a2800cd554 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 22 Aug 2025 17:35:38 +0800 Subject: [PATCH 04/12] [Test] (MG_Test/ProgramTest/UniformMatrixFunctions): get rid of junk --- MobileGL/MG_Test/Program/ProgramTest.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 9cf5bf89..abd62c5c 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -243,15 +243,6 @@ TEST_F(ProgramTest, UniformMatrixFunctions) { // Test with transpose = GL_TRUE UniformMatrix4fv(locProjMat, 1, GL_TRUE, nonIdentityMatrix); - - // Test UniformMatrix3fv with a 3x3 matrix - // We would need a 3x3 uniform in the shader for this test - - // Test UniformMatrix2fv with a 2x2 matrix - // We would need a 2x2 uniform in the shader for this test - - // Test with multiple matrices (count > 1) - // For this test, we would need uniforms that are arrays of matrices } TEST_F(ProgramTest, UniformMatrixTranspose) { From 620391b7ecd7fd917a88f90b4d8006ac53cfe860 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 22 Aug 2025 17:53:42 +0800 Subject: [PATCH 05/12] [Test] (MG_Test/ProgramTest/UniformLocationGaps): add test to check uniform locations with gap --- MobileGL/MG_Test/Program/ProgramTest.cpp | 90 ++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index abd62c5c..8d69bbc6 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -410,3 +410,93 @@ TEST_F(ProgramTest, UniformMatrixTranspose) { EXPECT_FLOAT_EQ(result4x4_transpose[i], expected4x4_transpose[i]); } } + +TEST_F(ProgramTest, UniformLocationGaps) { + char infoLog[1024] = ""; + + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &vsSrc, NULL); + CompileShader(vs); + GLint vsStatus = GL_FALSE; + GetShaderiv(vs, GL_COMPILE_STATUS, &vsStatus); + GetShaderInfoLog(vs, 1024, nullptr, infoLog); + ASSERT_EQ(vsStatus, GL_TRUE) << infoLog; + + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &fsSrc, NULL); + CompileShader(fs); + GLint fsStatus = GL_FALSE; + GetShaderiv(fs, GL_COMPILE_STATUS, &fsStatus); + GetShaderInfoLog(fs, 1024, nullptr, infoLog); + ASSERT_EQ(fsStatus, GL_TRUE) << infoLog; + + GLuint program = CreateProgram(); + AttachShader(program, vs); + AttachShader(program, fs); + + BindAttribLocation(program, 1, "fIn1"); + BindAttribLocation(program, 3, "fIn3"); + BindAttribLocation(program, 5, "fIn5"); + LinkProgram(program); + + UseProgram(program); + + // Test that uniform locations are correctly assigned even with gaps + // ProjMat is at location 0 + ASSERT_EQ(GetUniformLocation(program, "ProjMat"), 0); + + // TestMat3 is at location 10 (gap from 1-9) + ASSERT_EQ(GetUniformLocation(program, "TestMat3"), 10); + + // TestMat2 is at location 20 (gap from 11-19) + ASSERT_EQ(GetUniformLocation(program, "TestMat2"), 20); + + // Gray is at location 1 (no gap) + ASSERT_EQ(GetUniformLocation(program, "Gray"), 1); + + // Saturation is at location 6 (gap from 2-5) + ASSERT_EQ(GetUniformLocation(program, "Saturation"), 6); + + // Verify that locations in gaps correctly return -1 + ASSERT_EQ(GetUniformLocation(program, "NonExistentUniform"), -1); + + // Test uniform operations on locations with gaps + GLfloat matrix3[9] = { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f + }; + + // Test setting and getting uniform at location 10 (TestMat3) + UniformMatrix3fv(10, 1, GL_FALSE, matrix3); + GLfloat result[9]; + GetUniformfv(program, 10, result); + for (int i = 0; i < 9; i++) { + EXPECT_FLOAT_EQ(result[i], matrix3[i]); + } + + // Test setting and getting uniform at location 20 (TestMat2) + GLfloat matrix2[4] = { + 1.0f, 0.0f, + 0.0f, 1.0f + }; + UniformMatrix2fv(20, 1, GL_FALSE, matrix2); + GLfloat result2[4]; + GetUniformfv(program, 20, result2); + for (int i = 0; i < 4; i++) { + EXPECT_FLOAT_EQ(result2[i], matrix2[i]); + } + + // Test that accessing a gap location (e.g., 5) doesn't cause issues + // This should not crash or cause undefined behavior + Uniform1i(5, 114514); // Just to make sure we don't crash + + // Verify that we can still use uniforms with sequential locations + auto locRed = GetUniformLocation(program, "RedMatrix"); + Uniform3f(locRed, 1.0, 3.0, 5.0); + float redVal[3]; + GetUniformfv(program, locRed, redVal); + ASSERT_EQ(redVal[0], 1.0); + ASSERT_EQ(redVal[1], 3.0); + ASSERT_EQ(redVal[2], 5.0); +} From 556d47a9d57fce817b2dc5d5595e9db186b1ced3 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 24 Aug 2025 12:56:24 +0800 Subject: [PATCH 06/12] [Benchmark] (MG_Benchmark/Program): shader compilation benchmark --- .github/workflows/benchmark.yml | 2 +- MobileGL/MG_Benchmark/CMakeLists.txt | 13 +- MobileGL/MG_Benchmark/Program/CMakeLists.txt | 111 +++++++++++++ .../MG_Benchmark/Program/ProgramBench.cpp | 155 ++++++++++++++++++ 4 files changed, 277 insertions(+), 4 deletions(-) create mode 100644 MobileGL/MG_Benchmark/Program/CMakeLists.txt create mode 100644 MobileGL/MG_Benchmark/Program/ProgramBench.cpp diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 319f794c..38975456 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -48,4 +48,4 @@ jobs: - name: Benchmark working-directory: ${{env.BENCH_ROOT}}/build-bench - run: ctest -V \ No newline at end of file + run: ctest -V -C Release \ No newline at end of file diff --git a/MobileGL/MG_Benchmark/CMakeLists.txt b/MobileGL/MG_Benchmark/CMakeLists.txt index 8ae6353a..2e6df4d7 100644 --- a/MobileGL/MG_Benchmark/CMakeLists.txt +++ b/MobileGL/MG_Benchmark/CMakeLists.txt @@ -1,9 +1,13 @@ cmake_minimum_required(VERSION 3.14) -project(MobileGLTest) +project(MobileGLBenchmark) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Enable downloading dependencies +set(BENCHMARK_DOWNLOAD_DEPENDENCIES ON CACHE BOOL "Allow downloading benchmark dependencies") +set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "Disable GTest tests") +set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable testing") include(FetchContent) FetchContent_Declare( @@ -14,15 +18,18 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(benchmark) +enable_testing() + set(MGL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) add_executable(SanityBench SanityBench.cpp ) + target_link_libraries(SanityBench PRIVATE benchmark::benchmark ) -enable_testing() +add_test(NAME SanityBench COMMAND SanityBench --benchmark_counters_tabular=true) -add_test(NAME SanityBench COMMAND SanityBench) \ No newline at end of file +add_subdirectory(Program) \ No newline at end of file diff --git a/MobileGL/MG_Benchmark/Program/CMakeLists.txt b/MobileGL/MG_Benchmark/Program/CMakeLists.txt new file mode 100644 index 00000000..d73586f2 --- /dev/null +++ b/MobileGL/MG_Benchmark/Program/CMakeLists.txt @@ -0,0 +1,111 @@ +cmake_minimum_required(VERSION 3.24) + +# Vulkan SDK's cmake config is fundamentally broken. Directly find libs instead +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + find_package(Vulkan REQUIRED) + get_filename_component(VULKAN_LIB_DIR ${Vulkan_LIBRARY} PATH) + + set(LINK_LIBRARIES + ${VULKAN_LIB_DIR}/libglslang.a + ${VULKAN_LIB_DIR}/libspirv-cross-c-shared.dylib + ${VULKAN_LIB_DIR}/libGenericCodeGen.a + ${VULKAN_LIB_DIR}/libglslang-default-resource-limits.a + ${VULKAN_LIB_DIR}/libMachineIndependent.a + ${VULKAN_LIB_DIR}/libOSDependent.a + ${VULKAN_LIB_DIR}/libSPIRV-Tools-diff.a + ${VULKAN_LIB_DIR}/libSPIRV-Tools-link.a + ${VULKAN_LIB_DIR}/libSPIRV-Tools-lint.a + ${VULKAN_LIB_DIR}/libSPIRV-Tools-opt.a + ${VULKAN_LIB_DIR}/libSPIRV-Tools-reduce.a + ${VULKAN_LIB_DIR}/libSPIRV-Tools.a + ${VULKAN_LIB_DIR}/libSPIRV.a + ${VULKAN_LIB_DIR}/libSPVRemapper.a) +elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + find_package(Vulkan REQUIRED) + get_filename_component(VULKAN_LIB_DIR ${Vulkan_LIBRARY} PATH) + + set(LINK_LIBRARIES + ${VULKAN_LIB_DIR}/glslang$<$:d>.lib + ${VULKAN_LIB_DIR}/spirv-cross-c-shared$<$:d>.lib + ${VULKAN_LIB_DIR}/GenericCodeGen$<$:d>.lib + ${VULKAN_LIB_DIR}/glslang-default-resource-limits$<$:d>.lib + ${VULKAN_LIB_DIR}/MachineIndependent$<$:d>.lib + ${VULKAN_LIB_DIR}/OSDependent$<$:d>.lib + ${VULKAN_LIB_DIR}/SPIRV-Tools-diff$<$:d>.lib + ${VULKAN_LIB_DIR}/SPIRV-Tools-link$<$:d>.lib + ${VULKAN_LIB_DIR}/SPIRV-Tools-lint$<$:d>.lib + ${VULKAN_LIB_DIR}/SPIRV-Tools-opt$<$:d>.lib + ${VULKAN_LIB_DIR}/SPIRV-Tools-reduce$<$:d>.lib + ${VULKAN_LIB_DIR}/SPIRV-Tools$<$:d>.lib + ${VULKAN_LIB_DIR}/SPIRV$<$:d>.lib + ${VULKAN_LIB_DIR}/SPVRemapper$<$:d>.lib) +else () + find_package(glslang CONFIG REQUIRED) + find_package(spirv_cross_core CONFIG REQUIRED) + find_package(spirv_cross_glsl CONFIG REQUIRED) + find_package(spirv_cross_hlsl CONFIG REQUIRED) + find_package(spirv_cross_msl CONFIG REQUIRED) + find_package(spirv_cross_cpp CONFIG REQUIRED) + find_package(spirv_cross_reflect CONFIG REQUIRED) + find_package(spirv_cross_c CONFIG REQUIRED) + set(LINK_LIBRARIES glslang::glslang spirv-cross-c) +endif() + +add_executable( + ProgramBench + ProgramBench.cpp + + ${MGL_ROOT}/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp + + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp + + ${MGL_ROOT}/MobileGL/MG_Util/ShaderTranspiler/glslang/UniformTraverser.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/SPIRVCrossToGL/SpvcTypeConverter.cpp + + ${MGL_ROOT}/MobileGL/MG_State/GLState/Core.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/BufferState/BufferState.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/BufferState/BufferObject.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/TextureState/TextureUnit.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/TextureState/TextureState.cpp + ${MGL_ROOT}/MobileGL/MG_State/GLState/ErrorState/Error.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/Buffer/Validators.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/VertexArray/Validators.cpp + ${MGL_ROOT}/MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToStr/GLEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToStr/GLExtensionConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToStr/BufferEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToStr/DataTypeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToGlslang/GLShaderLangConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/ErrorCodeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/BufferEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/MGToGL/DataTypeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/BufferEnumConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Converters/GLToMG/DataTypeConverter.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Metrics/BufferMetrics.cpp + ${MGL_ROOT}/MobileGL/MG_Backend/Init.cpp + ${MGL_ROOT}/MobileGL/MG_Util/Debug/Log.cpp +) + +target_include_directories(ProgramBench PRIVATE + ${MGL_ROOT}/include + ${MGL_ROOT}/MobileGL +) + +target_link_libraries( + ProgramBench + benchmark::benchmark + ${LINK_LIBRARIES} +) + +add_test(NAME ProgramBench COMMAND ProgramBench --benchmark_counters_tabular=true) \ No newline at end of file diff --git a/MobileGL/MG_Benchmark/Program/ProgramBench.cpp b/MobileGL/MG_Benchmark/Program/ProgramBench.cpp new file mode 100644 index 00000000..c42721a6 --- /dev/null +++ b/MobileGL/MG_Benchmark/Program/ProgramBench.cpp @@ -0,0 +1,155 @@ +#include +#include "MG_Impl/GLImpl/Program/GL_Program.h" +#include "MG_State/GLState/Core.h" + +using namespace MobileGL; +using namespace MobileGL::MG_Impl::GLImpl; + +// Shader source code for benchmarking +const char* vsSrc = R"(#version 460 + +layout (location = 0) in vec4 Position; +in float fIn4; +in float fIn2; +in float fIn5; +in float fIn6; +in float fIn1; +in float fIn3; + +layout(location = 0) uniform mat4 ProjMat; +layout(location = 10) uniform mat3 TestMat3; +layout(location = 20) uniform mat2 TestMat2; +uniform vec2 InSize; +uniform vec2 OutSize; + +out vec2 texCoord; +out vec2 oneTexel; + +void main(){ + vec4 outPos = ProjMat * vec4(Position.xy, 0.0, 1.0); + gl_Position = vec4(outPos.xy, 0.2, 1.0); + + // Use TestMat2 and TestMat3 to prevent optimization + vec2 dummy2 = TestMat2[0]; + vec3 dummy3 = TestMat3[0]; + + oneTexel = (1.0 * (fIn1 * fIn2 * fIn3 * fIn4 * fIn5 * fIn6)) / InSize; + + texCoord = Position.xy / OutSize; +})"; + +const char* fsSrc = R"(#version 460 + +uniform sampler2D InSampler; + +in vec2 texCoord; +in vec2 oneTexel; + +uniform vec2 InSize; + +layout(location = 1) uniform vec3 Gray; +uniform vec3 RedMatrix; +uniform vec3 GreenMatrix0; +uniform vec3 BlueMatrix; +uniform vec3 Offset; +uniform vec3 ColorScale; +layout(location = 6) uniform float Saturation; +uniform int AQuickFoxJumpsOverALazyDog; +uniform int intVal; + +out vec4 fragColor; + +void main() { + vec4 InTexel = texture(InSampler, texCoord); + + // Color Matrix + float RedValue = dot(InTexel.rgb, RedMatrix); + float GreenValue = dot(InTexel.rgb, GreenMatrix0); + float BlueValue = dot(InTexel.rgb, BlueMatrix); + vec3 OutColor = vec3(RedValue, GreenValue, BlueValue); + + // Offset & Scale + OutColor = (OutColor * ColorScale) + Offset; + + // Saturation + float Luma = dot(OutColor, Gray); + vec3 Chroma = OutColor - Luma; + OutColor = (Chroma * Saturation) + Luma; + + fragColor = vec4(OutColor, float(intVal)); +})"; + +static void BM_CompileVertexShader(benchmark::State& state) { + // Initialize GL context + MG_State::pGLContext = new MG_State::GLState::GLContext(); + + for (auto _ : state) { + // Create and compile vertex shader + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &vsSrc, NULL); + CompileShader(vs); + + // Cleanup + DeleteShader(vs); + } + + // Set the counter for Compiles/Second + state.counters["VS_Compiles/Second"] = state.iterations(); + + // Cleanup GL context + delete MG_State::pGLContext; +} +BENCHMARK(BM_CompileVertexShader)->Unit(benchmark::kMillisecond); + +static void BM_CompileFragmentShader(benchmark::State& state) { + // Initialize GL context + MG_State::pGLContext = new MG_State::GLState::GLContext(); + + for (auto _ : state) { + // Create and compile fragment shader + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &fsSrc, NULL); + CompileShader(fs); + + // Cleanup + DeleteShader(fs); + } + + // Set the counter for Compiles/Second + state.counters["FS_Compiles/Second"] = state.iterations(); + + // Cleanup GL context + delete MG_State::pGLContext; +} +BENCHMARK(BM_CompileFragmentShader)->Unit(benchmark::kMillisecond); + +static void BM_CompileBothShaders(benchmark::State& state) { + // Initialize GL context + MG_State::pGLContext = new MG_State::GLState::GLContext(); + + for (auto _ : state) { + // Create and compile vertex shader + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &vsSrc, NULL); + CompileShader(vs); + + // Create and compile fragment shader + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &fsSrc, NULL); + CompileShader(fs); + + // Cleanup + DeleteShader(vs); + DeleteShader(fs); + } + + // Set the counter for Compiles/Second + state.counters["VS_Compiles/Second"] = state.iterations(); + state.counters["FS_Compiles/Second"] = state.iterations(); + + // Cleanup GL context + delete MG_State::pGLContext; +} +BENCHMARK(BM_CompileBothShaders)->Unit(benchmark::kMillisecond); + +BENCHMARK_MAIN(); \ No newline at end of file From a5ab9fe503e08c6b1ec1a5e6c3fb6ecb828c389b Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 25 Aug 2025 09:28:09 +0800 Subject: [PATCH 07/12] [Chore] (MG_State/Program): get rid of junk printing when linking --- MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 951faaad..656e9454 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -167,8 +167,8 @@ namespace MobileGL { SpvcSession session(m_generatedSpirv[0]); auto srcResult = ShaderCompiler::DecompileShader(session); assert(srcResult); - auto src = srcResult.value(); - printf("decompiled src: \n%s\n", src.c_str()); + // auto src = srcResult.value(); + // printf("decompiled src: \n%s\n", src.c_str()); auto& meta = session.GetMetadata(); auto size = meta.uboSize; From 591f61a9f09cff929a0b4a2add3f530d534006da Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 25 Aug 2025 09:28:55 +0800 Subject: [PATCH 08/12] [Feat] (MG_Benchmark/Program): add linking benchmark, add more metrics to benchmarks --- .../MG_Benchmark/Program/ProgramBench.cpp | 97 ++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/MobileGL/MG_Benchmark/Program/ProgramBench.cpp b/MobileGL/MG_Benchmark/Program/ProgramBench.cpp index c42721a6..d047f43f 100644 --- a/MobileGL/MG_Benchmark/Program/ProgramBench.cpp +++ b/MobileGL/MG_Benchmark/Program/ProgramBench.cpp @@ -1,4 +1,6 @@ +#include #include + #include "MG_Impl/GLImpl/Program/GL_Program.h" #include "MG_State/GLState/Core.h" @@ -82,7 +84,9 @@ void main() { static void BM_CompileVertexShader(benchmark::State& state) { // Initialize GL context MG_State::pGLContext = new MG_State::GLState::GLContext(); - + + SizeT vsLen = strlen(vsSrc); + for (auto _ : state) { // Create and compile vertex shader GLuint vs = CreateShader(GL_VERTEX_SHADER); @@ -95,6 +99,7 @@ static void BM_CompileVertexShader(benchmark::State& state) { // Set the counter for Compiles/Second state.counters["VS_Compiles/Second"] = state.iterations(); + state.counters["VS_Bytes/Second"] = state.iterations() * vsLen; // Cleanup GL context delete MG_State::pGLContext; @@ -104,7 +109,9 @@ BENCHMARK(BM_CompileVertexShader)->Unit(benchmark::kMillisecond); static void BM_CompileFragmentShader(benchmark::State& state) { // Initialize GL context MG_State::pGLContext = new MG_State::GLState::GLContext(); - + + SizeT fsLen = strlen(fsSrc); + for (auto _ : state) { // Create and compile fragment shader GLuint fs = CreateShader(GL_FRAGMENT_SHADER); @@ -117,7 +124,8 @@ static void BM_CompileFragmentShader(benchmark::State& state) { // Set the counter for Compiles/Second state.counters["FS_Compiles/Second"] = state.iterations(); - + state.counters["FS_Bytes/Second"] = state.iterations() * fsLen; + // Cleanup GL context delete MG_State::pGLContext; } @@ -126,7 +134,9 @@ BENCHMARK(BM_CompileFragmentShader)->Unit(benchmark::kMillisecond); static void BM_CompileBothShaders(benchmark::State& state) { // Initialize GL context MG_State::pGLContext = new MG_State::GLState::GLContext(); - + SizeT vsLen = strlen(vsSrc); + SizeT fsLen = strlen(fsSrc); + for (auto _ : state) { // Create and compile vertex shader GLuint vs = CreateShader(GL_VERTEX_SHADER); @@ -146,10 +156,89 @@ static void BM_CompileBothShaders(benchmark::State& state) { // Set the counter for Compiles/Second state.counters["VS_Compiles/Second"] = state.iterations(); state.counters["FS_Compiles/Second"] = state.iterations(); + state.counters["VS_Bytes/Second"] = state.iterations() * vsLen; + state.counters["FS_Bytes/Second"] = state.iterations() * fsLen; // Cleanup GL context delete MG_State::pGLContext; } BENCHMARK(BM_CompileBothShaders)->Unit(benchmark::kMillisecond); +static void BM_LinkProgram(benchmark::State& state) { + // Initialize GL context + MG_State::pGLContext = new MG_State::GLState::GLContext(); + + // Create and compile vertex shader + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &vsSrc, NULL); + CompileShader(vs); + + // Create and compile fragment shader + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &fsSrc, NULL); + CompileShader(fs); + + for (auto _ : state) { + GLuint program = CreateProgram(); + AttachShader(program, vs); + AttachShader(program, fs); + LinkProgram(program); + DeleteProgram(program); + } + + // Cleanup + DeleteShader(vs); + DeleteShader(fs); + + // Set the counter for Compiles/Second + state.counters["Links/Second"] = state.iterations(); + + // Cleanup GL context + delete MG_State::pGLContext; +} +BENCHMARK(BM_LinkProgram)->Unit(benchmark::kMillisecond); + +static void BM_CompileAndLink(benchmark::State& state) { + // Initialize GL context + MG_State::pGLContext = new MG_State::GLState::GLContext(); + + SizeT vsLen = strlen(vsSrc); + SizeT fsLen = strlen(fsSrc); + + for (auto _ : state) { + // Create and compile vertex shader + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &vsSrc, NULL); + CompileShader(vs); + + // Create and compile fragment shader + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &fsSrc, NULL); + CompileShader(fs); + + GLuint program = CreateProgram(); + AttachShader(program, vs); + AttachShader(program, fs); + LinkProgram(program); + DeleteProgram(program); + + // Cleanup + DeleteShader(vs); + DeleteShader(fs); + } + + + // Set the counter for Compiles/Second + state.counters["VS_Compiles/Second"] = state.iterations(); + state.counters["FS_Compiles/Second"] = state.iterations(); + state.counters["VS_Bytes/Second"] = state.iterations() * vsLen; + state.counters["FS_Bytes/Second"] = state.iterations() * fsLen; + state.counters["Links/Second"] = state.iterations(); + + // Cleanup GL context + delete MG_State::pGLContext; +} + +BENCHMARK(BM_CompileAndLink)->Unit(benchmark::kMillisecond); + BENCHMARK_MAIN(); \ No newline at end of file From fae9bcd0df7312ca152fc86f46a3604a32573162 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 25 Aug 2025 12:30:32 +0800 Subject: [PATCH 09/12] [Refactor] (buildsystem): use FindXXX.cmake to find 3rdparty libraries --- MobileGL/MG_Test/CMakeLists.txt | 66 ++---- buildsystem/cmake/FindSPIRVCross.cmake | 297 +++++++++++++++++++++++++ buildsystem/cmake/FindSPIRVTools.cmake | 153 +++++++++++++ buildsystem/cmake/Findglslang.cmake | 237 ++++++++++++++++++++ 4 files changed, 704 insertions(+), 49 deletions(-) create mode 100644 buildsystem/cmake/FindSPIRVCross.cmake create mode 100644 buildsystem/cmake/FindSPIRVTools.cmake create mode 100644 buildsystem/cmake/Findglslang.cmake diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index b4efe926..aa8cb0ba 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -4,6 +4,9 @@ project(MobileGLTest) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Add the directory containing our custom Find modules +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../buildsystem/cmake") + include(FetchContent) FetchContent_Declare( googletest @@ -18,6 +21,11 @@ enable_testing() set(MGL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) +# Find the required libraries using our custom Find modules +find_package(glslang REQUIRED) +find_package(SPIRVTools REQUIRED) +find_package(SPIRVCross REQUIRED) + add_executable( SanityTest SanityTest.cpp @@ -27,56 +35,16 @@ target_link_libraries( GTest::gtest_main ) -# Vulkan SDK's cmake config is fundamentally broken. Directly find libs instead -if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - find_package(Vulkan REQUIRED) - get_filename_component(VULKAN_LIB_DIR ${Vulkan_LIBRARY} PATH) +message(STATUS "glslang_LIBRARIES: ${glslang_LIBRARIES}") +message(STATUS "SPIRVTools_LIBRARIES: ${SPIRVTools_LIBRARIES}") +message(STATUS "SPIRVCross_LIBRARIES: ${SPIRVCross_LIBRARIES}") - set(LINK_LIBRARIES - ${VULKAN_LIB_DIR}/libglslang.a - ${VULKAN_LIB_DIR}/libspirv-cross-c-shared.dylib - ${VULKAN_LIB_DIR}/libGenericCodeGen.a - ${VULKAN_LIB_DIR}/libglslang-default-resource-limits.a - ${VULKAN_LIB_DIR}/libMachineIndependent.a - ${VULKAN_LIB_DIR}/libOSDependent.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-diff.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-link.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-lint.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-opt.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-reduce.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools.a - ${VULKAN_LIB_DIR}/libSPIRV.a - ${VULKAN_LIB_DIR}/libSPVRemapper.a) -elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - find_package(Vulkan REQUIRED) - get_filename_component(VULKAN_LIB_DIR ${Vulkan_LIBRARY} PATH) - - set(LINK_LIBRARIES - ${VULKAN_LIB_DIR}/glslang$<$:d>.lib - ${VULKAN_LIB_DIR}/spirv-cross-c-shared$<$:d>.lib - ${VULKAN_LIB_DIR}/GenericCodeGen$<$:d>.lib - ${VULKAN_LIB_DIR}/glslang-default-resource-limits$<$:d>.lib - ${VULKAN_LIB_DIR}/MachineIndependent$<$:d>.lib - ${VULKAN_LIB_DIR}/OSDependent$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-diff$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-link$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-lint$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-opt$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-reduce$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV$<$:d>.lib - ${VULKAN_LIB_DIR}/SPVRemapper$<$:d>.lib) -else () - find_package(glslang CONFIG REQUIRED) - find_package(spirv_cross_core CONFIG REQUIRED) - find_package(spirv_cross_glsl CONFIG REQUIRED) - find_package(spirv_cross_hlsl CONFIG REQUIRED) - find_package(spirv_cross_msl CONFIG REQUIRED) - find_package(spirv_cross_cpp CONFIG REQUIRED) - find_package(spirv_cross_reflect CONFIG REQUIRED) - find_package(spirv_cross_c CONFIG REQUIRED) - set(LINK_LIBRARIES glslang::glslang spirv-cross-c) -endif() +# Set the libraries to link against +set(LINK_LIBRARIES + ${glslang_LIBRARIES} + ${SPIRVTools_LIBRARIES} + ${SPIRVCross_LIBRARIES} +) include(GoogleTest) gtest_discover_tests(SanityTest) diff --git a/buildsystem/cmake/FindSPIRVCross.cmake b/buildsystem/cmake/FindSPIRVCross.cmake new file mode 100644 index 00000000..b852ba12 --- /dev/null +++ b/buildsystem/cmake/FindSPIRVCross.cmake @@ -0,0 +1,297 @@ +# FindSPIRVCross.cmake +# -------------------- +# +# Find SPIRV-Cross library +# +# This module defines the following variables: +# SPIRVCross_FOUND - True if SPIRV-Cross library is found +# SPIRVCross_INCLUDE_DIRS - Include directories for SPIRV-Cross +# SPIRVCross_LIBRARIES - Libraries for SPIRV-Cross +# +# This module reads hints about search locations from: +# SPIRVCross_ROOT - Preferred installation prefix + +# First try to find SPIRV-Cross using CONFIG mode (for vcpkg, conan, etc.) +if (NOT SPIRVCross_FOUND) + find_package(spirv_cross_core CONFIG QUIET) + if (spirv_cross_core_FOUND) + message(STATUS "Found SPIRV-Cross via CONFIG mode") + # Try to find all components + find_package(spirv_cross_glsl CONFIG QUIET) + find_package(spirv_cross_hlsl CONFIG QUIET) + find_package(spirv_cross_msl CONFIG QUIET) + find_package(spirv_cross_cpp CONFIG QUIET) + find_package(spirv_cross_reflect CONFIG QUIET) + find_package(spirv_cross_c CONFIG QUIET) + + # Set the libraries (using the CONFIG mode variables) + set(SPIRVCross_LIBRARIES + spirv-cross-core + spirv-cross-glsl + spirv-cross-hlsl + spirv-cross-msl + spirv-cross-cpp + spirv-cross-reflect + spirv-cross-c + ) + + # Set the include directories + set(SPIRVCross_INCLUDE_DIRS ${spirv_cross_core_INCLUDE_DIRS}) + + # Mark as found + set(SPIRVCross_FOUND TRUE) + endif() +endif() + +# If CONFIG mode failed, try to find Vulkan SDK +if (NOT SPIRVCross_FOUND) + find_package(Vulkan QUIET) + if (Vulkan_FOUND) + get_filename_component(VULKAN_SDK_DIR ${Vulkan_INCLUDE_DIRS} DIRECTORY) + message(STATUS "Found Vulkan SDK: ${VULKAN_SDK_DIR}") + + # Try to find headers in Vulkan SDK + find_path(SPIRVCross_INCLUDE_DIR + NAMES spirv_cross/spirv_cross.hpp + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) + + # Try to find libraries in Vulkan SDK (separate debug/release searches) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + find_library(SPIRVCross_c_LIBRARY + NAMES spirv-cross-cd libspirv-cross-cd spirv-cross-c-sharedd libspirv-cross-c-sharedd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_cpp_LIBRARY + NAMES spirv-cross-cppd libspirv-cross-cppd spirv-cross-cpp-sharedd libspirv-cross-cpp-sharedd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_core_LIBRARY + NAMES spirv-cross-cored libspirv-cross-cored + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_reflect_LIBRARY + NAMES spirv-cross-reflectd libspirv-cross-reflectd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_glsl_LIBRARY + NAMES spirv-cross-glsld libspirv-cross-glsld + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_hlsl_LIBRARY + NAMES spirv-cross-hlsld libspirv-cross-hlsld + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_msl_LIBRARY + NAMES spirv-cross-msld libspirv-cross-msld + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + else() + find_library(SPIRVCross_c_LIBRARY + NAMES spirv-cross-c libspirv-cross-c spirv-cross-c-shared libspirv-cross-c-shared + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_cpp_LIBRARY + NAMES spirv-cross-cpp libspirv-cross-cpp spirv-cross-cpp-shared libspirv-cross-cpp-shared + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_core_LIBRARY + NAMES spirv-cross-core libspirv-cross-core + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_reflect_LIBRARY + NAMES spirv-cross-reflect libspirv-cross-reflect + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_glsl_LIBRARY + NAMES spirv-cross-glsl libspirv-cross-glsl + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_hlsl_LIBRARY + NAMES spirv-cross-hlsl libspirv-cross-hlsl + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVCross_msl_LIBRARY + NAMES spirv-cross-msl libspirv-cross-msl + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + endif() + endif() +endif() + +# If Vulkan SDK search failed, try standard search +if (NOT SPIRVCross_FOUND) + # Look for the header file + find_path(SPIRVCross_INCLUDE_DIR + NAMES spirv_cross/spirv_cross.hpp + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES include + ) + + # Look for the libraries (separate debug/release searches) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + find_library(SPIRVCross_c_LIBRARY + NAMES spirv-cross-cd libspirv-cross-cd spirv-cross-c-sharedd libspirv-cross-c-sharedd + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_cpp_LIBRARY + NAMES spirv-cross-cppd libspirv-cross-cppd spirv-cross-cpp-sharedd libspirv-cross-cpp-sharedd + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_core_LIBRARY + NAMES spirv-cross-cored libspirv-cross-cored + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_reflect_LIBRARY + NAMES spirv-cross-reflectd libspirv-cross-reflectd + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_glsl_LIBRARY + NAMES spirv-cross-glsld libspirv-cross-glsld + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_hlsl_LIBRARY + NAMES spirv-cross-hlsld libspirv-cross-hlsld + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_msl_LIBRARY + NAMES spirv-cross-msld libspirv-cross-msld + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + else() + find_library(SPIRVCross_c_LIBRARY + NAMES spirv-cross-c libspirv-cross-c spirv-cross-c-shared libspirv-cross-c-shared + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_core_LIBRARY + NAMES spirv-cross-core libspirv-cross-core + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_reflect_LIBRARY + NAMES spirv-cross-reflect libspirv-cross-reflect + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_glsl_LIBRARY + NAMES spirv-cross-glsl libspirv-cross-glsl + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_hlsl_LIBRARY + NAMES spirv-cross-hlsl libspirv-cross-hlsl + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVCross_msl_LIBRARY + NAMES spirv-cross-msl libspirv-cross-msl + HINTS ${SPIRVCross_ROOT} ENV SPIRVCross_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + endif() +endif() + +# If we found the main library, mark as found +if (SPIRVCross_c_LIBRARY OR SPIRVCross_cpp_LIBRARY AND SPIRVCross_INCLUDE_DIR) + set(SPIRVCross_FOUND TRUE) +endif() + +# Set the include directory and libraries +if (SPIRVCross_FOUND) + # If we already found the libraries through CONFIG mode, don't override them + if (NOT SPIRVCross_LIBRARIES) + set(SPIRVCross_INCLUDE_DIRS ${SPIRVCross_INCLUDE_DIR}) + set(SPIRVCross_LIBRARIES + ${SPIRVCross_c_LIBRARY} + ${SPIRVCross_cpp_LIBRARY} + ${SPIRVCross_core_LIBRARY} + ${SPIRVCross_reflect_LIBRARY} + ${SPIRVCross_glsl_LIBRARY} + ${SPIRVCross_hlsl_LIBRARY} + ${SPIRVCross_msl_LIBRARY} + ) + endif() +else() + # If we didn't find anything, set the variables from standard search + set(SPIRVCross_INCLUDE_DIRS ${SPIRVCross_INCLUDE_DIR}) + set(SPIRVCross_LIBRARIES + ${SPIRVCross_c_LIBRARY} + ${SPIRVCross_cpp_LIBRARY} + ${SPIRVCross_core_LIBRARY} + ${SPIRVCross_reflect_LIBRARY} + ${SPIRVCross_glsl_LIBRARY} + ${SPIRVCross_hlsl_LIBRARY} + ${SPIRVCross_msl_LIBRARY} + ) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SPIRVCross + REQUIRED_VARS SPIRVCross_INCLUDE_DIR SPIRVCross_LIBRARIES +) + +mark_as_advanced( + SPIRVCross_INCLUDE_DIR + SPIRVCross_LIBRARIES +) \ No newline at end of file diff --git a/buildsystem/cmake/FindSPIRVTools.cmake b/buildsystem/cmake/FindSPIRVTools.cmake new file mode 100644 index 00000000..bc7b65fc --- /dev/null +++ b/buildsystem/cmake/FindSPIRVTools.cmake @@ -0,0 +1,153 @@ +# FindSPIRVTools.cmake +# -------------------- +# +# Find SPIRV-Tools library +# +# This module defines the following variables: +# SPIRVTools_FOUND - True if SPIRV-Tools library is found +# SPIRVTools_INCLUDE_DIRS - Include directories for SPIRV-Tools +# SPIRVTools_LIBRARIES - Libraries for SPIRV-Tools +# +# This module reads hints about search locations from: +# SPIRVTools_ROOT - Preferred installation prefix + +# First try to find SPIRV-Tools using CONFIG mode (for vcpkg, conan, etc.) +if (NOT SPIRVTools_FOUND) + find_package(SPIRV-Tools CONFIG QUIET) + if (SPIRVTools_FOUND) + message(STATUS "Found SPIRV-Tools via CONFIG mode: ${SPIRV-Tools_DIR}") + set(SPIRVTools_INCLUDE_DIRS ${SPIRV-Tools_INCLUDE_DIRS}) + set(SPIRVTools_LIBRARIES ${SPIRV-Tools_LIBRARIES}) + endif() +endif() + +# If CONFIG mode failed, try to find Vulkan SDK +if (NOT SPIRVTools_FOUND) + find_package(Vulkan QUIET) + if (Vulkan_FOUND) + get_filename_component(VULKAN_SDK_DIR ${Vulkan_INCLUDE_DIRS} DIRECTORY) + message(STATUS "Found Vulkan SDK: ${VULKAN_SDK_DIR}") + + # Try to find headers in Vulkan SDK + find_path(SPIRVTools_INCLUDE_DIR + NAMES spirv-tools/libspirv.h + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) + + # Try to find libraries in Vulkan SDK (separate debug/release searches) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + find_library(SPIRVTools_LIBRARY + NAMES SPIRV-Toolsd libSPIRV-Toolsd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVTools_opt_LIBRARY + NAMES SPIRV-Tools-optd libSPIRV-Tools-optd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVTools_link_LIBRARY + NAMES SPIRV-Tools-linkd libSPIRV-Tools-linkd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + else() + find_library(SPIRVTools_LIBRARY + NAMES SPIRV-Tools libSPIRV-Tools + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVTools_opt_LIBRARY + NAMES SPIRV-Tools-opt libSPIRV-Tools-opt + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(SPIRVTools_link_LIBRARY + NAMES SPIRV-Tools-link libSPIRV-Tools-link + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + endif() + endif() +endif() + +# If Vulkan SDK search failed, try standard search +if (NOT SPIRVTools_FOUND) + # Look for the header file + find_path(SPIRVTools_INCLUDE_DIR + NAMES spirv-tools/libspirv.h + HINTS ${SPIRVTools_ROOT} ENV SPIRVTools_ROOT + PATH_SUFFIXES include + ) + + # Look for the libraries (separate debug/release searches) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + find_library(SPIRVTools_LIBRARY + NAMES SPIRV-Toolsd libSPIRV-Toolsd + HINTS ${SPIRVTools_ROOT} ENV SPIRVTools_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVTools_opt_LIBRARY + NAMES SPIRV-Tools-optd libSPIRV-Tools-optd + HINTS ${SPIRVTools_ROOT} ENV SPIRVTools_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVTools_link_LIBRARY + NAMES SPIRV-Tools-linkd libSPIRV-Tools-linkd + HINTS ${SPIRVTools_ROOT} ENV SPIRVTools_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + else() + find_library(SPIRVTools_LIBRARY + NAMES SPIRV-Tools libSPIRV-Tools + HINTS ${SPIRVTools_ROOT} ENV SPIRVTools_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVTools_opt_LIBRARY + NAMES SPIRV-Tools-opt libSPIRV-Tools-opt + HINTS ${SPIRVTools_ROOT} ENV SPIRVTools_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(SPIRVTools_link_LIBRARY + NAMES SPIRV-Tools-link libSPIRV-Tools-link + HINTS ${SPIRVTools_ROOT} ENV SPIRVTools_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + endif() +endif() + +# Set the include directory and libraries +set(SPIRVTools_INCLUDE_DIRS ${SPIRVTools_INCLUDE_DIR}) +set(SPIRVTools_LIBRARIES + ${SPIRVTools_LIBRARY} + ${SPIRVTools_opt_LIBRARY} + ${SPIRVTools_link_LIBRARY} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SPIRVTools + REQUIRED_VARS SPIRVTools_INCLUDE_DIR SPIRVTools_LIBRARY +) + +mark_as_advanced( + SPIRVTools_INCLUDE_DIR + SPIRVTools_LIBRARY + SPIRVTools_opt_LIBRARY + SPIRVTools_link_LIBRARY +) \ No newline at end of file diff --git a/buildsystem/cmake/Findglslang.cmake b/buildsystem/cmake/Findglslang.cmake new file mode 100644 index 00000000..736ec92f --- /dev/null +++ b/buildsystem/cmake/Findglslang.cmake @@ -0,0 +1,237 @@ +# Findglslang.cmake +# ------------------ +# +# Find glslang library +# +# This module defines the following variables: +# glslang_FOUND - True if glslang library is found +# glslang_INCLUDE_DIRS - Include directories for glslang +# glslang_LIBRARIES - Libraries for glslang +# +# This module reads hints about search locations from: +# glslang_ROOT - Preferred installation prefix + +# First try to find glslang using CONFIG mode (for vcpkg, conan, etc.) +if (NOT glslang_FOUND) + find_package(glslang CONFIG QUIET) + if (glslang_FOUND) + message(STATUS "Found glslang via CONFIG mode: ${glslang_DIR}") + set(glslang_INCLUDE_DIRS ${glslang_INCLUDE_DIRS} ${glslang_INCLUDE_DIR}) + set(glslang_LIBRARIES ${glslang_LIBRARIES} ${glslang_LIBRARY}) + endif() +endif() + +# If CONFIG mode failed, try to find Vulkan SDK +if (NOT glslang_FOUND) + find_package(Vulkan QUIET) + if (Vulkan_FOUND) + get_filename_component(VULKAN_SDK_DIR ${Vulkan_INCLUDE_DIRS} DIRECTORY) + message(STATUS "Found Vulkan SDK: ${VULKAN_SDK_DIR}") + + # Try to find headers in Vulkan SDK + find_path(glslang_INCLUDE_DIR + NAMES glslang/Public/ShaderLang.h + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) + + # Try to find libraries in Vulkan SDK (separate debug/release searches) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + find_library(glslang_LIBRARY + NAMES glslangd libglslangd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_OSDependent_LIBRARY + NAMES OSDependentd libOSDependentd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_MachineIndependent_LIBRARY + NAMES MachineIndependentd libMachineIndependentd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_GenericCodeGen_LIBRARY + NAMES GenericCodeGend libGenericCodeGend + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_SPIRV_LIBRARY + NAMES SPIRVd libSPIRVd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_glslang_default_resource_limits_LIBRARY + NAMES glslang-default-resource-limitsd libglslang-default-resource-limitsd + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + else() + find_library(glslang_LIBRARY + NAMES glslang libglslang + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_OSDependent_LIBRARY + NAMES OSDependent libOSDependent + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_MachineIndependent_LIBRARY + NAMES MachineIndependent libMachineIndependent + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_GenericCodeGen_LIBRARY + NAMES GenericCodeGen libGenericCodeGen + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_SPIRV_LIBRARY + NAMES SPIRV libSPIRV + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + + find_library(glslang_glslang_default_resource_limits_LIBRARY + NAMES glslang-default-resource-limits libglslang-default-resource-limits + HINTS ${VULKAN_SDK_DIR} + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + NO_DEFAULT_PATH + ) + endif() + endif() +endif() + +# If Vulkan SDK search failed, try standard search +if (NOT glslang_FOUND) + # Look for the header file + find_path(glslang_INCLUDE_DIR + NAMES glslang/Public/ShaderLang.h + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES include + ) + + # Look for the libraries (separate debug/release searches) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + find_library(glslang_LIBRARY + NAMES glslangd libglslangd + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_OSDependent_LIBRARY + NAMES OSDependentd libOSDependentd + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_MachineIndependent_LIBRARY + NAMES MachineIndependentd libMachineIndependentd + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_GenericCodeGen_LIBRARY + NAMES GenericCodeGend libGenericCodeGend + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_SPIRV_LIBRARY + NAMES SPIRVd libSPIRVd + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_glslang_default_resource_limits_LIBRARY + NAMES glslang-default-resource-limitsd libglslang-default-resource-limitsd + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + else() + find_library(glslang_LIBRARY + NAMES glslang libglslang + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_OSDependent_LIBRARY + NAMES OSDependent libOSDependent + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_MachineIndependent_LIBRARY + NAMES MachineIndependent libMachineIndependent + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_GenericCodeGen_LIBRARY + NAMES GenericCodeGen libGenericCodeGen + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_SPIRV_LIBRARY + NAMES SPIRV libSPIRV + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + + find_library(glslang_glslang_default_resource_limits_LIBRARY + NAMES glslang-default-resource-limits libglslang-default-resource-limits + HINTS ${glslang_ROOT} ENV glslang_ROOT + PATH_SUFFIXES lib lib64 lib/x86_64 lib/x64 + ) + endif() +endif() + +# Set the include directory and libraries +set(glslang_INCLUDE_DIRS ${glslang_INCLUDE_DIR}) +set(glslang_LIBRARIES + ${glslang_LIBRARY} + ${glslang_OSDependent_LIBRARY} + ${glslang_MachineIndependent_LIBRARY} + ${glslang_GenericCodeGen_LIBRARY} + ${glslang_SPIRV_LIBRARY} + ${glslang_glslang_default_resource_limits_LIBRARY} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(glslang + REQUIRED_VARS glslang_INCLUDE_DIR glslang_LIBRARY +) + +mark_as_advanced( + glslang_INCLUDE_DIR + glslang_LIBRARY + glslang_OSDependent_LIBRARY + glslang_MachineIndependent_LIBRARY + glslang_GenericCodeGen_LIBRARY + glslang_SPIRV_LIBRARY + glslang_glslang_default_resource_limits_LIBRARY +) \ No newline at end of file From 700d72f1803db44289b06cd5c57c2840d163fd52 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 25 Aug 2025 13:08:22 +0800 Subject: [PATCH 10/12] [Refactor] (buildsystem): don't require SPIRV-Tools --- MobileGL/MG_Test/CMakeLists.txt | 7 +++++-- buildsystem/cmake/FindSPIRVCross.cmake | 14 +++++++++----- buildsystem/cmake/FindSPIRVTools.cmake | 2 +- buildsystem/cmake/Findglslang.cmake | 5 ++--- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index aa8cb0ba..427e0acc 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -23,8 +23,8 @@ set(MGL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) # Find the required libraries using our custom Find modules find_package(glslang REQUIRED) -find_package(SPIRVTools REQUIRED) find_package(SPIRVCross REQUIRED) +find_package(SPIRVTools) add_executable( SanityTest @@ -42,10 +42,13 @@ message(STATUS "SPIRVCross_LIBRARIES: ${SPIRVCross_LIBRARIES}") # Set the libraries to link against set(LINK_LIBRARIES ${glslang_LIBRARIES} - ${SPIRVTools_LIBRARIES} ${SPIRVCross_LIBRARIES} ) +if (SPIRVTools_FOUND) + list(APPEND LINK_LIBRARIES ${SPIRVTools_LIBRARIES}) +endif() + include(GoogleTest) gtest_discover_tests(SanityTest) diff --git a/buildsystem/cmake/FindSPIRVCross.cmake b/buildsystem/cmake/FindSPIRVCross.cmake index b852ba12..1425e5de 100644 --- a/buildsystem/cmake/FindSPIRVCross.cmake +++ b/buildsystem/cmake/FindSPIRVCross.cmake @@ -35,9 +35,6 @@ if (NOT SPIRVCross_FOUND) spirv-cross-c ) - # Set the include directories - set(SPIRVCross_INCLUDE_DIRS ${spirv_cross_core_INCLUDE_DIRS}) - # Mark as found set(SPIRVCross_FOUND TRUE) endif() @@ -288,10 +285,17 @@ endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(SPIRVCross - REQUIRED_VARS SPIRVCross_INCLUDE_DIR SPIRVCross_LIBRARIES + REQUIRED_VARS SPIRVCross_LIBRARIES ) mark_as_advanced( SPIRVCross_INCLUDE_DIR - SPIRVCross_LIBRARIES + SPIRVCross_LIBRARY + SPIRVCross_c_LIBRARY + SPIRVCross_cpp_LIBRARY + SPIRVCross_core_LIBRARY + SPIRVCross_reflect_LIBRARY + SPIRVCross_glsl_LIBRARY + SPIRVCross_hlsl_LIBRARY + SPIRVCross_msl_LIBRARY ) \ No newline at end of file diff --git a/buildsystem/cmake/FindSPIRVTools.cmake b/buildsystem/cmake/FindSPIRVTools.cmake index bc7b65fc..1fae50c2 100644 --- a/buildsystem/cmake/FindSPIRVTools.cmake +++ b/buildsystem/cmake/FindSPIRVTools.cmake @@ -142,7 +142,7 @@ set(SPIRVTools_LIBRARIES include(FindPackageHandleStandardArgs) find_package_handle_standard_args(SPIRVTools - REQUIRED_VARS SPIRVTools_INCLUDE_DIR SPIRVTools_LIBRARY + REQUIRED_VARS SPIRVTools_LIBRARY ) mark_as_advanced( diff --git a/buildsystem/cmake/Findglslang.cmake b/buildsystem/cmake/Findglslang.cmake index 736ec92f..7880b03b 100644 --- a/buildsystem/cmake/Findglslang.cmake +++ b/buildsystem/cmake/Findglslang.cmake @@ -16,8 +16,7 @@ if (NOT glslang_FOUND) find_package(glslang CONFIG QUIET) if (glslang_FOUND) message(STATUS "Found glslang via CONFIG mode: ${glslang_DIR}") - set(glslang_INCLUDE_DIRS ${glslang_INCLUDE_DIRS} ${glslang_INCLUDE_DIR}) - set(glslang_LIBRARIES ${glslang_LIBRARIES} ${glslang_LIBRARY}) + set(glslang_LIBRARY glslang::glslang) endif() endif() @@ -223,7 +222,7 @@ set(glslang_LIBRARIES include(FindPackageHandleStandardArgs) find_package_handle_standard_args(glslang - REQUIRED_VARS glslang_INCLUDE_DIR glslang_LIBRARY + REQUIRED_VARS glslang_LIBRARIES ) mark_as_advanced( From 2be199bad871a6d2a5aeaa26d31d47c6981c76ac Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 25 Aug 2025 13:46:00 +0800 Subject: [PATCH 11/12] [Refactor] (buildsystem): make MG_Benchmark also use FindXXX.cmake --- MobileGL/MG_Benchmark/Program/CMakeLists.txt | 65 ++++++-------------- MobileGL/MG_Test/CMakeLists.txt | 6 +- 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/MobileGL/MG_Benchmark/Program/CMakeLists.txt b/MobileGL/MG_Benchmark/Program/CMakeLists.txt index d73586f2..f2fc3012 100644 --- a/MobileGL/MG_Benchmark/Program/CMakeLists.txt +++ b/MobileGL/MG_Benchmark/Program/CMakeLists.txt @@ -1,54 +1,25 @@ cmake_minimum_required(VERSION 3.24) -# Vulkan SDK's cmake config is fundamentally broken. Directly find libs instead -if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - find_package(Vulkan REQUIRED) - get_filename_component(VULKAN_LIB_DIR ${Vulkan_LIBRARY} PATH) +# Add the directory containing our custom Find modules +list(APPEND CMAKE_MODULE_PATH "${MGL_ROOT}/buildsystem/cmake") - set(LINK_LIBRARIES - ${VULKAN_LIB_DIR}/libglslang.a - ${VULKAN_LIB_DIR}/libspirv-cross-c-shared.dylib - ${VULKAN_LIB_DIR}/libGenericCodeGen.a - ${VULKAN_LIB_DIR}/libglslang-default-resource-limits.a - ${VULKAN_LIB_DIR}/libMachineIndependent.a - ${VULKAN_LIB_DIR}/libOSDependent.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-diff.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-link.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-lint.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-opt.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools-reduce.a - ${VULKAN_LIB_DIR}/libSPIRV-Tools.a - ${VULKAN_LIB_DIR}/libSPIRV.a - ${VULKAN_LIB_DIR}/libSPVRemapper.a) -elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - find_package(Vulkan REQUIRED) - get_filename_component(VULKAN_LIB_DIR ${Vulkan_LIBRARY} PATH) +# Find the required libraries using our custom Find modules +find_package(glslang REQUIRED) +find_package(SPIRVCross REQUIRED) +find_package(SPIRVTools) - set(LINK_LIBRARIES - ${VULKAN_LIB_DIR}/glslang$<$:d>.lib - ${VULKAN_LIB_DIR}/spirv-cross-c-shared$<$:d>.lib - ${VULKAN_LIB_DIR}/GenericCodeGen$<$:d>.lib - ${VULKAN_LIB_DIR}/glslang-default-resource-limits$<$:d>.lib - ${VULKAN_LIB_DIR}/MachineIndependent$<$:d>.lib - ${VULKAN_LIB_DIR}/OSDependent$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-diff$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-link$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-lint$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-opt$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools-reduce$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV-Tools$<$:d>.lib - ${VULKAN_LIB_DIR}/SPIRV$<$:d>.lib - ${VULKAN_LIB_DIR}/SPVRemapper$<$:d>.lib) -else () - find_package(glslang CONFIG REQUIRED) - find_package(spirv_cross_core CONFIG REQUIRED) - find_package(spirv_cross_glsl CONFIG REQUIRED) - find_package(spirv_cross_hlsl CONFIG REQUIRED) - find_package(spirv_cross_msl CONFIG REQUIRED) - find_package(spirv_cross_cpp CONFIG REQUIRED) - find_package(spirv_cross_reflect CONFIG REQUIRED) - find_package(spirv_cross_c CONFIG REQUIRED) - set(LINK_LIBRARIES glslang::glslang spirv-cross-c) +message(STATUS "glslang_LIBRARIES: ${glslang_LIBRARIES}") +message(STATUS "SPIRVTools_LIBRARIES: ${SPIRVTools_LIBRARIES}") +message(STATUS "SPIRVCross_LIBRARIES: ${SPIRVCross_LIBRARIES}") + +# Set the libraries to link against +set(LINK_LIBRARIES + ${glslang_LIBRARIES} + ${SPIRVCross_LIBRARIES} +) + +if (SPIRVTools_FOUND) + list(APPEND LINK_LIBRARIES ${SPIRVTools_LIBRARIES}) endif() add_executable( diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index 427e0acc..ff8235ef 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -4,8 +4,10 @@ project(MobileGLTest) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(MGL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) + # Add the directory containing our custom Find modules -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../buildsystem/cmake") +list(APPEND CMAKE_MODULE_PATH "${MGL_ROOT}/buildsystem/cmake") include(FetchContent) FetchContent_Declare( @@ -19,8 +21,6 @@ FetchContent_MakeAvailable(googletest) enable_testing() -set(MGL_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) - # Find the required libraries using our custom Find modules find_package(glslang REQUIRED) find_package(SPIRVCross REQUIRED) From aebfa2745a97e76110ef1568d3ee8539bc7fea1a Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 25 Aug 2025 14:10:43 +0800 Subject: [PATCH 12/12] [Chore] (3rdparty): add glslang and SPIRV-Cross as submodules --- 3rdparty/SPIRV-Cross | 1 + 3rdparty/glslang | 1 + 2 files changed, 2 insertions(+) create mode 160000 3rdparty/SPIRV-Cross create mode 160000 3rdparty/glslang diff --git a/3rdparty/SPIRV-Cross b/3rdparty/SPIRV-Cross new file mode 160000 index 00000000..0e2880ab --- /dev/null +++ b/3rdparty/SPIRV-Cross @@ -0,0 +1 @@ +Subproject commit 0e2880ab990e79ce6cc8c79c219feda42d98b1e8 diff --git a/3rdparty/glslang b/3rdparty/glslang new file mode 160000 index 00000000..8a85691a --- /dev/null +++ b/3rdparty/glslang @@ -0,0 +1 @@ +Subproject commit 8a85691a0740d390761a1008b4696f57facd02c4