VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
metalPipelineLayout.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Created by Arnis Lektauers on 14.11.2025.
5//
6#pragma once
7
8#include <Metal/Metal.hpp>
9#include <vector>
10
12{
20
28
34
36 uint32_t groupIndex;
37 std::vector<BindGroupLayoutEntryDesc> entries;
38 };
39
41 public:
42 explicit BindGroupLayout(const BindGroupLayoutDesc& desc): _groupIndex(desc.groupIndex), _entries(desc.entries) {}
43
44 [[nodiscard]] uint32_t groupIndex() const { return _groupIndex; }
45
46 [[nodiscard]] const std::vector<BindGroupLayoutEntryDesc>& entries() const { return _entries; }
47
48 [[nodiscard]] const BindGroupLayoutEntryDesc* findEntry(const uint32_t binding) const {
49 for (auto& e : _entries) {
50 if (e.binding == binding)
51 {
52 return &e;
53 }
54 }
55 return nullptr;
56 }
57 private:
58 uint32_t _groupIndex;
59 std::vector<BindGroupLayoutEntryDesc> _entries;
60 };
61
62 class BindGroup {
63 public:
64 BindGroup(MTL::Device* device, BindGroupLayout* layout, MTL::ArgumentEncoder* encoder):
65 _device(device), _layout(layout), _encoder(encoder)
66 {
67 assert(_device && "Device must not be null");
68 assert(_layout && "Layout must not be null");
69 assert(_encoder && "Argument encoder must not be null");
70
71 NS::UInteger length = _encoder->encodedLength();
72
73 _argBuffer= _device->newBuffer(length, MTL::ResourceStorageModeManaged);
74 assert(_argBuffer && "Failed to allocate argument buffer");
75
76 _encoder->setArgumentBuffer(_argBuffer, 0);
77 }
78
80 {
81 if (_argBuffer)
82 {
83 _argBuffer->release();
84 }
85 if (_encoder)
86 {
87 _encoder->release();
88 }
89 }
90
91 [[nodiscard]] BindGroupLayout* layout() const { return _layout; }
92
93 [[nodiscard]] MTL::Buffer* argBuffer() const { return _argBuffer; }
94
95 void setBuffer(const uint32_t binding, const MTL::Buffer* buffer, const NS::UInteger offset = 0) const
96 {
97 if (auto* entry = _layout->findEntry(binding); !entry ||
98 (entry->type != BindingType::UniformBuffer && entry->type != BindingType::StorageBuffer))
99 {
100 return;
101 }
102 _encoder->setBuffer(buffer, offset, binding);
103 }
104
105 void setSampler(const uint32_t binding, const MTL::SamplerState* sampler) const
106 {
107 if (auto* entry = _layout->findEntry(binding); !entry || entry->type != BindingType::Sampler)
108 {
109 return;
110 }
111 _encoder->setSamplerState(sampler, binding);
112 }
113
114 void setTexture(const uint32_t binding, const MTL::Texture* texture) const
115 {
116 if (auto* entry = _layout->findEntry(binding); !entry ||
117 (entry->type != BindingType::SampledTexture && entry->type != BindingType::StorageTexture))
118 {
119 return;
120 }
121 _encoder->setTexture(texture, binding);
122 }
123
124 // Call this before encoding draws if you use Managed storage
125 void didModifyRange() const
126 {
127 _argBuffer->didModifyRange(NS::Range::Make(0, _argBuffer->length()));
128 }
129
130 private:
131 MTL::Device* _device = nil;
132 BindGroupLayout* _layout = nullptr;
133 MTL::ArgumentEncoder* _encoder = nil;
134 MTL::Buffer* _argBuffer = nil;
135 };
136
138 std::vector<BindGroupLayout*> bindGroupLayouts;
139 };
140
142 {
143 public:
144 explicit PipelineLayout(const PipelineLayoutDesc& desc) : _bindGroupLayouts(desc.bindGroupLayouts) {}
145
146 [[nodiscard]] BindGroupLayout* getBindGroupLayout(const uint32_t index) const {
147 if (index >= _bindGroupLayouts.size())
148 {
149 return nullptr;
150 }
151 return _bindGroupLayouts[index];
152 }
153
154 void setDebugLabel(int layoutIt, const std::string& label) {}
155 private:
156 std::vector<BindGroupLayout*> _bindGroupLayouts;
157 };
158}
void setBuffer(const uint32_t binding, const MTL::Buffer *buffer, const NS::UInteger offset=0) const
void setSampler(const uint32_t binding, const MTL::SamplerState *sampler) const
BindGroup(MTL::Device *device, BindGroupLayout *layout, MTL::ArgumentEncoder *encoder)
void setTexture(const uint32_t binding, const MTL::Texture *texture) const
const BindGroupLayoutEntryDesc * findEntry(const uint32_t binding) const
BindGroupLayout(const BindGroupLayoutDesc &desc)
const std::vector< BindGroupLayoutEntryDesc > & entries() const
BindGroupLayout * getBindGroupLayout(const uint32_t index) const
void setDebugLabel(int layoutIt, const std::string &label)
PipelineLayout(const PipelineLayoutDesc &desc)
std::vector< BindGroupLayoutEntryDesc > entries
ShaderStageFlags visibility
uint32_t binding
BindingType type
std::vector< BindGroupLayout * > bindGroupLayouts