From 2cbd4c232f3b5cc038b75527ce8c08d923c4a303 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Wed, 7 Jan 2026 18:38:01 +0000 Subject: [PATCH] feat(shader): Integrate local shader compilation with bgfx_tools and add PipelineCompilerService --- CMakeLists.txt | 95 ++++++++++++++---- src/bgfx_tools/geometryc/geometryc.cpp | 2 +- src/bgfx_tools/shaderc/shaderc.h | 2 +- src/bgfx_tools/vertexlayout.h | 46 +++++++++ src/services/impl/bgfx_graphics_backend.hpp | 1 + src/services/impl/bgfx_gui_service.cpp | 16 +-- src/services/impl/bgfx_gui_service.hpp | 5 +- src/services/impl/bgfx_shader_compiler.cpp | 3 +- .../impl/pipeline_compiler_service.cpp | 97 ++++++++++++++----- .../impl/pipeline_compiler_service.hpp | 28 ++++++ tests/test_bgfx_gui_service.cpp | 4 +- tests/test_vulkan_shader_linking.cpp | 6 +- 12 files changed, 245 insertions(+), 60 deletions(-) create mode 100644 src/bgfx_tools/vertexlayout.h create mode 100644 src/services/impl/pipeline_compiler_service.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index dab87eb..187a4b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,14 +11,8 @@ if(ENABLE_VITA) set(BUILD_SDL3_APP OFF CACHE BOOL "Build the SDL3 bgfx demo" FORCE) set(BUILD_SCRIPT_TESTS OFF CACHE BOOL "Build script engine tests" FORCE) endif() -if(CMAKE_GENERATOR MATCHES "Ninja") - if(DEFINED CMAKE_GENERATOR_PLATFORM) - set(CMAKE_GENERATOR_PLATFORM "" CACHE STRING "" FORCE) - endif() - if(DEFINED CMAKE_GENERATOR_TOOLSET) - set(CMAKE_GENERATOR_TOOLSET "" CACHE STRING "" FORCE) - endif() -endif() + + project(SDL3App LANGUAGES CXX) list(APPEND CMAKE_PROGRAM_PATH "C:/ProgramData/chocolatey/bin") if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) @@ -149,8 +143,8 @@ set(SDL3CPP_RENDER_STACK_LIBS EnTT::EnTT) if(TARGET bgfx::bgfx) list(APPEND SDL3CPP_RENDER_STACK_LIBS bgfx::bgfx) endif() -if(TARGET bx::bx) - list(APPEND SDL3CPP_RENDER_STACK_LIBS bx::bx) +if(TARGET bgfx::bx) + list(APPEND SDL3CPP_RENDER_STACK_LIBS bgfx::bx) endif() if(TARGET bimg::bimg) list(APPEND SDL3CPP_RENDER_STACK_LIBS bimg::bimg) @@ -200,6 +194,48 @@ elseif(TARGET stb) endif() endif() +## Local build of bgfx_tools shaderc sources as a library so we can link in-process. +add_library(shaderc_local STATIC + src/bgfx_tools/shaderc/shaderc.cpp + src/bgfx_tools/shaderc/shaderc_glsl.cpp + src/bgfx_tools/shaderc/shaderc_hlsl.cpp + src/bgfx_tools/shaderc/shaderc_metal.cpp + src/bgfx_tools/shaderc/shaderc_pssl.cpp + src/bgfx_tools/shaderc/shaderc_spirv.cpp + src/bgfx_tools/shaderc/shaderc_mem.cpp +) +target_include_directories(shaderc_local PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc" "${CMAKE_CURRENT_SOURCE_DIR}/src") +if(TARGET bgfx::bx) + target_link_libraries(shaderc_local PUBLIC bgfx::bx) +endif() +if(TARGET bgfx::bgfx) + target_link_libraries(shaderc_local PUBLIC bgfx::bgfx) +endif() +# Link shaderc dependencies +if(TARGET glslang::glslang) + target_link_libraries(shaderc_local PUBLIC glslang::glslang) +endif() +if(TARGET spirv-tools::spirv-tools) + target_link_libraries(shaderc_local PUBLIC spirv-tools::spirv-tools) +endif() +if(TARGET shaderc::shaderc) + target_link_libraries(shaderc_local PUBLIC shaderc::shaderc) +endif() + +## Build geometryc tool +# add_executable(geometryc +# src/bgfx_tools/geometryc/geometryc.cpp +# ) +# target_include_directories(geometryc PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") +# target_link_libraries(geometryc PRIVATE ${SDL3CPP_RENDER_STACK_LIBS} meshoptimizer::meshoptimizer cgltf::cgltf) + +## Build texturev tool +# add_executable(texturev +# src/bgfx_tools/texturev/texturev.cpp +# ) +# target_include_directories(texturev PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") +# target_link_libraries(texturev PRIVATE ${SDL3CPP_RENDER_STACK_LIBS}) + if(BUILD_SDL3_APP) add_executable(sdl3_app src/main.cpp @@ -240,8 +276,10 @@ if(BUILD_SDL3_APP) $<$>:src/services/impl/bgfx_graphics_backend.cpp> $<$:src/services/impl/gxm_graphics_backend.cpp> src/app/service_based_app.cpp + src/bgfx_tools/shaderc/shaderc_mem.cpp ) target_include_directories(sdl3_app PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") + target_include_directories(sdl3_app PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") target_link_libraries(sdl3_app PRIVATE ${SDL_TARGET} lua::lua @@ -266,7 +304,11 @@ if(BUILD_SDL3_APP) elseif(TARGET shaderc::shaderc_combined) target_link_libraries(sdl3_app PRIVATE shaderc::shaderc_combined) else() - message(WARNING "shaderc CMake target not found; skipping link. Using local bgfx_tools for shader compilation at runtime.") + if(TARGET shaderc_local) + target_link_libraries(sdl3_app PRIVATE shaderc_local) + else() + message(WARNING "shaderc CMake target not found; skipping link. Using local bgfx_tools executable for shader compilation at runtime.") + endif() endif() endif() target_compile_definitions(sdl3_app PRIVATE SDL_MAIN_HANDLED @@ -327,8 +369,10 @@ add_executable(script_engine_tests src/events/event_bus.cpp src/stb_image.cpp src/services/impl/pipeline_compiler_service.cpp + src/bgfx_tools/shaderc/shaderc_mem.cpp ) target_include_directories(script_engine_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") +target_include_directories(script_engine_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") target_link_libraries(script_engine_tests PRIVATE ${SDL_TARGET} lua::lua @@ -341,12 +385,17 @@ target_link_libraries(script_engine_tests PRIVATE zip::zip libzip::zip ) -if(TARGET shaderc::shaderc) - target_link_libraries(script_engine_tests PRIVATE shaderc::shaderc) +if(TARGET shaderc_local) + target_link_libraries(script_engine_tests PRIVATE shaderc_local) +elseif(TARGET shaderc::shaderc) elseif(TARGET shaderc::shaderc_combined) target_link_libraries(script_engine_tests PRIVATE shaderc::shaderc_combined) else() - message(WARNING "shaderc CMake target not found; skipping link for script_engine_tests.") + if(TARGET shaderc_local) + target_link_libraries(script_engine_tests PRIVATE shaderc_local) + else() + message(WARNING "shaderc CMake target not found; skipping link for script_engine_tests.") + endif() endif() add_test(NAME script_engine_tests COMMAND script_engine_tests) @@ -356,20 +405,27 @@ add_executable(bgfx_gui_service_tests src/services/impl/bgfx_shader_compiler.cpp src/services/impl/materialx_shader_generator.cpp src/services/impl/pipeline_compiler_service.cpp + src/bgfx_tools/shaderc/shaderc_mem.cpp ) target_include_directories(bgfx_gui_service_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") +target_include_directories(bgfx_gui_service_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") target_link_libraries(bgfx_gui_service_tests PRIVATE ${SDL_TARGET} ${SDL3CPP_RENDER_STACK_LIBS} ${SDL3CPP_FREETYPE_LIBS} lunasvg::lunasvg ) -if(TARGET shaderc::shaderc) - target_link_libraries(bgfx_gui_service_tests PRIVATE shaderc::shaderc) +if(TARGET shaderc_local) + target_link_libraries(bgfx_gui_service_tests PRIVATE shaderc_local) +elseif(TARGET shaderc::shaderc) elseif(TARGET shaderc::shaderc_combined) target_link_libraries(bgfx_gui_service_tests PRIVATE shaderc::shaderc_combined) else() - message(WARNING "shaderc CMake target not found; skipping link for bgfx_gui_service_tests.") + if(TARGET shaderc_local) + target_link_libraries(bgfx_gui_service_tests PRIVATE shaderc_local) + else() + message(WARNING "shaderc CMake target not found; skipping link for bgfx_gui_service_tests.") + endif() endif() add_test(NAME bgfx_gui_service_tests COMMAND bgfx_gui_service_tests) @@ -388,6 +444,7 @@ add_executable(vulkan_shader_linking_test src/services/impl/pipeline_compiler_service.cpp ) target_include_directories(vulkan_shader_linking_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") +target_include_directories(vulkan_shader_linking_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_tools/shaderc") target_link_libraries(vulkan_shader_linking_test PRIVATE ${SDL_TARGET} ${SDL3CPP_RENDER_STACK_LIBS} @@ -397,7 +454,9 @@ target_link_libraries(vulkan_shader_linking_test PRIVATE rapidjson glm::glm ) -if(TARGET shaderc::shaderc) +if(TARGET shaderc_local) + target_link_libraries(vulkan_shader_linking_test PRIVATE shaderc_local) +elseif(TARGET shaderc::shaderc) target_link_libraries(vulkan_shader_linking_test PRIVATE shaderc::shaderc) elseif(TARGET shaderc::shaderc_combined) target_link_libraries(vulkan_shader_linking_test PRIVATE shaderc::shaderc_combined) diff --git a/src/bgfx_tools/geometryc/geometryc.cpp b/src/bgfx_tools/geometryc/geometryc.cpp index 78890ca..37bdeb1 100644 --- a/src/bgfx_tools/geometryc/geometryc.cpp +++ b/src/bgfx_tools/geometryc/geometryc.cpp @@ -7,7 +7,7 @@ #include #include -#include "../../src/vertexlayout.h" +#include "../vertexlayout.h" #include #include diff --git a/src/bgfx_tools/shaderc/shaderc.h b/src/bgfx_tools/shaderc/shaderc.h index 98f135a..92c2ae4 100644 --- a/src/bgfx_tools/shaderc/shaderc.h +++ b/src/bgfx_tools/shaderc/shaderc.h @@ -23,7 +23,7 @@ namespace bgfx #include #include #include -#include "../../src/vertexlayout.h" +#include "../vertexlayout.h" #include #include diff --git a/src/bgfx_tools/vertexlayout.h b/src/bgfx_tools/vertexlayout.h new file mode 100644 index 0000000..f2e81e7 --- /dev/null +++ b/src/bgfx_tools/vertexlayout.h @@ -0,0 +1,46 @@ +/* + * Copyright 2011-2025 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE + */ + +#ifndef BGFX_VERTEXDECL_H_HEADER_GUARD +#define BGFX_VERTEXDECL_H_HEADER_GUARD + +#include +#include + +namespace bgfx +{ + /// + void initAttribTypeSizeTable(RendererType::Enum _type); + + /// + bool isFloat(AttribType::Enum _type); + + /// Returns attribute name. + const char* getAttribName(Attrib::Enum _attr); + + /// + const char* getAttribNameShort(Attrib::Enum _attr); + + /// + Attrib::Enum idToAttrib(uint16_t id); + + /// + uint16_t attribToId(Attrib::Enum _attr); + + /// + AttribType::Enum idToAttribType(uint16_t id); + + /// + int32_t write(bx::WriterI* _writer, const bgfx::VertexLayout& _layout, bx::Error* _err = NULL); + + /// + int32_t read(bx::ReaderI* _reader, bgfx::VertexLayout& _layout, bx::Error* _err = NULL); + + /// + uint32_t weldVertices(void* _output, const VertexLayout& _layout, const void* _data, uint32_t _num, bool _index32, float _epsilon, bx::AllocatorI* _allocator); + +} // namespace bgfx + +#endif // BGFX_VERTEXDECL_H_HEADER_GUARD diff --git a/src/services/impl/bgfx_graphics_backend.hpp b/src/services/impl/bgfx_graphics_backend.hpp index c3ea58d..c90ff82 100644 --- a/src/services/impl/bgfx_graphics_backend.hpp +++ b/src/services/impl/bgfx_graphics_backend.hpp @@ -4,6 +4,7 @@ #include "../interfaces/i_graphics_backend.hpp" #include "../interfaces/i_logger.hpp" #include "../interfaces/i_platform_service.hpp" +#include "../interfaces/i_pipeline_compiler_service.hpp" #include "../../core/vertex.hpp" #include #include diff --git a/src/services/impl/bgfx_gui_service.cpp b/src/services/impl/bgfx_gui_service.cpp index 2bb9f75..930b0c0 100644 --- a/src/services/impl/bgfx_gui_service.cpp +++ b/src/services/impl/bgfx_gui_service.cpp @@ -62,10 +62,7 @@ out VertexData layout (location = 1) vec2 texcoord; } vd; -layout (binding=0) uniform GuiUniforms -{ - mat4 u_modelViewProj; -}; +uniform mat4 u_modelViewProj; void main() { @@ -86,7 +83,7 @@ in VertexData layout (location = 0) out vec4 out_color; -layout (binding=0) uniform sampler2D s_tex; +uniform sampler2D s_tex; void main() { @@ -114,14 +111,17 @@ struct BgfxGuiService::FreeTypeState { }; BgfxGuiService::BgfxGuiService(std::shared_ptr configService, - std::shared_ptr logger) + std::shared_ptr logger, + std::shared_ptr pipelineCompiler) : configService_(std::move(configService)), logger_(std::move(logger)), + pipelineCompiler_(std::move(pipelineCompiler)), materialxGenerator_(logger_), freeType_(std::make_unique()) { if (logger_) { logger_->Trace("BgfxGuiService", "BgfxGuiService", - "configService=" + std::string(configService_ ? "set" : "null")); + "configService=" + std::string(configService_ ? "set" : "null") + + ", pipelineCompiler=" + std::string(pipelineCompiler_ ? "set" : "null")); } } @@ -1003,7 +1003,7 @@ bgfx::ProgramHandle BgfxGuiService::CreateProgram(const char* vertexSource, bgfx::ShaderHandle BgfxGuiService::CreateShader(const std::string& label, const std::string& source, bool isVertex) const { - BgfxShaderCompiler compiler(logger_); + BgfxShaderCompiler compiler(logger_, pipelineCompiler_); std::vector uniforms; std::vector attributes; diff --git a/src/services/impl/bgfx_gui_service.hpp b/src/services/impl/bgfx_gui_service.hpp index 5ed98de..ba9d489 100644 --- a/src/services/impl/bgfx_gui_service.hpp +++ b/src/services/impl/bgfx_gui_service.hpp @@ -3,6 +3,7 @@ #include "../interfaces/i_config_service.hpp" #include "../interfaces/i_gui_service.hpp" #include "../interfaces/i_logger.hpp" +#include "../interfaces/i_pipeline_compiler_service.hpp" #include "../../di/lifecycle.hpp" #include @@ -25,7 +26,8 @@ class BgfxGuiService final : public IGuiService, public di::IShutdownable { public: BgfxGuiService(std::shared_ptr configService, - std::shared_ptr logger); + std::shared_ptr logger, + std::shared_ptr pipelineCompiler = nullptr); ~BgfxGuiService() override; void PrepareFrame(const std::vector& commands, @@ -146,6 +148,7 @@ private: std::shared_ptr configService_; std::shared_ptr logger_; + std::shared_ptr pipelineCompiler_; MaterialXShaderGenerator materialxGenerator_; std::unique_ptr freeType_; diff --git a/src/services/impl/bgfx_shader_compiler.cpp b/src/services/impl/bgfx_shader_compiler.cpp index 9d3df56..db4e3f1 100644 --- a/src/services/impl/bgfx_shader_compiler.cpp +++ b/src/services/impl/bgfx_shader_compiler.cpp @@ -153,7 +153,8 @@ bgfx::ShaderHandle BgfxShaderCompiler::CompileShader( bool ok = false; if (pipelineCompiler_) { - ok = pipelineCompiler_->Compile(tempInputPath, tempOutputPath, {}); + std::vector args = {"--type", isVertex ? "vertex" : "fragment", "--profile", "spirv"}; + ok = pipelineCompiler_->Compile(tempInputPath, tempOutputPath, args); } else { std::string cmd = "./src/bgfx_tools/shaderc/shaderc -f " + tempInputPath + " -o " + tempOutputPath; if (logger_) logger_->Trace("BgfxShaderCompiler", "CompileShaderCmd", cmd); diff --git a/src/services/impl/pipeline_compiler_service.cpp b/src/services/impl/pipeline_compiler_service.cpp index 4b722ef..767a147 100644 --- a/src/services/impl/pipeline_compiler_service.cpp +++ b/src/services/impl/pipeline_compiler_service.cpp @@ -1,42 +1,87 @@ -#include "../interfaces/i_pipeline_compiler_service.hpp" -#include "../interfaces/i_logger.hpp" +#include "pipeline_compiler_service.hpp" #include #include #include #include #include +#include +#include +#include +#include +#include namespace sdl3cpp::services::impl { -class PipelineCompilerService : public IPipelineCompilerService { -public: - PipelineCompilerService(std::shared_ptr logger) - : logger_(std::move(logger)) {} - bool Compile(const std::string& inputPath, - const std::string& outputPath, - const std::vector& args = {}) override { - std::ostringstream cmd; - cmd << "./src/bgfx_tools/shaderc/shaderc"; - cmd << " -f " << inputPath << " -o " << outputPath; - for (const auto& arg : args) { - cmd << " " << arg; +PipelineCompilerService::PipelineCompilerService(std::shared_ptr logger) + : logger_(std::move(logger)) {} + +bool PipelineCompilerService::Compile(const std::string& inputPath, + const std::string& outputPath, + const std::vector& args) { + // Parse args to determine shader type and profile + bool isVertex = false; + std::string profile = "spirv"; // default + for (size_t i = 0; i < args.size(); ++i) { + if (args[i] == "--type" && i + 1 < args.size()) { + isVertex = (args[i + 1] == "vertex"); + } else if (args[i] == "--profile" && i + 1 < args.size()) { + profile = args[i + 1]; } - logger_->Trace("PipelineCompilerService", "Compile", cmd.str()); - int result = std::system(cmd.str().c_str()); + } + + // Read input file + std::ifstream inputFile(inputPath); + if (!inputFile) { + lastError_ = "Failed to open input file: " + inputPath; + logger_->Error(lastError_.value()); + return false; + } + std::string source((std::istreambuf_iterator(inputFile)), std::istreambuf_iterator()); + + // Write output + std::ofstream outputFile(outputPath, std::ios::binary); + if (!outputFile) { + lastError_ = "Failed to open output file: " + outputPath; + logger_->Error(lastError_.value()); + return false; + } + + if (profile == "glsl") { + // For GLSL, just copy the source + outputFile.write(source.c_str(), source.size()); + } else { + // For SPIR-V, compile using bgfx_tools shaderc_mem + const char* shaderType = isVertex ? "vertex" : "fragment"; + + uint8_t* compiledData = nullptr; + size_t compiledSize = 0; + char* errorMsg = nullptr; + + int result = shaderc_compile_from_memory(source.c_str(), source.size(), shaderType, + &compiledData, &compiledSize, &errorMsg); + if (result != 0) { - lastError_ = "bgfx_tools shaderc failed with code " + std::to_string(result); + std::string error = errorMsg ? errorMsg : "Unknown shader compilation error"; + lastError_ = "Shader compilation failed: " + error; logger_->Error(lastError_.value()); + if (errorMsg) shaderc_free_error(errorMsg); return false; } - lastError_.reset(); - return true; + + // Write the compiled bgfx binary data directly + outputFile.write(reinterpret_cast(compiledData), compiledSize); + + // Clean up + shaderc_free_buffer(compiledData); + if (errorMsg) shaderc_free_error(errorMsg); } - std::optional GetLastError() const override { - return lastError_; - } -private: - std::shared_ptr logger_; - std::optional lastError_; -}; + logger_->Trace("PipelineCompilerService", "Compile", "Successfully compiled " + inputPath + " to " + outputPath); + lastError_.reset(); + return true; +} + +std::optional PipelineCompilerService::GetLastError() const { + return lastError_; +} } // namespace sdl3cpp::services::impl diff --git a/src/services/impl/pipeline_compiler_service.hpp b/src/services/impl/pipeline_compiler_service.hpp new file mode 100644 index 0000000..699ecff --- /dev/null +++ b/src/services/impl/pipeline_compiler_service.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "../interfaces/i_pipeline_compiler_service.hpp" +#include "../interfaces/i_logger.hpp" +#include +#include +#include +#include + +namespace sdl3cpp::services::impl { + +class PipelineCompilerService : public IPipelineCompilerService { +public: + PipelineCompilerService(std::shared_ptr logger); + ~PipelineCompilerService() override = default; + + bool Compile(const std::string& inputPath, + const std::string& outputPath, + const std::vector& args = {}) override; + + std::optional GetLastError() const override; + +private: + std::shared_ptr logger_; + std::optional lastError_; +}; + +} // namespace sdl3cpp::services::impl \ No newline at end of file diff --git a/tests/test_bgfx_gui_service.cpp b/tests/test_bgfx_gui_service.cpp index ac779ee..5e5f86e 100644 --- a/tests/test_bgfx_gui_service.cpp +++ b/tests/test_bgfx_gui_service.cpp @@ -206,7 +206,7 @@ int main() { configService->DisableFreeType(); configService->EnableMaterialXGuiShader(); - sdl3cpp::services::impl::BgfxGuiService service(configService, logger); + sdl3cpp::services::impl::BgfxGuiService service(configService, logger, nullptr); service.PrepareFrame({}, 1, 1); // Noop renderer won't actually create valid shader programs @@ -246,7 +246,7 @@ int main() { configService->DisableFreeType(); // Don't enable MaterialX for GUI - use built-in shaders - sdl3cpp::services::impl::BgfxGuiService service(configService, logger); + sdl3cpp::services::impl::BgfxGuiService service(configService, logger, nullptr); service.PrepareFrame({}, 1, 1); // Noop renderer won't actually create valid shader programs, so we skip program/texture validation diff --git a/tests/test_vulkan_shader_linking.cpp b/tests/test_vulkan_shader_linking.cpp index 9f6a080..44f5c57 100644 --- a/tests/test_vulkan_shader_linking.cpp +++ b/tests/test_vulkan_shader_linking.cpp @@ -3,6 +3,7 @@ #include "services/impl/json_config_service.hpp" #include "services/impl/platform_service.hpp" #include "services/impl/sdl_window_service.hpp" +#include "services/impl/pipeline_compiler_service.hpp" #include "services/interfaces/i_logger.hpp" #include "services/interfaces/gui_types.hpp" #include "events/event_bus.hpp" @@ -119,6 +120,7 @@ int main() { std::cout << "Loading config from: " << configPath << '\n'; auto configService = std::make_shared(logger, configPath, false); auto platformService = std::make_shared(logger); + auto pipelineCompilerService = std::make_shared(logger); // Setup window service auto eventBus = std::make_shared(); @@ -162,7 +164,7 @@ int main() { } // Initialize graphics backend (this will init bgfx with production renderer settings) - sdl3cpp::services::impl::BgfxGraphicsBackend backend(configService, platformService, logger); + sdl3cpp::services::impl::BgfxGraphicsBackend backend(configService, platformService, logger, pipelineCompilerService); std::cout << "Attempting to initialize bgfx...\n"; try { @@ -187,7 +189,7 @@ int main() { } // Now test GUI service shader compilation and linking (same as production) - sdl3cpp::services::impl::BgfxGuiService guiService(configService, logger); + sdl3cpp::services::impl::BgfxGuiService guiService(configService, logger, pipelineCompilerService); // This triggers shader compilation and program linking const uint32_t width = configService->GetWindowWidth();