VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
metalTextureBinder.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Per-pass texture binding deduplication.
5// Extracted from MetalGraphicsDevice for single-responsibility decomposition.
6//
8
9#include <cassert>
10#include "metalTexture.h"
13
14namespace visutwin::canvas
15{
16 // -----------------------------------------------------------------------
17 // Low-level cached bind / clear
18 // -----------------------------------------------------------------------
19
20 void MetalTextureBinder::bindCached(MTL::RenderCommandEncoder* encoder, const int slot, Texture* texture)
21 {
22 assert(slot >= 0 && slot < kMaxTextureSlots);
23
24 // Skip if the same texture is already bound at this slot.
25 if (!_dirty && _boundTextures[slot] == texture) {
26 return;
27 }
28
29 // Update the cache and perform the actual Metal bind.
30 _boundTextures[slot] = texture;
31 if (texture) {
32 if (auto* hw = dynamic_cast<gpu::MetalTexture*>(texture->impl())) {
33 if (hw->raw()) {
34 encoder->setFragmentTexture(hw->raw(), slot);
35 return;
36 }
37 }
38 }
39 encoder->setFragmentTexture(nullptr, slot);
40 }
41
42 void MetalTextureBinder::clearCached(MTL::RenderCommandEncoder* encoder, const int slot)
43 {
44 assert(slot >= 0 && slot < kMaxTextureSlots);
45
46 if (!_dirty && _boundTextures[slot] == nullptr) {
47 return;
48 }
49
50 _boundTextures[slot] = nullptr;
51 encoder->setFragmentTexture(nullptr, slot);
52 }
53
54 // -----------------------------------------------------------------------
55 // Sampler
56 // -----------------------------------------------------------------------
57
58 void MetalTextureBinder::bindSamplerCached(MTL::RenderCommandEncoder* encoder, MTL::SamplerState* sampler)
59 {
60 if (sampler && _boundSampler != sampler) {
61 encoder->setFragmentSamplerState(sampler, 0);
62 _boundSampler = sampler;
63 }
64 }
65
66 // -----------------------------------------------------------------------
67 // Material textures
68 // -----------------------------------------------------------------------
69
70 void MetalTextureBinder::bindMaterialTextures(MTL::RenderCommandEncoder* encoder,
71 const std::vector<TextureSlot>& textureSlots)
72 {
73 // Clear material-owned slots (0,1,3,4,5) not used by this material.
74 constexpr int materialSlots[] = {0, 1, 3, 4, 5, 17};
75 for (const int s : materialSlots) {
76 bool used = false;
77 for (const auto& [slot, tex] : textureSlots) {
78 if (slot == s) { used = true; break; }
79 }
80 if (!used) {
81 clearCached(encoder, s);
82 }
83 }
84
85 // Bind present material textures.
86 for (const auto& [slot, texture] : textureSlots) {
87 bindCached(encoder, slot, texture);
88 }
89 }
90
91 void MetalTextureBinder::clearAllMaterialSlots(MTL::RenderCommandEncoder* encoder)
92 {
93 for (int i = 0; i < 8; ++i) {
94 clearCached(encoder, i);
95 }
96 }
97
98 // -----------------------------------------------------------------------
99 // Scene-global textures
100 // -----------------------------------------------------------------------
101
102 void MetalTextureBinder::bindSceneTextures(MTL::RenderCommandEncoder* encoder,
103 Texture* envAtlas, Texture* shadow, Texture* sceneDepth, Texture* skyboxCubeMap,
104 Texture* reflection, Texture* reflectionDepth, Texture* ssao)
105 {
106 bindCached(encoder, 2, envAtlas);
107 bindCached(encoder, 6, shadow);
108 bindCached(encoder, 7, sceneDepth);
109 bindCached(encoder, 8, skyboxCubeMap);
110 bindCached(encoder, 9, reflection);
111 bindCached(encoder, 10, reflectionDepth);
112 bindCached(encoder, 18, ssao);
113 }
114
115 void MetalTextureBinder::bindQuadTextures(MTL::RenderCommandEncoder* encoder,
116 const std::array<Texture*, 8>& quadBindings)
117 {
118 for (int i = 0; i < 8; ++i) {
119 bindCached(encoder, i, quadBindings[i]);
120 }
121 }
122
123 // -----------------------------------------------------------------------
124 // Local shadow textures
125 // -----------------------------------------------------------------------
126
127 void MetalTextureBinder::bindLocalShadowTextures(MTL::RenderCommandEncoder* encoder,
128 Texture* shadow0, Texture* shadow1)
129 {
130 bindCached(encoder, 11, shadow0);
131 bindCached(encoder, 12, shadow1);
132 }
133
134 void MetalTextureBinder::bindOmniShadowTextures(MTL::RenderCommandEncoder* encoder,
135 Texture* cube0, Texture* cube1)
136 {
137 bindCached(encoder, 15, cube0);
138 bindCached(encoder, 16, cube1);
139 }
140
141 // -----------------------------------------------------------------------
142 // Pass lifecycle
143 // -----------------------------------------------------------------------
144
146 {
147 _boundTextures.fill(nullptr);
148 _dirty = true;
149 _boundSampler = nullptr;
150 }
151}
void bindSamplerCached(MTL::RenderCommandEncoder *encoder, MTL::SamplerState *sampler)
Bind a sampler at slot 0, skipping if already bound.
void bindSceneTextures(MTL::RenderCommandEncoder *encoder, Texture *envAtlas, Texture *shadow, Texture *sceneDepth, Texture *skyboxCubeMap, Texture *reflection=nullptr, Texture *reflectionDepth=nullptr, Texture *ssao=nullptr)
Bind scene-global textures (envAtlas, shadow, sceneDepth, skybox cubemap, reflection,...
void resetPassState()
Reset all cached state. Must be called at the start of each render pass.
void clearCached(MTL::RenderCommandEncoder *encoder, int slot)
Clear (unbind) a texture slot, skipping if already nullptr.
void bindCached(MTL::RenderCommandEncoder *encoder, int slot, Texture *texture)
Bind a texture at the given fragment slot, skipping if already bound.
void clearAllMaterialSlots(MTL::RenderCommandEncoder *encoder)
Clear all 8 texture slots (used when no material is bound).
void bindOmniShadowTextures(MTL::RenderCommandEncoder *encoder, Texture *cube0, Texture *cube1)
Bind omni shadow cubemap depth textures at slots 15 and 16 (point lights, cube).
void bindLocalShadowTextures(MTL::RenderCommandEncoder *encoder, Texture *shadow0, Texture *shadow1)
Bind local shadow depth textures at slots 11 and 12 (spot lights, 2D).
void bindMaterialTextures(MTL::RenderCommandEncoder *encoder, const std::vector< TextureSlot > &textureSlots)
void bindQuadTextures(MTL::RenderCommandEncoder *encoder, const std::array< Texture *, 8 > &quadBindings)
Bind quad render textures for all 8 slots.
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
Definition texture.h:57
gpu::HardwareTexture * impl() const
Definition texture.h:101