From 9ec17a5302ceaf05da882705b8d34146454cbb3d Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sat, 2 May 2026 20:52:51 +0100 Subject: [PATCH] Add Metal shaders for Quake 3 BSP --- .../quake3/shaders/msl/bsp.frag.metal | 46 +++++++++++++++++++ .../quake3/shaders/msl/bsp.vert.metal | 43 +++++++++++++++++ .../rendering/workflow_overlay_fps_step.cpp | 9 ++++ .../rendering/workflow_overlay_fps_step.hpp | 1 + 4 files changed, 99 insertions(+) create mode 100644 gameengine/packages/quake3/shaders/msl/bsp.frag.metal create mode 100644 gameengine/packages/quake3/shaders/msl/bsp.vert.metal diff --git a/gameengine/packages/quake3/shaders/msl/bsp.frag.metal b/gameengine/packages/quake3/shaders/msl/bsp.frag.metal new file mode 100644 index 000000000..b2d416d42 --- /dev/null +++ b/gameengine/packages/quake3/shaders/msl/bsp.frag.metal @@ -0,0 +1,46 @@ +#include +using namespace metal; + +struct PBRUniforms { + float4 u_lightDir; + float4 u_lightColor; + float4 u_ambient; + float4 u_material; + float4 u_flashPos; + float4 u_flashDir; + float4 u_flashColor; +}; + +struct FragmentInput { + float4 position [[position]]; + float2 uv; + float2 lightmapUv; + float3 worldNormal; + float3 worldPos; + float3 cameraPos; +}; + +fragment float4 main0( + FragmentInput in [[stage_in]], + texture2d albedoTex [[texture(0)]], + sampler albedoSampler [[sampler(0)]], + texture2d shadowMap [[texture(1)]], + sampler shadowSampler [[sampler(1)]], + texture2d lightmapTex [[texture(2)]], + sampler lightmapSampler [[sampler(2)]], + constant PBRUniforms& pbr [[buffer(0)]]) +{ + (void)shadowMap; + (void)shadowSampler; + (void)in.worldNormal; + (void)in.worldPos; + (void)in.cameraPos; + + float3 albedo = albedoTex.sample(albedoSampler, in.uv).rgb; + float3 lightmap = lightmapTex.sample(lightmapSampler, in.lightmapUv).rgb; + float overbright = (pbr.u_material.z > 0.0) ? pbr.u_material.z : 2.0; + float3 ambient = pbr.u_ambient.rgb * albedo; + float exposure = (pbr.u_lightColor.a > 0.0) ? pbr.u_lightColor.a : 1.0; + + return float4((albedo * lightmap * overbright + ambient) * exposure, 1.0); +} diff --git a/gameengine/packages/quake3/shaders/msl/bsp.vert.metal b/gameengine/packages/quake3/shaders/msl/bsp.vert.metal new file mode 100644 index 000000000..cfc394505 --- /dev/null +++ b/gameengine/packages/quake3/shaders/msl/bsp.vert.metal @@ -0,0 +1,43 @@ +#include +using namespace metal; + +struct VertexUniforms { + float4x4 u_modelViewProj; + float4x4 u_model; + float4 u_surfaceNormal; + float4 u_uvScale; + float4 u_cameraPos; + float4x4 u_shadowVP; +}; + +struct VertexInput { + float3 position [[attribute(0)]]; + float2 uv [[attribute(1)]]; + float2 lightmapUv [[attribute(2)]]; + float3 normal [[attribute(3)]]; +}; + +struct VertexOutput { + float4 position [[position]]; + float2 uv; + float2 lightmapUv; + float3 worldNormal; + float3 worldPos; + float3 cameraPos; +}; + +vertex VertexOutput main0( + VertexInput in [[stage_in]], + constant VertexUniforms& uniforms [[buffer(0)]]) +{ + VertexOutput out; + out.position = uniforms.u_modelViewProj * float4(in.position, 1.0); + out.uv = in.uv * uniforms.u_uvScale.xy; + out.lightmapUv = in.lightmapUv; + + float4 worldPos = uniforms.u_model * float4(in.position, 1.0); + out.worldPos = worldPos.xyz; + out.worldNormal = (uniforms.u_model * float4(in.normal, 0.0)).xyz; + out.cameraPos = uniforms.u_cameraPos.xyz; + return out; +} diff --git a/gameengine/src/services/impl/workflow/rendering/workflow_overlay_fps_step.cpp b/gameengine/src/services/impl/workflow/rendering/workflow_overlay_fps_step.cpp index 7db9fc7cb..594cf0911 100644 --- a/gameengine/src/services/impl/workflow/rendering/workflow_overlay_fps_step.cpp +++ b/gameengine/src/services/impl/workflow/rendering/workflow_overlay_fps_step.cpp @@ -32,8 +32,17 @@ std::string WorkflowOverlayFpsStep::GetPluginId() const { } void WorkflowOverlayFpsStep::TryInit(SDL_GPUDevice* device, SDL_Window* window) { + if (disabled_) return; device_ = device; + const char* driver = SDL_GetGPUDeviceDriver(device); + const std::string driverName = driver ? driver : ""; + if (driverName != "vulkan") { + if (logger_) logger_->Warn("overlay.fps: SPIR-V overlay only supported on Vulkan, disabled for " + driverName); + disabled_ = true; + return; + } + auto loadSpv = [](const char* path) -> std::vector { std::ifstream f(path, std::ios::binary | std::ios::ate); if (!f.is_open()) return {}; diff --git a/gameengine/src/services/interfaces/workflow/rendering/workflow_overlay_fps_step.hpp b/gameengine/src/services/interfaces/workflow/rendering/workflow_overlay_fps_step.hpp index 414ebbd5b..956469baa 100644 --- a/gameengine/src/services/interfaces/workflow/rendering/workflow_overlay_fps_step.hpp +++ b/gameengine/src/services/interfaces/workflow/rendering/workflow_overlay_fps_step.hpp @@ -28,6 +28,7 @@ private: std::shared_ptr logger_; bool ready_ = false; + bool disabled_ = false; bool vbuf_uploaded_ = false; SDL_GPUGraphicsPipeline* pipeline_ = nullptr; SDL_GPUTexture* tex_ = nullptr;