VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
metalUniformBinder.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Metal-specific uniform packing, ring-buffer allocation, and per-pass deduplication.
5// Extracted from MetalGraphicsDevice for single-responsibility decomposition.
6//
7#pragma once
8
9#include <cstdint>
10#include <simd/simd.h>
11#include <vector>
12#include <Metal/Metal.hpp>
13
15
16namespace visutwin::canvas
17{
18 class Color;
19 class Material;
20 class Matrix4;
22 class Texture;
23 class Vector3;
24 struct FogParams;
25 struct GpuLightData;
26 struct MaterialUniforms;
27 struct ShadowParams;
28
35 {
36 public:
37 // Use base class GpuLightUniform and LightingUniforms types.
40
41 // ---------------------------------------------------------------
42 // Per-frame uniform setters (called by renderer before draw loop)
43 // ---------------------------------------------------------------
44
46 void setTransformUniforms(MTL::RenderCommandEncoder* encoder,
47 MetalUniformRingBuffer* transformRing,
48 const Matrix4& viewProjection, const Matrix4& model);
49
51 void setLightingUniforms(const Color& ambientColor, const std::vector<GpuLightData>& lights,
52 const Vector3& cameraPosition, bool enableNormalMaps, float exposure,
53 const FogParams& fogParams, const ShadowParams& shadowParams,
54 int toneMapping = 0);
55
57 void setEnvironmentUniforms(Texture* envAtlas, float skyboxIntensity, float skyboxMip,
58 const Vector3& skyDomeCenter, bool isDome, Texture* skyboxCubeMap);
59
61 void setAtmosphereUniforms(const void* data, size_t size);
62
64 void setScreenResolution(float width, float height)
65 {
66 if (width > 0.0f && height > 0.0f) {
67 _lightingUniforms.screenInvResolution[0] = 1.0f / width;
68 _lightingUniforms.screenInvResolution[1] = 1.0f / height;
69 _lightingUniforms.screenInvResolution[2] = width;
70 _lightingUniforms.screenInvResolution[3] = height;
71 }
72 }
73
75 void setReflectionBlurParams(float intensity, float blurAmount, float fadeStrength, float angleFade,
76 float fadeR, float fadeG, float fadeB)
77 {
78 _lightingUniforms.reflectionParams[0] = intensity;
79 _lightingUniforms.reflectionParams[1] = blurAmount;
80 _lightingUniforms.reflectionParams[2] = fadeStrength;
81 _lightingUniforms.reflectionParams[3] = angleFade;
82 _lightingUniforms.reflectionFadeColor[0] = fadeR;
83 _lightingUniforms.reflectionFadeColor[1] = fadeG;
84 _lightingUniforms.reflectionFadeColor[2] = fadeB;
85 _lightingUniforms.reflectionFadeColor[3] = 0.0f;
86 }
87
89 void setReflectionDepthParams(float planeDistance, float heightRange)
90 {
91 _lightingUniforms.reflectionDepthParams[0] = planeDistance;
92 _lightingUniforms.reflectionDepthParams[1] = (heightRange > 0.001f) ? heightRange : 0.001f;
93 _lightingUniforms.reflectionDepthParams[2] = 0.0f;
94 _lightingUniforms.reflectionDepthParams[3] = 0.0f;
95 }
96
98 void setClusterParams(const float* boundsMin, const float* boundsRange,
99 const float* cellsCountByBoundsSize,
100 int cellsX, int cellsY, int cellsZ, int maxLightsPerCell,
101 int numClusteredLights)
102 {
103 _lightingUniforms.clusterBoundsMin[0] = boundsMin[0];
104 _lightingUniforms.clusterBoundsMin[1] = boundsMin[1];
105 _lightingUniforms.clusterBoundsMin[2] = boundsMin[2];
106 _lightingUniforms.clusterBoundsMin[3] = 0.0f;
107
108 _lightingUniforms.clusterBoundsRange[0] = boundsRange[0];
109 _lightingUniforms.clusterBoundsRange[1] = boundsRange[1];
110 _lightingUniforms.clusterBoundsRange[2] = boundsRange[2];
111 _lightingUniforms.clusterBoundsRange[3] = 0.0f;
112
113 _lightingUniforms.clusterCellsCountByBoundsSize[0] = cellsCountByBoundsSize[0];
114 _lightingUniforms.clusterCellsCountByBoundsSize[1] = cellsCountByBoundsSize[1];
115 _lightingUniforms.clusterCellsCountByBoundsSize[2] = cellsCountByBoundsSize[2];
116 _lightingUniforms.clusterCellsCountByBoundsSize[3] = 0.0f;
117
118 _lightingUniforms.clusterParams[0] = static_cast<uint32_t>(cellsX);
119 _lightingUniforms.clusterParams[1] = static_cast<uint32_t>(cellsY);
120 _lightingUniforms.clusterParams[2] = static_cast<uint32_t>(cellsZ);
121 _lightingUniforms.clusterParams[3] = static_cast<uint32_t>(maxLightsPerCell);
122
123 _lightingUniforms.clusterParams2[0] = static_cast<uint32_t>(numClusteredLights);
124 _lightingUniforms.clusterParams2[1] = 0u;
125 _lightingUniforms.clusterParams2[2] = 0u;
126 _lightingUniforms.clusterParams2[3] = 0u;
127 }
128
129 // ---------------------------------------------------------------
130 // Per-draw uniform submission with deduplication (called from draw())
131 // ---------------------------------------------------------------
132
133 void submitPerDrawUniforms(MTL::RenderCommandEncoder* encoder,
134 MetalUniformRingBuffer* uniformRing,
135 const Material* currentMaterial,
136 const void* uniformData,
137 size_t uniformSize,
138 bool hdrPass);
139
140 // ---------------------------------------------------------------
141 // UniformBinder interface
142 // ---------------------------------------------------------------
143
144 void resetPassState() override;
145
146 [[nodiscard]] bool isMaterialChanged(const Material* mat) const override
147 {
148 return !_materialBoundThisPass || mat != _lastBoundMaterial;
149 }
150
151 [[nodiscard]] Texture* envAtlasTexture() const override { return _envAtlasTexture; }
152 [[nodiscard]] Texture* skyboxCubeMapTexture() const override { return _skyboxCubeMapTexture; }
153 [[nodiscard]] Texture* shadowTexture() const override { return _shadowTexture; }
154 [[nodiscard]] Texture* localShadowTexture0() const override { return _localShadowTexture0; }
155 [[nodiscard]] Texture* localShadowTexture1() const override { return _localShadowTexture1; }
156 [[nodiscard]] Texture* omniShadowCube0() const override { return _omniShadowCube0; }
157 [[nodiscard]] Texture* omniShadowCube1() const override { return _omniShadowCube1; }
158
159 private:
160 // Scene-global texture pointers set by setLightingUniforms / setEnvironmentUniforms,
161 // read by MetalGraphicsDevice::draw() for texture binding.
162 Texture* _envAtlasTexture = nullptr;
163 Texture* _skyboxCubeMapTexture = nullptr;
164 Texture* _shadowTexture = nullptr;
165 Texture* _localShadowTexture0 = nullptr;
166 Texture* _localShadowTexture1 = nullptr;
167 Texture* _omniShadowCube0 = nullptr;
168 Texture* _omniShadowCube1 = nullptr;
169
170 // SceneData (VP matrix) dedup.
171 bool _sceneDataBoundThisPass = false;
172 simd::float4x4 _cachedSceneVP{};
173
174 // Lighting dedup: FNV-1a hash of LightingUniforms.
175 bool _lightingBoundThisPass = false;
176 uint32_t _lastLightingHash = 0;
177 size_t _lastLightingOffset = 0;
178
179 // Material dedup: pointer comparison.
180 bool _materialBoundThisPass = false;
181 const Material* _lastBoundMaterial = nullptr;
182 size_t _lastMaterialOffset = 0;
183 };
184}
Base class for GPU materials — owns uniform data, texture bindings, blend/depth state,...
Definition material.h:143
void setEnvironmentUniforms(Texture *envAtlas, float skyboxIntensity, float skyboxMip, const Vector3 &skyDomeCenter, bool isDome, Texture *skyboxCubeMap)
Pack environment uniforms (skybox, env atlas) into LightingUniforms.
void setScreenResolution(float width, float height)
Pack screen resolution for planar reflection screen-space UV.
Texture * localShadowTexture1() const override
Texture * envAtlasTexture() const override
void setClusterParams(const float *boundsMin, const float *boundsRange, const float *cellsCountByBoundsSize, int cellsX, int cellsY, int cellsZ, int maxLightsPerCell, int numClusteredLights)
Pack clustered lighting grid parameters into LightingUniforms.
void setTransformUniforms(MTL::RenderCommandEncoder *encoder, MetalUniformRingBuffer *transformRing, const Matrix4 &viewProjection, const Matrix4 &model)
Pack transform uniforms (SceneData VP + ModelData per draw).
void setReflectionDepthParams(float planeDistance, float heightRange)
Pack planar reflection depth pass parameters.
Texture * skyboxCubeMapTexture() const override
Texture * omniShadowCube1() const override
void setLightingUniforms(const Color &ambientColor, const std::vector< GpuLightData > &lights, const Vector3 &cameraPosition, bool enableNormalMaps, float exposure, const FogParams &fogParams, const ShadowParams &shadowParams, int toneMapping=0)
Pack lighting uniforms into the internal LightingUniforms struct.
void submitPerDrawUniforms(MTL::RenderCommandEncoder *encoder, MetalUniformRingBuffer *uniformRing, const Material *currentMaterial, const void *uniformData, size_t uniformSize, bool hdrPass)
Texture * localShadowTexture0() const override
void setReflectionBlurParams(float intensity, float blurAmount, float fadeStrength, float angleFade, float fadeR, float fadeG, float fadeB)
Pack blurred planar reflection parameters.
void setAtmosphereUniforms(const void *data, size_t size)
Pack atmosphere uniforms (Nishita scattering) into AtmosphereUniforms.
Texture * shadowTexture() const override
Texture * omniShadowCube0() const override
bool isMaterialChanged(const Material *mat) const override
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
Definition texture.h:57
RGBA color with floating-point components in [0, 1].
Definition color.h:18
Per-light GPU data uploaded to the lighting uniform buffer.
4x4 column-major transformation matrix with SIMD acceleration.
Definition matrix4.h:31
3D vector for positions, directions, and normals with multi-backend SIMD acceleration.
Definition vector3.h:29