From 36d8a40fcc91bd83efee7e9dbf48de2f7dd1648e Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Wed, 7 Jan 2026 10:27:51 +0000 Subject: [PATCH] feat(shader): Enhance shader creation for OpenGL and Vulkan by adding SPIRV wrapping and improved error logging --- CMakeUserPresets.json | 1 - scripts/dev_commands.py | 0 src/services/impl/bgfx_graphics_backend.cpp | 69 +++++++++++++++++---- src/services/impl/bgfx_gui_service.cpp | 59 +++++++++++++++--- 4 files changed, 105 insertions(+), 24 deletions(-) mode change 100644 => 100755 scripts/dev_commands.py diff --git a/CMakeUserPresets.json b/CMakeUserPresets.json index b1b4a07..2103e2b 100644 --- a/CMakeUserPresets.json +++ b/CMakeUserPresets.json @@ -18,7 +18,6 @@ } ], "include": [ - "build/build/Release/generators/CMakePresets.json", "build-ninja/build/Release/generators/CMakePresets.json" ] } \ No newline at end of file diff --git a/scripts/dev_commands.py b/scripts/dev_commands.py old mode 100644 new mode 100755 diff --git a/src/services/impl/bgfx_graphics_backend.cpp b/src/services/impl/bgfx_graphics_backend.cpp index 7b0fd08..dc0baa4 100644 --- a/src/services/impl/bgfx_graphics_backend.cpp +++ b/src/services/impl/bgfx_graphics_backend.cpp @@ -668,36 +668,79 @@ std::vector BgfxGraphicsBackend::ReadShaderSource(const std::string& pa bgfx::ShaderHandle BgfxGraphicsBackend::CreateShader(const std::string& label, const std::string& source, bool isVertex) const { + const bgfx::RendererType::Enum rendererType = bgfx::getRendererType(); + + if (logger_) { + logger_->Trace("BgfxGraphicsBackend", "CreateShader", + "label=" + label + + ", renderer=" + RendererTypeName(rendererType) + + ", sourceLength=" + std::to_string(source.size())); + } + + // For OpenGL, bgfx expects raw GLSL source (no wrapper needed) + // For Vulkan/Metal/DX, bgfx expects SPIRV wrapped in binary format + const bool isOpenGL = (rendererType == bgfx::RendererType::OpenGL || + rendererType == bgfx::RendererType::OpenGLES); + + if (isOpenGL) { + // For OpenGL: Just copy GLSL source directly + const uint32_t sourceSize = static_cast(source.size()); + const bgfx::Memory* mem = bgfx::copy(source.c_str(), sourceSize + 1); // +1 for null terminator + + bgfx::ShaderHandle handle = bgfx::createShader(mem); + if (!bgfx::isValid(handle) && logger_) { + logger_->Error("bgfx::createShader failed for " + label + + " (renderer=" + RendererTypeName(rendererType) + ")"); + } + return handle; + } + + // For Vulkan/Metal/DX: Compile to SPIRV and wrap in bgfx binary format shaderc::Compiler compiler; shaderc::CompileOptions options; options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_1); options.SetAutoBindUniforms(true); options.SetAutoMapLocations(true); - if (logger_) { - logger_->Trace("BgfxGraphicsBackend", "CreateShader", - "label=" + label + - ", renderer=" + RendererTypeName(bgfx::getRendererType()) + - ", sourceLength=" + std::to_string(source.size())); - } - shaderc_shader_kind kind = isVertex ? shaderc_vertex_shader : shaderc_fragment_shader; - auto result = compiler.CompileGlslToSpv(source, kind, label.c_str(), options); + if (result.GetCompilationStatus() != shaderc_compilation_status_success) { std::string error = result.GetErrorMessage(); if (logger_) { - logger_->Error("Bgfx shader compilation failed: " + label + "\n" + error); + logger_->Error("Shader GLSL->SPIRV compilation failed: " + label + "\n" + error); } - throw std::runtime_error("Bgfx shader compilation failed: " + label + "\n" + error); + throw std::runtime_error("Shader GLSL->SPIRV compilation failed: " + label + "\n" + error); } std::vector spirv(result.cbegin(), result.cend()); - const bgfx::Memory* mem = bgfx::copy(spirv.data(), - static_cast(spirv.size() * sizeof(uint32_t))); + + // Wrap SPIRV with bgfx binary format: magic + hashes + uniformCount + spirvSize + spirv + nul + constexpr uint8_t kBgfxShaderVersion = 11; + constexpr uint32_t kMagicVSH = ('V') | ('S' << 8) | ('H' << 16) | (kBgfxShaderVersion << 24); + constexpr uint32_t kMagicFSH = ('F') | ('S' << 8) | ('H' << 16) | (kBgfxShaderVersion << 24); + const uint32_t magic = isVertex ? kMagicVSH : kMagicFSH; + const uint32_t inputHash = static_cast(std::hash{}(source)); + const uint32_t spirvSize = static_cast(spirv.size() * sizeof(uint32_t)); + const uint16_t uniformCount = 0; + const uint32_t totalSize = 4 + 4 + 4 + 2 + 4 + spirvSize + 1; + + const bgfx::Memory* mem = bgfx::alloc(totalSize); + uint8_t* data = mem->data; + uint32_t offset = 0; + + std::memcpy(data + offset, &magic, 4); offset += 4; + std::memcpy(data + offset, &inputHash, 4); offset += 4; + std::memcpy(data + offset, &inputHash, 4); offset += 4; + std::memcpy(data + offset, &uniformCount, 2); offset += 2; + std::memcpy(data + offset, &spirvSize, 4); offset += 4; + std::memcpy(data + offset, spirv.data(), spirvSize); offset += spirvSize; + data[offset] = 0; + bgfx::ShaderHandle handle = bgfx::createShader(mem); if (!bgfx::isValid(handle) && logger_) { - logger_->Error("BgfxGraphicsBackend::CreateShader: Failed to create shader handle for " + label); + logger_->Error("bgfx::createShader failed for " + label + + " (renderer=" + RendererTypeName(rendererType) + ", spirvSize=" + std::to_string(spirv.size()) + " words)"); } return handle; } diff --git a/src/services/impl/bgfx_gui_service.cpp b/src/services/impl/bgfx_gui_service.cpp index bfae446..a299450 100644 --- a/src/services/impl/bgfx_gui_service.cpp +++ b/src/services/impl/bgfx_gui_service.cpp @@ -855,19 +855,37 @@ bgfx::ProgramHandle BgfxGuiService::CreateProgram(const char* vertexSource, bgfx::ShaderHandle BgfxGuiService::CreateShader(const std::string& label, const std::string& source, bool isVertex) const { + const bgfx::RendererType::Enum rendererType = bgfx::getRendererType(); + + if (logger_) { + logger_->Trace("BgfxGuiService", "CreateShader", + "label=" + label + + ", renderer=" + std::string(RendererTypeName(rendererType)) + + ", sourceLength=" + std::to_string(source.size())); + } + + const bool isOpenGL = (rendererType == bgfx::RendererType::OpenGL || + rendererType == bgfx::RendererType::OpenGLES); + + if (isOpenGL) { + // For OpenGL: Just copy GLSL source directly + const uint32_t sourceSize = static_cast(source.size()); + const bgfx::Memory* mem = bgfx::copy(source.c_str(), sourceSize + 1); + + bgfx::ShaderHandle handle = bgfx::createShader(mem); + if (!bgfx::isValid(handle) && logger_) { + logger_->Error("BgfxGuiService: Failed to create shader handle for " + label); + } + return handle; + } + + // For Vulkan/Metal/DX: Compile to SPIRV and wrap in bgfx binary format shaderc::Compiler compiler; shaderc::CompileOptions options; options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_1); options.SetAutoBindUniforms(true); options.SetAutoMapLocations(true); - if (logger_) { - logger_->Trace("BgfxGuiService", "CreateShader", - "label=" + label + - ", renderer=" + std::string(RendererTypeName(bgfx::getRendererType())) + - ", sourceLength=" + std::to_string(source.size())); - } - shaderc_shader_kind kind = isVertex ? shaderc_vertex_shader : shaderc_fragment_shader; auto result = compiler.CompileGlslToSpv(source, kind, label.c_str(), options); if (result.GetCompilationStatus() != shaderc_compilation_status_success) { @@ -878,11 +896,32 @@ bgfx::ShaderHandle BgfxGuiService::CreateShader(const std::string& label, } std::vector spirv(result.cbegin(), result.cend()); - const bgfx::Memory* mem = bgfx::copy(spirv.data(), - static_cast(spirv.size() * sizeof(uint32_t))); + + // Wrap SPIRV with bgfx binary format + constexpr uint8_t kBgfxShaderVersion = 11; + constexpr uint32_t kMagicVSH = ('V') | ('S' << 8) | ('H' << 16) | (kBgfxShaderVersion << 24); + constexpr uint32_t kMagicFSH = ('F') | ('S' << 8) | ('H' << 16) | (kBgfxShaderVersion << 24); + const uint32_t magic = isVertex ? kMagicVSH : kMagicFSH; + const uint32_t inputHash = static_cast(std::hash{}(source)); + const uint32_t spirvSize = static_cast(spirv.size() * sizeof(uint32_t)); + const uint16_t uniformCount = 0; + const uint32_t totalSize = 4 + 4 + 4 + 2 + 4 + spirvSize + 1; + + const bgfx::Memory* mem = bgfx::alloc(totalSize); + uint8_t* data = mem->data; + uint32_t offset = 0; + + std::memcpy(data + offset, &magic, 4); offset += 4; + std::memcpy(data + offset, &inputHash, 4); offset += 4; + std::memcpy(data + offset, &inputHash, 4); offset += 4; + std::memcpy(data + offset, &uniformCount, 2); offset += 2; + std::memcpy(data + offset, &spirvSize, 4); offset += 4; + std::memcpy(data + offset, spirv.data(), spirvSize); offset += spirvSize; + data[offset] = 0; + bgfx::ShaderHandle handle = bgfx::createShader(mem); if (!bgfx::isValid(handle) && logger_) { - logger_->Error("BgfxGuiService::CreateShader: Failed to create shader handle for " + label); + logger_->Error("BgfxGuiService: Failed to create shader handle for " + label); } return handle; }