From 556d47a9d57fce817b2dc5d5595e9db186b1ced3 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 24 Aug 2025 12:56:24 +0800 Subject: [PATCH] [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