Blender V4.5
mtl_pso_descriptor_state.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#pragma once
9
10#include "BLI_math_bits.h"
11#include "GPU_batch.hh"
12#include "GPU_vertex_format.hh"
13
14#include <Metal/Metal.h>
15
16#include "BLI_vector.hh"
17
19#include "gpu_shader_private.hh"
20
21namespace blender::gpu {
22
28 MTLVertexFormat format;
29 int offset;
32
34 {
35 return (format == other.format) && (offset == other.offset) &&
36 (buffer_index == other.buffer_index) &&
38 }
39
40 uint64_t hash() const
41 {
42 return uint64_t((uint64_t(this->format) ^ (this->offset << 4) ^ (this->buffer_index << 8) ^
43 (this->format_conversion_mode << 12)));
44 }
45
46 void reset()
47 {
48 format = MTLVertexFormatInvalid;
49 offset = 0;
50 buffer_index = 0;
52 }
53};
54
56 MTLVertexStepFunction step_function;
58 int stride;
59
61 {
62 return (step_function == other.step_function) && (step_rate == other.step_rate) &&
63 (stride == other.stride);
64 }
65
66 uint64_t hash() const
67 {
68 return uint64_t(uint64_t(this->step_function) ^ (this->step_rate << 4) ^ (this->stride << 8));
69 }
70
71 void reset()
72 {
73 step_function = MTLVertexStepFunctionPerVertex;
74 step_rate = 1;
75 stride = 0;
76 }
77};
78
79/* SSBO attribute state caching. */
81
83 int vbo_id;
88
89 MTLSSBOAttribute() = default;
91 int attribute_ind, int vertexbuffer_ind, int offset, int stride, int format, bool instanced)
92 : mtl_attribute_index(attribute_ind),
93 vbo_id(vertexbuffer_ind),
94 attribute_offset(offset),
95 per_vertex_stride(stride),
97 is_instance(instanced)
98 {
99 }
100
101 bool operator==(const MTLSSBOAttribute &other) const
102 {
103 return (mtl_attribute_index == other.mtl_attribute_index && vbo_id == other.vbo_id &&
107 }
108
109 void reset()
110 {
112 vbo_id = 0;
116 is_instance = false;
117 }
118};
119
121
122 /* Core Vertex Attributes. */
129 MTLPrimitiveTopologyClass prim_topology_class;
130
131 bool operator==(const MTLVertexDescriptor &other) const
132 {
133 if ((this->max_attribute_value != other.max_attribute_value) ||
134 (this->total_attributes != other.total_attributes) ||
135 (this->num_vert_buffers != other.num_vert_buffers))
136 {
137 return false;
138 }
139 if (this->prim_topology_class != other.prim_topology_class) {
140 return false;
141 };
142
143 for (const int a : IndexRange(this->max_attribute_value + 1)) {
144 if (!(this->attributes[a] == other.attributes[a])) {
145 return false;
146 }
147 }
148
149 for (const int b : IndexRange(this->num_vert_buffers)) {
150 if (!(this->buffer_layouts[b] == other.buffer_layouts[b])) {
151 return false;
152 }
153 }
154
155 /* NOTE: No need to compare SSBO attributes, as these will match attribute bindings for the
156 * given shader. These are simply extra pre-resolved properties we want to include in the
157 * cache. */
158 return true;
159 }
160
162 {
163 uint64_t hash = (uint64_t)(this->max_attribute_value ^ this->num_vert_buffers);
164 for (const int a : IndexRange(this->max_attribute_value + 1)) {
165 hash ^= this->attributes[a].hash() << a;
166 }
167
168 for (const int b : IndexRange(this->num_vert_buffers)) {
169 hash ^= this->buffer_layouts[b].hash() << (b + 10);
170 }
171 return hash;
172 }
173};
174
177
183
185 {
186 return values == other.values;
187 }
188
190 {
191 uint64_t hash = values.size();
192 uint seed = 0xFF;
193 for (const shader::SpecializationConstant::Value &value : values) {
194 seed = seed << 1;
195 hash ^= seed ^ value.u;
196 }
197 return hash;
198 }
199};
200
201/* Metal Render Pipeline State Descriptor -- All unique information which feeds PSO creation. */
203 /* This state descriptor will contain ALL parameters which generate a unique PSO.
204 * We will then use this state-object to efficiently look-up or create a
205 * new PSO for the current shader.
206 *
207 * Unlike the 'MTLContextGlobalShaderPipelineState', this struct contains a subset of
208 * parameters used to distinguish between unique PSOs. This struct is hash-able and only
209 * contains those parameters which are required by PSO generation. Non-unique state such as
210 * bound resources is not tracked here, as it does not require a unique PSO permutation if
211 * changed. */
212
213 /* Input Vertex Descriptor. */
215
216 /* Render Target attachment state.
217 * Assign to #MTLPixelFormatInvalid if not used. */
222
223 /* Render Pipeline State affecting PSO creation. */
225 MTLBlendOperation alpha_blend_op;
226 MTLBlendOperation rgb_blend_op;
228 MTLBlendFactor dest_rgb_blend_factor;
230 MTLBlendFactor src_rgb_blend_factor;
231
232 /* Global color write mask as this cannot be specified per attachment. */
233 MTLColorWriteMask color_write_mask;
234
235 /* Clip distance enablement. */
237
238 /* Point size required by point primitives. */
239 float point_size = 0.0f;
240
241 /* Specialization constants map. */
243
244 /* Comparison Operator for caching. */
246 {
247 if (!(vertex_descriptor == other.vertex_descriptor)) {
248 return false;
249 }
250
252 return false;
253 }
254
260 (rgb_blend_op != other.rgb_blend_op) ||
265 (vertex_descriptor.prim_topology_class != other.vertex_descriptor.prim_topology_class) ||
266 (point_size != other.point_size))
267 {
268 return false;
269 }
270
271 /* Attachments can be skipped, so num_color_attachments will not define the range. */
272 for (const int c : IndexRange(GPU_FB_MAX_COLOR_ATTACHMENT)) {
274 return false;
275 }
276 }
277
279 return false;
280 }
281
282 return true;
283 }
284
286 {
287 /* NOTE(Metal): Current setup aims to minimize overlap of parameters
288 * which are more likely to be different, to ensure earlier hash
289 * differences without having to fallback to comparisons.
290 * Though this could likely be further improved to remove
291 * has collisions. */
292
293 uint64_t hash = this->vertex_descriptor.hash();
294 hash ^= uint64_t(this->num_color_attachments) << 16; /* up to 6 (3 bits). */
295 hash ^= uint64_t(this->depth_attachment_format) << 18; /* up to 555 (9 bits). */
296 hash ^= uint64_t(this->stencil_attachment_format) << 20; /* up to 555 (9 bits). */
297 hash ^= uint64_t(
298 *((uint64_t *)&this->vertex_descriptor.prim_topology_class)); /* Up to 3 (2 bits). */
299
300 /* Only include elements in Hash if they are needed - avoids variable null assignments
301 * influencing hash. */
302 if (this->num_color_attachments > 0) {
303 hash ^= uint64_t(this->color_write_mask) << 22; /* 4 bit bit-mask. */
304 hash ^= uint64_t(this->alpha_blend_op) << 26; /* Up to 4 (3 bits). */
305 hash ^= uint64_t(this->rgb_blend_op) << 29; /* Up to 4 (3 bits). */
306 hash ^= uint64_t(this->dest_alpha_blend_factor) << 32; /* Up to 18 (5 bits). */
307 hash ^= uint64_t(this->dest_rgb_blend_factor) << 37; /* Up to 18 (5 bits). */
308 hash ^= uint64_t(this->src_alpha_blend_factor) << 42; /* Up to 18 (5 bits). */
309 hash ^= uint64_t(this->src_rgb_blend_factor) << 47; /* Up to 18 (5 bits). */
310
312 hash ^= uint64_t(this->color_attachment_format[c]) << (c + 52); /* Up to 555 (9 bits). */
313 }
314 }
315
316 hash |= uint64_t((this->blending_enabled && (this->num_color_attachments > 0)) ? 1 : 0) << 62;
317 hash ^= uint64_t(float_as_uint(this->point_size));
318
319 /* Clipping plane enablement. */
321
322 /* Specialization constants. We can treat the raw bytes as uint. */
323 hash ^= specialization_state.hash();
324
325 return hash;
326 }
327
328 /* Reset the Vertex Descriptor to default. */
330 {
331 vertex_descriptor.total_attributes = 0;
332 vertex_descriptor.max_attribute_value = 0;
333 vertex_descriptor.num_vert_buffers = 0;
334 vertex_descriptor.prim_topology_class = MTLPrimitiveTopologyClassUnspecified;
335 for (int i = 0; i < GPU_VERT_ATTR_MAX_LEN; i++) {
336 vertex_descriptor.attributes[i].reset();
337 }
338 }
339};
340
341/* Metal Compute Pipeline State Descriptor containing all unique information which feeds PSO
342 * creation. */
344
345 /* Specialization constants map. */
347
353
354 /* Comparison Operator for caching. */
356 {
358 }
359
361 {
362 return specialization_state.hash();
363 }
364};
365
366} // namespace blender::gpu
MINLINE unsigned int float_as_uint(float f)
unsigned char uchar
unsigned int uint
static constexpr int GPU_BATCH_VBO_MAX_LEN
Definition GPU_batch.hh:31
static constexpr int GPU_BATCH_INST_VBO_MAX_LEN
Definition GPU_batch.hh:32
static constexpr int GPU_VERT_ATTR_MAX_LEN
GPUVertFetchMode
@ GPU_FETCH_FLOAT
unsigned long long int uint64_t
static unsigned long seed
Definition btSoftBody.h:39
#define GPU_FB_MAX_COLOR_ATTACHMENT
#define this
format
bool operator==(const MTLComputePipelineStateDescriptor &other) const
MTLComputePipelineStateDescriptor(Vector< shader::SpecializationConstant::Value > values)
MTLPixelFormat color_attachment_format[GPU_FB_MAX_COLOR_ATTACHMENT]
bool operator==(const MTLRenderPipelineStateDescriptor &other) const
MTLSSBOAttribute(int attribute_ind, int vertexbuffer_ind, int offset, int stride, int format, bool instanced)
bool operator==(const MTLSSBOAttribute &other) const
bool operator==(const MTLVertexAttributeDescriptorPSO &other) const
bool operator==(const MTLVertexBufferLayoutDescriptorPSO &other) const
MTLVertexBufferLayoutDescriptorPSO buffer_layouts[GPU_BATCH_VBO_MAX_LEN+GPU_BATCH_INST_VBO_MAX_LEN]
MTLVertexAttributeDescriptorPSO attributes[GPU_VERT_ATTR_MAX_LEN]
bool operator==(const MTLVertexDescriptor &other) const
SpecializationStateDescriptor(Vector< shader::SpecializationConstant::Value > source)
bool operator==(const SpecializationStateDescriptor &other) const
Vector< shader::SpecializationConstant::Value > values
i
Definition text_draw.cc:230