Blender V4.3
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 "GPU_vertex_format.hh"
11
12#include <Metal/Metal.h>
13
14#include "BLI_vector.hh"
15
16#include "gpu_shader_private.hh"
17
18namespace blender::gpu {
19
25 MTLVertexFormat format;
26 int offset;
29
31 {
32 return (format == other.format) && (offset == other.offset) &&
33 (buffer_index == other.buffer_index) &&
34 (format_conversion_mode == other.format_conversion_mode);
35 }
36
37 uint64_t hash() const
38 {
39 return uint64_t((uint64_t(this->format) ^ (this->offset << 4) ^ (this->buffer_index << 8) ^
40 (this->format_conversion_mode << 12)));
41 }
42
43 void reset()
44 {
45 format = MTLVertexFormatInvalid;
46 offset = 0;
47 buffer_index = 0;
49 }
50};
51
53 MTLVertexStepFunction step_function;
55 int stride;
56
58 {
59 return (step_function == other.step_function) && (step_rate == other.step_rate) &&
60 (stride == other.stride);
61 }
62
63 uint64_t hash() const
64 {
65 return uint64_t(uint64_t(this->step_function) ^ (this->step_rate << 4) ^ (this->stride << 8));
66 }
67
68 void reset()
69 {
70 step_function = MTLVertexStepFunctionPerVertex;
71 step_rate = 1;
72 stride = 0;
73 }
74};
75
76/* SSBO attribute state caching. */
78
80 int vbo_id;
85
88 int attribute_ind, int vertexbuffer_ind, int offset, int stride, int format, bool instanced)
89 : mtl_attribute_index(attribute_ind),
90 vbo_id(vertexbuffer_ind),
91 attribute_offset(offset),
92 per_vertex_stride(stride),
94 is_instance(instanced)
95 {
96 }
97
98 bool operator==(const MTLSSBOAttribute &other) const
99 {
100 return (memcmp(this, &other, sizeof(MTLSSBOAttribute)) == 0);
101 }
102
103 void reset()
104 {
106 vbo_id = 0;
110 is_instance = false;
111 }
112};
113
115
116 /* Core Vertex Attributes. */
123 MTLPrimitiveTopologyClass prim_topology_class;
124
125 /* WORKAROUND: SSBO Vertex-fetch attributes -- These follow the same structure
126 * but have slightly different binding rules, passed in via uniform
127 * push constant data block. */
131
132 bool operator==(const MTLVertexDescriptor &other) const
133 {
134 if ((this->max_attribute_value != other.max_attribute_value) ||
135 (this->total_attributes != other.total_attributes) ||
136 (this->num_vert_buffers != other.num_vert_buffers))
137 {
138 return false;
139 }
140 if (this->prim_topology_class != other.prim_topology_class) {
141 return false;
142 };
143
144 for (const int a : IndexRange(this->max_attribute_value + 1)) {
145 if (!(this->attributes[a] == other.attributes[a])) {
146 return false;
147 }
148 }
149
150 for (const int b : IndexRange(this->num_vert_buffers)) {
151 if (!(this->buffer_layouts[b] == other.buffer_layouts[b])) {
152 return false;
153 }
154 }
155
156 /* NOTE: No need to compare SSBO attributes, as these will match attribute bindings for the
157 * given shader. These are simply extra pre-resolved properties we want to include in the
158 * cache. */
159 return true;
160 }
161
163 {
164 uint64_t hash = (uint64_t)(this->max_attribute_value ^ this->num_vert_buffers);
165 for (const int a : IndexRange(this->max_attribute_value + 1)) {
166 hash ^= this->attributes[a].hash() << a;
167 }
168
169 for (const int b : IndexRange(this->num_vert_buffers)) {
170 hash ^= this->buffer_layouts[b].hash() << (b + 10);
171 }
172
173 /* NOTE: SSBO vertex fetch members not hashed as these will match attribute bindings. */
174 return hash;
175 }
176};
177
180
183
185 {
186 return values == other.values;
187 }
188
190 {
191 uint64_t hash = values.size();
192 uint seed = 0xFF;
193 for (const Shader::Constants::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
251 if (clipping_plane_enable_mask != other.clipping_plane_enable_mask) {
252 return false;
253 }
254
255 if ((num_color_attachments != other.num_color_attachments) ||
256 (depth_attachment_format != other.depth_attachment_format) ||
257 (stencil_attachment_format != other.stencil_attachment_format) ||
258 (color_write_mask != other.color_write_mask) ||
259 (blending_enabled != other.blending_enabled) || (alpha_blend_op != other.alpha_blend_op) ||
260 (rgb_blend_op != other.rgb_blend_op) ||
261 (dest_alpha_blend_factor != other.dest_alpha_blend_factor) ||
262 (dest_rgb_blend_factor != other.dest_rgb_blend_factor) ||
263 (src_alpha_blend_factor != other.src_alpha_blend_factor) ||
264 (src_rgb_blend_factor != other.src_rgb_blend_factor) ||
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)) {
273 if (color_attachment_format[c] != other.color_attachment_format[c]) {
274 return false;
275 }
276 }
277
278 if (!(specialization_state == other.specialization_state)) {
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(this->point_size);
318
319 /* Clipping plane enablement. */
321
322 /* Specialization constants. We can treat the raw bytes as uint. */
324
325 return hash;
326 }
327
328 /* Reset the Vertex Descriptor to default. */
341};
342
343/* Metal Compute Pipeline State Descriptor containing all unique information which feeds PSO
344 * creation. */
346
347 /* Specialization constants map. */
349
355
356 /* Comparison Operator for caching. */
358 {
359 return (specialization_state == other.specialization_state);
360 }
361
363 {
364 return specialization_state.hash();
365 }
366};
367
368} // namespace blender::gpu
unsigned char uchar
unsigned int uint
#define GPU_BATCH_INST_VBO_MAX_LEN
Definition GPU_batch.hh:33
#define GPU_BATCH_VBO_MAX_LEN
Definition GPU_batch.hh:32
GPUVertFetchMode
@ GPU_FETCH_FLOAT
#define GPU_VERT_ATTR_MAX_LEN
static unsigned long seed
Definition btSoftBody.h:39
local_group_size(16, 16) .push_constant(Type b
#define GPU_FB_MAX_COLOR_ATTACHMENT
format
unsigned __int64 uint64_t
Definition stdint.h:90
bool operator==(const MTLComputePipelineStateDescriptor &other) const
MTLComputePipelineStateDescriptor(Vector< Shader::Constants::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
MTLSSBOAttribute ssbo_attributes[GPU_VERT_ATTR_MAX_LEN]
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
bool operator==(const SpecializationStateDescriptor &other) const
SpecializationStateDescriptor(Vector< Shader::Constants::Value > source)