38 this->shader_in_use_ =
false;
40 this->draw_advanced(v_first, v_count, i_first, i_count);
46 this->shader_in_use_ =
false;
48 this->draw_advanced_indirect(indirect_buf, offset);
51void MTLBatch::shader_bind()
53 if (active_shader_ && active_shader_->
is_valid()) {
54 active_shader_->
bind();
55 shader_in_use_ =
true;
59void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_init(MTLContext *ctx)
62 this->vertex_descriptor_cache_clear();
66void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_clear()
69 cache_context_ =
nullptr;
72void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_ensure()
74 if (this->cache_context_ !=
nullptr) {
78 batch_->flag &= ~GPU_BATCH_DIRTY;
79 this->vertex_descriptor_cache_clear();
84 if (cache_context_ ==
nullptr) {
89MTLBatch::VertexDescriptorShaderInterfacePair *MTLBatch::MTLVertexDescriptorCache::find(
90 const ShaderInterface *interface)
92 this->vertex_descriptor_cache_ensure();
94 if (cache_[i].interface == interface && cache_[i].cache_life_index == cache_life_index_) {
101bool MTLBatch::MTLVertexDescriptorCache::insert(
102 MTLBatch::VertexDescriptorShaderInterfacePair &data)
104 vertex_descriptor_cache_ensure();
106 if (cache_[i].interface ==
nullptr || cache_[i].cache_life_index != cache_life_index_) {
108 cache_[i].cache_life_index = cache_life_index_;
115int MTLBatch::prepare_vertex_binding(MTLVertBuf *
verts,
116 MTLRenderPipelineStateDescriptor &desc,
117 const MTLShaderInterface *interface,
124 bool buffer_added =
false;
128 int buffer_index = -1;
129 int attribute_offset = 0;
133 buffer_stride >= 4 &&
134 "In Metal, Vertex buffer stride should be 4. SSBO Vertex fetch is not affected by this");
142 if (
format->deinterleaved) {
143 attribute_offset += ((a_idx == 0) ? 0 :
format->attrs[a_idx - 1].size) *
verts->vertex_len;
144 buffer_stride = a->
size;
147 attribute_offset = a->offset;
152 for (
uint32_t n_idx = 0; n_idx < a->name_len; n_idx++) {
154 const ShaderInput *input = interface->attr_get(name);
156 if (input ==
nullptr || input->location == -1) {
160 if (StringRefNull(name) !=
"dummy") {
162 "MTLBatch: Could not find attribute with name '%s' (defined in active vertex "
164 "in the shader interface for shader '%s'",
166 interface->get_name());
173 const MTLShaderInputAttribute &mtl_attr = interface->get_attribute(input->binding);
178 BLI_assert(mtl_attr.location == input->location);
181 if ((~attr_mask) & (1 << mtl_attr.location)) {
183 " -- [Batch] Skipping attribute with input location %d (As one is already bound)",
189 attr_mask &= ~(1 << mtl_attr.location);
194 buffer_index = desc.vertex_descriptor.num_vert_buffers;
195 desc.vertex_descriptor.buffer_layouts[buffer_index].step_function =
196 (instanced) ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
197 desc.vertex_descriptor.buffer_layouts[buffer_index].step_rate = 1;
198 desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride;
199 desc.vertex_descriptor.num_vert_buffers++;
202 MTL_LOG_INFO(
" -- [Batch] Adding source %s buffer (Index: %d, Stride: %d)",
203 (instanced) ?
"instance" :
"vertex",
209 desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride;
219 if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) {
222 "only mat4 attributes currently supported -- Not ready to handle other long "
223 "component length attributes yet");
229 MTLSSBOAttribute ssbo_attr(mtl_attr.index,
236 desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] =
238 desc.vertex_descriptor.num_ssbo_attributes++;
243 if (a->comp_len == 16) {
246 "mat4 type expected but there are fewer components");
247 BLI_assert_msg(mtl_attr.size == 16,
"Expecting subtype 'vec4' with 16 bytes");
249 mtl_attr.format == MTLVertexFormatFloat4,
250 "Per-attribute vertex format MUST be float4 for an input type of 'mat4'");
254 for (
int i = 0; i < a->comp_len / 4; i++) {
255 desc.vertex_descriptor.attributes[mtl_attr.location + i].format =
256 MTLVertexFormatFloat4;
259 desc.vertex_descriptor.attributes[mtl_attr.location + i].offset =
260 attribute_offset + i * 16;
262 desc.vertex_descriptor.attributes[mtl_attr.location + i].buffer_index =
266 desc.vertex_descriptor.total_attributes++;
267 desc.vertex_descriptor.max_attribute_value =
max_ii(
268 mtl_attr.location + i, desc.vertex_descriptor.max_attribute_value);
269 MTL_LOG_INFO(
"-- Sub-Attrib Location: %d, offset: %d, buffer index: %d",
270 mtl_attr.location + i,
271 attribute_offset + i * 16,
275 attr_mask &= ~(1 << (mtl_attr.location + i));
278 "Float4x4 attribute type added for '%s' at attribute locations: %d to %d",
281 mtl_attr.location + 3);
285 BLI_assert(desc.vertex_descriptor.max_attribute_value <
311 MTLVertexFormat converted_format;
318 bool is_floating_point_format = (a->comp_type ==
GPU_COMP_F32);
320 if (can_use_internal_conversion) {
321 desc.vertex_descriptor.attributes[mtl_attr.location].format = converted_format;
322 desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
325 BLI_assert(converted_format != MTLVertexFormatInvalid);
341 MTLVertexFormat converted_format;
343 mtl_attr.format, a->comp_len, &converted_format);
344 desc.vertex_descriptor.attributes[mtl_attr.location].format = can_convert ?
347 desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
349 BLI_assert(desc.vertex_descriptor.attributes[mtl_attr.location].format !=
350 MTLVertexFormatInvalid);
352 desc.vertex_descriptor.attributes[mtl_attr.location].offset = attribute_offset;
353 desc.vertex_descriptor.attributes[mtl_attr.location].buffer_index = buffer_index;
354 desc.vertex_descriptor.max_attribute_value =
355 ((mtl_attr.location) > desc.vertex_descriptor.max_attribute_value) ?
356 (mtl_attr.location) :
357 desc.vertex_descriptor.max_attribute_value;
358 desc.vertex_descriptor.total_attributes++;
361 BLI_assert_msg(desc.vertex_descriptor.attributes[mtl_attr.location].format ==
363 "SSBO Vertex Fetch does not support attribute conversion.");
365 MTLSSBOAttribute ssbo_attr(
371 desc.vertex_descriptor.attributes[mtl_attr.location].format),
375 desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] =
377 desc.vertex_descriptor.num_ssbo_attributes++;
384 " -- Batch Attribute(%d): ORIG Shader Format: %d, ORIG Vert format: %d, Vert "
385 "components: %d, Fetch Mode %d --> FINAL FORMAT: %d",
387 (
int)mtl_attr.format,
391 (
int)desc.vertex_descriptor.attributes[mtl_attr.location].format);
394 " -- [Batch] matching %s attribute '%s' (Attribute Index: %d, Buffer index: %d, "
396 (instanced) ?
"instance" :
"vertex",
427 if (active_shader_ ==
nullptr || !active_shader_->
is_valid()) {
447 if (mtl_elem !=
NULL) {
457 prepare_vertex_descriptor_and_bindings(
buffers, num_buffers);
461 for (
int i = 0; i < num_buffers; i++) {
463 if (buf_at_index ==
NULL) {
466 "Total buffer count does not match highest buffer index, could be gaps in bindings");
488 [rec pushDebugGroup:[NSString stringWithFormat:
@"Draw Commands%@ (GPUShader: %s)",
489 this->elem ?
@"(indexed)" :
@"",
491 [rec insertDebugSignpost:[NSString
492 stringWithFormat:
@"Draw Commands %@ (GPUShader: %s)",
493 this->elem ?
@"(indexed)" :
@"",
500 if (uses_ssbo_fetch) {
503 id<MTLBuffer> idx_buffer = nil;
506 if (mtl_elem !=
nullptr) {
517 BLI_assert(uniform_ssbo_index_mode_u16 != -1);
519 active_shader_->
uniform_int(uniform_ssbo_index_mode_u16, 1, 1, &uses_index_mode_u16);
545 int uses_indexed_rendering = (mtl_elem !=
nullptr) ? 1 : 0;
546 active_shader_->
uniform_int(uniform_ssbo_use_indexed, 1, 1, &uses_indexed_rendering);
555 (
const int *)(&final_prim_type));
560 (
const int *)(&v_count));
567 MTL_LOG_ERROR(
"Failed to prepare and apply render pipeline state.");
573 for (
int i = 0; i < num_buffers; i++) {
575 if (buf_at_index ==
NULL) {
578 "Total buffer count does not match highest buffer index, could be gaps in bindings");
586 id<MTLBuffer> mtl_buffer = mtlvbo->get_metal_buffer();
604void MTLBatch::prepare_vertex_descriptor_and_bindings(
MTLVertBuf **
buffers,
int &num_buffers)
613 uint16_t attr_mask = interface->get_enabled_attribute_mask();
641 VertexDescriptorShaderInterfacePair *
descriptor = this->vao_cache.find(interface);
651 buffer_is_instanced[bid] =
true;
655 buffer_is_instanced[bid] =
false;
670 VertexDescriptorShaderInterfacePair pair{};
671 pair.interface = interface;
674 pair.bufferIds[i].id = -1;
675 pair.bufferIds[i].is_instance = 0;
676 pair.bufferIds[i].used = 0;
683 MTL_LOG_INFO(
" -- [Batch] Checking bindings for bound instance buffer %p", mtl_inst[
v]);
684 int buffer_ind = this->prepare_vertex_binding(
685 mtl_inst[
v], desc, interface, attr_mask,
true);
686 if (buffer_ind >= 0) {
688 buffer_is_instanced[buffer_ind] =
true;
690 pair.bufferIds[buffer_ind].id =
v;
691 pair.bufferIds[buffer_ind].used = 1;
692 pair.bufferIds[buffer_ind].is_instance = 1;
693 num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers;
700 if (mtl_verts[
v] !=
NULL) {
701 MTL_LOG_INFO(
" -- [Batch] Checking bindings for bound vertex buffer %p", mtl_verts[
v]);
702 int buffer_ind = this->prepare_vertex_binding(
703 mtl_verts[
v], desc, interface, attr_mask,
false);
704 if (buffer_ind >= 0) {
706 buffer_is_instanced[buffer_ind] =
false;
708 pair.bufferIds[buffer_ind].id =
v;
709 pair.bufferIds[buffer_ind].used = 1;
710 pair.bufferIds[buffer_ind].is_instance = 0;
711 num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers;
718 pair.attr_mask = attr_mask;
720 pair.num_buffers = num_buffers;
721 if (!this->vao_cache.insert(pair)) {
723 "[Performance Warning] cache is full (Size: %d), vertex descriptor will not be cached\n",
729#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
730 if (attr_mask != 0) {
732 for (
int i = 0; i < active_shader_->
get_interface()->get_total_attributes(); i++) {
734 if (attr_mask & (1 << attr.location)) {
736 "Warning: Missing expected attribute '%s' with location: %u in shader %s (attr "
746 MTLVertexFormatInvalid);
753void MTLBatch::draw_advanced(
int v_first,
int v_count,
int i_first,
int i_count)
762 id<MTLRenderCommandEncoder> rec = this->
bind(v_count);
770 MTLIndexBuf *mtl_elem =
static_cast<MTLIndexBuf *
>(
reinterpret_cast<IndexBuf *
>(this->elem));
779 int output_num_verts = num_input_primitives *
784 "Output Vertex count is not compatible with the requested output vertex primitive type");
791 vertexCount:output_num_verts
792 instanceCount:i_count
793 baseInstance:i_first];
794 ctx->main_command_buffer.register_draw_counters(output_num_verts * i_count);
797 else if (mtl_elem ==
NULL) {
804 uint32_t emulated_v_count = v_count;
805 id<MTLBuffer> generated_index_buffer = this->get_emulated_toplogy_buffer(emulated_prim_type,
813 [rec setCullMode:MTLCullModeNone];
815 if (generated_index_buffer != nil) {
816 BLI_assert(emulated_mtl_prim_type == MTLPrimitiveTypeTriangle ||
817 emulated_mtl_prim_type == MTLPrimitiveTypeLine);
818 if (emulated_mtl_prim_type == MTLPrimitiveTypeTriangle) {
821 if (emulated_mtl_prim_type == MTLPrimitiveTypeLine) {
826 ctx->ensure_depth_stencil_state(emulated_mtl_prim_type);
828 [rec drawIndexedPrimitives:emulated_mtl_prim_type
829 indexCount:emulated_v_count
830 indexType:MTLIndexTypeUInt32
831 indexBuffer:generated_index_buffer
833 instanceCount:i_count
835 baseInstance:i_first];
838 printf(
"[Note] Cannot draw batch -- Emulated Topology mode: %u not yet supported\n",
844 ctx->ensure_depth_stencil_state(mtl_prim_type);
847 [rec drawPrimitives:mtl_prim_type
850 instanceCount:i_count
851 baseInstance:i_first];
853 ctx->main_command_buffer.register_draw_counters(v_count * i_count);
859 uint32_t base_index = mtl_elem->index_base_;
861 uint32_t v_first_ofs = ((v_first + mtl_elem->index_start_) * index_size);
863 "Index offset is not 2/4-byte aligned as per METAL spec");
869 uint index_count = v_count;
871 id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
875 if (index_buffer != nil) {
878 ctx->ensure_depth_stencil_state(mtl_prim_type);
881 [rec drawIndexedPrimitives:mtl_prim_type
882 indexCount:index_count
884 indexBuffer:index_buffer
885 indexBufferOffset:v_first_ofs
886 instanceCount:i_count
887 baseVertex:base_index
888 baseInstance:i_first];
889 ctx->main_command_buffer.register_draw_counters(index_count * i_count);
892 BLI_assert_msg(
false,
"Index buffer does not have backing Metal buffer");
900void MTLBatch::draw_advanced_indirect(GPUStorageBuf *indirect_buf,
intptr_t offset)
904 id<MTLRenderCommandEncoder> rec = this->
bind(0);
906 printf(
"Failed to open Render Command encoder for DRAW INDIRECT\n");
914 MTLStorageBuf *mtlssbo =
static_cast<MTLStorageBuf *
>(
unwrap(indirect_buf));
915 id<MTLBuffer> mtl_indirect_buf = mtlssbo->get_metal_buffer();
917 if (mtl_indirect_buf == nil) {
934 indirectBuffer:mtl_indirect_buf
935 indirectBufferOffset:offset];
936 ctx->main_command_buffer.register_draw_counters(1);
945 "TriangleFan is not supported in Metal for Indirect draws.");
948 MTLIndexBuf *mtl_elem =
static_cast<MTLIndexBuf *
>(
reinterpret_cast<IndexBuf *
>(this->elem));
952 BLI_assert_msg(
false,
"Metal Topology emulation unsupported for draw indirect.\n");
959 if (mtl_elem ==
NULL) {
961 ctx->ensure_depth_stencil_state(mtl_prim_type);
964 [rec drawPrimitives:mtl_prim_type indirectBuffer:mtl_indirect_buf indirectBufferOffset:offset];
965 ctx->main_command_buffer.register_draw_counters(1);
973 uint index_count = 0;
976 mtl_elem->flag_can_optimize(
false);
978 id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
982 if (index_buffer != nil) {
985 ctx->ensure_depth_stencil_state(mtl_prim_type);
988 [rec drawIndexedPrimitives:mtl_prim_type
990 indexBuffer:index_buffer
992 indirectBuffer:mtl_indirect_buf
993 indirectBufferOffset:offset];
994 ctx->main_command_buffer.register_draw_counters(1);
997 BLI_assert_msg(
false,
"Index buffer does not have backing Metal buffer");
1011id<MTLBuffer> MTLBatch::get_emulated_toplogy_buffer(
GPUPrimType &in_out_prim_type,
1020 switch (input_prim_type) {
1024 BLI_assert_msg(
false,
"Optimal primitive types should not reach here.");
1029 BLI_assert_msg(
false,
"Adjacency primitive types should not reach here.");
1047 if (this->emulated_topology_buffer_ !=
nullptr &&
1048 (emulated_topology_type_ != input_prim_type || topology_buffer_input_v_count_ != v_count))
1052 emulated_topology_buffer_->
free();
1053 emulated_topology_buffer_ =
nullptr;
1057 if (this->emulated_topology_buffer_ ==
nullptr) {
1060 switch (input_prim_type) {
1063 output_prim_count = v_count - 1;
1066 output_prim_count = v_count;
1070 output_prim_count = v_count - 2;
1073 BLI_assert_msg(
false,
"Cannot generate optimized topology buffer for other types.");
1079 uint32_t buffer_bytes = output_IB_elems * 4;
1082 buffer_bytes,
true);
1089 bool winding_clockwise =
false;
1092 switch (input_prim_type) {
1096 for (line = 0; line < output_prim_count - 1; line++) {
1097 data[line * 2 + 0] = line + 0;
1098 data[line * 2 + 1] = line + 1;
1101 data[line * 2 + 0] = line + 0;
1102 data[line * 2 + 1] = 0;
1107 for (
int triangle = 0; triangle < output_prim_count; triangle++) {
1108 data[triangle * 3 + 0] = 0;
1109 data[triangle * 3 + 1] = triangle + 1;
1110 data[triangle * 3 + 2] = triangle + 2;
1115 BLI_assert_msg(
false,
"Other primitive types do not require emulation.");
1120 this->emulated_topology_buffer_->
flush();
1122 topology_buffer_input_v_count_ = v_count;
1123 topology_buffer_output_v_count_ = output_IB_elems;
1124 emulated_topology_type_ = input_prim_type;
1128 in_out_v_count = topology_buffer_output_v_count_;
1129 in_out_prim_type = output_prim_type;
1130 return (emulated_topology_buffer_) ? emulated_topology_buffer_->
get_metal_buffer() : nil;
#define BLI_assert_msg(a, msg)
MINLINE int max_ii(int a, int b)
#define GPU_BATCH_INST_VBO_MAX_LEN
#define GPU_BATCH_VBO_MAX_LEN
@ GPU_PRIM_LINE_STRIP_ADJ
int gpu_get_prim_count_from_type(uint vertex_len, GPUPrimType prim_type)
void GPU_shader_uniform_int_ex(GPUShader *shader, int location, int length, int array_size, const int *value)
struct GPUShader GPUShader
ATTR_WARN_UNUSED_RESULT const BMVert * v
StateManager * state_manager
GPUIndexBufType index_type_
void draw(int v_first, int v_count, int i_first, int i_count) override
void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override
id< MTLRenderCommandEncoder > bind(uint v_count)
void unbind(id< MTLRenderCommandEncoder > rec)
gpu::MTLBuffer * allocate(uint64_t size, bool cpu_visible)
void * get_host_ptr() const
id< MTLBuffer > get_metal_buffer() const
MTLFrameBuffer * get_active_framebuffer()
MTLRenderPassState & get_render_pass_state()
bool ensure_render_pipeline_state(MTLPrimitiveType prim_type)
id< MTLRenderCommandEncoder > ensure_begin_render_pass()
static MTLContext * get()
id< MTLBuffer > get_null_buffer()
MTLCommandBufferManager main_command_buffer
static MTLBufferPool * get_global_memory_manager()
static MTLIndexType gpu_index_type_to_metal(GPUIndexBufType type)
void upload_data() override
id< MTLBuffer > get_index_buffer(GPUPrimType &in_out_primitive_type, uint &in_out_v_count)
void bind_vertex_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
BufferBindingCached cached_vertex_buffer_bindings[MTL_MAX_BUFFER_BINDINGS]
const char * get_name() const
const char * get_name_at_offset(uint32_t offset) const
const MTLShaderInputAttribute & get_attribute(uint index) const
void ssbo_vertex_fetch_bind_attributes_begin()
void ssbo_vertex_fetch_bind_attribute(const MTLSSBOAttribute &ssbo_attr)
int uni_ssbo_input_prim_type_loc
int get_ssbo_vertex_fetch_output_num_verts() const override
void uniform_int(int location, int comp_len, int array_size, const int *data) override
MTLPrimitiveType get_ssbo_vertex_fetch_output_prim_type()
int uni_ssbo_index_base_loc
int uni_ssbo_uses_index_mode_u16
int uni_ssbo_input_vert_count_loc
int uni_ssbo_uses_indexed_rendering
static int ssbo_vertex_type_to_attr_type(MTLVertexFormat attribute_type)
MTLShaderInterface * get_interface()
void ssbo_vertex_fetch_bind_attributes_end(id< MTLRenderCommandEncoder > active_encoder)
bool get_uses_ssbo_vertex_fetch() const override
MTLRenderPipelineStateDescriptor & get_pipeline_descriptor()
const char *const name_get() const
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
struct @620::@623 attr_id
#define GPU_VAO_STATIC_LEN
#define MTL_MAX_VERTEX_INPUT_ATTRIBUTES
#define MTL_LOG_INFO(info,...)
#define MTL_LOG_WARNING(info,...)
#define MTL_LOG_ERROR(info,...)
#define MTL_SSBO_VERTEX_FETCH_MAX_VBOS
#define GPU_SHADER_ATTR_TYPE_MAT4
#define MTL_SSBO_VERTEX_FETCH_IBO_INDEX
static Context * unwrap(GPUContext *ctx)
bool mtl_vertex_format_resize(MTLVertexFormat mtl_format, uint32_t components, MTLVertexFormat *r_convertedFormat)
static GPUContext * wrap(Context *ctx)
static MTLPrimitiveType gpu_prim_type_to_metal(GPUPrimType prim_type)
static bool mtl_vertex_count_fits_primitive_type(uint32_t vertex_count, MTLPrimitiveType prim_type)
static bool mtl_needs_topology_emulation(GPUPrimType prim_type)
bool mtl_convert_vertex_format(MTLVertexFormat shader_attrib_format, GPUVertCompType component_type, uint32_t component_length, GPUVertFetchMode fetch_mode, MTLVertexFormat *r_convertedFormat)
id< MTLBuffer > metal_buffer
void reset_vertex_descriptor()
MTLVertexDescriptor vertex_descriptor
MTLSSBOAttribute ssbo_attributes[GPU_VERT_ATTR_MAX_LEN]
bool uses_ssbo_vertex_fetch
MTLVertexAttributeDescriptorPSO attributes[GPU_VERT_ATTR_MAX_LEN]