37 this->draw_advanced(v_first, v_count, i_first, i_count);
42 this->draw_advanced_indirect(indirect_buf, offset);
45void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_init(
MTLContext *ctx)
48 this->vertex_descriptor_cache_clear();
52void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_clear()
55 cache_context_ =
nullptr;
58void MTLBatch::MTLVertexDescriptorCache::vertex_descriptor_cache_ensure()
60 if (this->cache_context_ !=
nullptr) {
65 this->vertex_descriptor_cache_clear();
70 if (cache_context_ ==
nullptr) {
75MTLBatch::VertexDescriptorShaderInterfacePair *MTLBatch::MTLVertexDescriptorCache::find(
76 const ShaderInterface *interface)
78 this->vertex_descriptor_cache_ensure();
80 if (cache_[
i].interface == interface && cache_[
i].cache_life_index == cache_life_index_) {
87bool MTLBatch::MTLVertexDescriptorCache::insert(
88 MTLBatch::VertexDescriptorShaderInterfacePair &
data)
90 vertex_descriptor_cache_ensure();
92 if (cache_[
i].interface ==
nullptr || cache_[
i].cache_life_index != cache_life_index_) {
94 cache_[
i].cache_life_index = cache_life_index_;
101int MTLBatch::prepare_vertex_binding(MTLVertBuf *
verts,
102 MTLRenderPipelineStateDescriptor &desc,
103 const MTLShaderInterface *interface,
109 bool buffer_added =
false;
111 int buffer_stride =
format->stride;
113 int buffer_index = -1;
114 int attribute_offset = 0;
118 for (uint32_t a_idx = 0; a_idx <
format->attr_len; a_idx++) {
119 const GPUVertAttr *a = &
format->attrs[a_idx];
121 if (
format->deinterleaved) {
122 attribute_offset += ((a_idx == 0) ? 0 :
format->attrs[a_idx - 1].type.size()) *
127 attribute_offset = a->
offset;
132 for (uint32_t n_idx = 0; n_idx < a->
name_len; n_idx++) {
136 if (
input ==
nullptr ||
input->location == -1) {
142 const MTLShaderInputAttribute &mtl_attr =
interface->get_attribute(
input->binding);
150 if ((~attr_mask) & (1 << mtl_attr.location)) {
152 " -- [Batch] Skipping attribute with input location %d (As one is already bound)",
158 attr_mask &= ~(1 << mtl_attr.location);
163 buffer_index = desc.vertex_descriptor.num_vert_buffers;
164 desc.vertex_descriptor.buffer_layouts[buffer_index].step_function =
165 MTLVertexStepFunctionPerVertex;
166 desc.vertex_descriptor.buffer_layouts[buffer_index].step_rate = 1;
167 desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride;
168 desc.vertex_descriptor.num_vert_buffers++;
171 MTL_LOG_DEBUG(
" -- [Batch] Adding source vertex buffer (Index: %d, Stride: %d)",
177 desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride;
201 MTLVertexFormat converted_format;
209 if (can_use_internal_conversion) {
210 desc.vertex_descriptor.attributes[mtl_attr.location].format = converted_format;
211 desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
214 BLI_assert(converted_format != MTLVertexFormatInvalid);
232 desc.vertex_descriptor.attributes[mtl_attr.location].format = converted_format;
233 desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
235 BLI_assert(desc.vertex_descriptor.attributes[mtl_attr.location].format !=
236 MTLVertexFormatInvalid);
238 desc.vertex_descriptor.attributes[mtl_attr.location].offset = attribute_offset;
239 desc.vertex_descriptor.attributes[mtl_attr.location].buffer_index = buffer_index;
240 desc.vertex_descriptor.max_attribute_value =
241 ((mtl_attr.location) > desc.vertex_descriptor.max_attribute_value) ?
242 (mtl_attr.location) :
243 desc.vertex_descriptor.max_attribute_value;
244 desc.vertex_descriptor.total_attributes++;
250 " -- Batch Attribute(%d): ORIG Shader Format: %d, ORIG Vert format: %d, Vert "
251 "components: %d, Fetch Mode %d --> FINAL FORMAT: %d",
253 (
int)mtl_attr.format,
257 (
int)desc.vertex_descriptor.attributes[mtl_attr.location].format);
260 " -- [Batch] matching vertex attribute '%s' (Attribute Index: %d, Buffer index: "
293 if (active_shader_ ==
nullptr || !active_shader_->is_valid()) {
307 if (mtl_elem !=
nullptr) {
317 prepare_vertex_descriptor_and_bindings(
buffers, num_buffers);
321 for (
int i = 0;
i < num_buffers;
i++) {
323 if (buf_at_index ==
nullptr) {
326 "Total buffer count does not match highest buffer index, could be gaps in bindings");
345 [rec pushDebugGroup:[NSString stringWithFormat:
@"Draw Commands%@ (Shader: %s)",
346 this->elem ?
@"(indexed)" :
@"",
347 active_shader_->get_interface()->get_name()]];
348 [rec insertDebugSignpost:[NSString
349 stringWithFormat:
@"Draw Commands %@ (Shader: %s)",
350 this->elem ?
@"(indexed)" :
@"",
351 active_shader_->get_interface()->get_name()]];
360 MTL_LOG_ERROR(
"Failed to prepare and apply render pipeline state.");
366 for (
int i = 0;
i < num_buffers;
i++) {
368 if (buf_at_index ==
nullptr) {
371 "Total buffer count does not match highest buffer index, could be gaps in bindings");
379 id<MTLBuffer> mtl_buffer = mtlvbo->get_metal_buffer();
397void MTLBatch::prepare_vertex_descriptor_and_bindings(
MTLVertBuf **
buffers,
int &num_buffers)
406 uint16_t attr_mask =
interface->get_enabled_attribute_mask();
439 VertexDescriptorShaderInterfacePair pair{};
443 pair.bufferIds[
i].id = -1;
444 pair.bufferIds[
i].used = 0;
451 if (mtl_verts[
v] !=
nullptr) {
452 MTL_LOG_DEBUG(
" -- [Batch] Checking bindings for bound vertex buffer %p", mtl_verts[
v]);
453 int buffer_ind = this->prepare_vertex_binding(mtl_verts[
v], desc,
interface, attr_mask);
454 if (buffer_ind >= 0) {
457 pair.bufferIds[buffer_ind].id =
v;
458 pair.bufferIds[buffer_ind].used = 1;
459 num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers;
465 pair.attr_mask = attr_mask;
467 pair.num_buffers = num_buffers;
468 if (!this->vao_cache.insert(pair)) {
470 "[Performance Warning] cache is full (Size: %d), vertex descriptor will not be cached\n",
476#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
477 if (attr_mask != 0) {
479 for (
int i = 0;
i < active_shader_->get_interface()->get_total_attributes();
i++) {
480 const MTLShaderInputAttribute &attr = active_shader_->get_interface()->get_attribute(
i);
481 if (attr_mask & (1 << attr.location)) {
483 "Warning: Missing expected attribute '%s' with location: %u in shader %s (attr "
485 active_shader_->get_interface()->get_name_at_offset(attr.name_offset),
487 active_shader_->name_get(),
493 MTLVertexFormatInvalid);
500void MTLBatch::draw_advanced(
int v_first,
int v_count,
int i_first,
int i_count)
506 id<MTLRenderCommandEncoder> rec = this->
bind();
514 MTLIndexBuf *mtl_elem =
static_cast<MTLIndexBuf *
>(
reinterpret_cast<IndexBuf *
>(this->elem));
518 if (mtl_elem ==
nullptr) {
523 uint32_t emulated_v_count = v_count;
524 id<MTLBuffer> generated_index_buffer = this->get_emulated_toplogy_buffer(emulated_prim_type,
532 [rec setCullMode:MTLCullModeNone];
534 if (generated_index_buffer != nil) {
535 BLI_assert(emulated_mtl_prim_type == MTLPrimitiveTypeTriangle ||
536 emulated_mtl_prim_type == MTLPrimitiveTypeLine);
537 if (emulated_mtl_prim_type == MTLPrimitiveTypeTriangle) {
540 if (emulated_mtl_prim_type == MTLPrimitiveTypeLine) {
545 ctx->ensure_depth_stencil_state(emulated_mtl_prim_type);
547 [rec drawIndexedPrimitives:emulated_mtl_prim_type
548 indexCount:emulated_v_count
549 indexType:MTLIndexTypeUInt32
550 indexBuffer:generated_index_buffer
552 instanceCount:i_count
554 baseInstance:i_first];
557 printf(
"[Note] Cannot draw batch -- Emulated Topology mode: %u not yet supported\n",
563 ctx->ensure_depth_stencil_state(mtl_prim_type);
566 [rec drawPrimitives:mtl_prim_type
569 instanceCount:i_count
570 baseInstance:i_first];
572 ctx->main_command_buffer.register_draw_counters(v_count * i_count);
578 uint32_t base_index = mtl_elem->index_base_;
580 uint32_t v_first_ofs = ((v_first + mtl_elem->index_start_) * index_size);
582 "Index offset is not 2/4-byte aligned as per METAL spec");
588 uint index_count = v_count;
590 id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
594 if (index_buffer != nil) {
597 ctx->ensure_depth_stencil_state(mtl_prim_type);
600 [rec drawIndexedPrimitives:mtl_prim_type
601 indexCount:index_count
603 indexBuffer:index_buffer
604 indexBufferOffset:v_first_ofs
605 instanceCount:i_count
606 baseVertex:base_index
607 baseInstance:i_first];
608 ctx->main_command_buffer.register_draw_counters(index_count * i_count);
611 BLI_assert_msg(
false,
"Index buffer does not have backing Metal buffer");
619void MTLBatch::draw_advanced_indirect(StorageBuf *indirect_buf, intptr_t offset)
623 id<MTLRenderCommandEncoder> rec = this->
bind();
625 printf(
"Failed to open Render Command encoder for DRAW INDIRECT\n");
633 MTLStorageBuf *mtlssbo =
static_cast<MTLStorageBuf *
>(indirect_buf);
634 id<MTLBuffer> mtl_indirect_buf = mtlssbo->get_metal_buffer();
636 if (mtl_indirect_buf == nil) {
646 "TriangleFan is not supported in Metal for Indirect draws.");
649 MTLIndexBuf *mtl_elem =
static_cast<MTLIndexBuf *
>(
reinterpret_cast<IndexBuf *
>(this->elem));
653 BLI_assert_msg(
false,
"Metal Topology emulation unsupported for draw indirect.\n");
660 if (mtl_elem ==
nullptr) {
662 ctx->ensure_depth_stencil_state(mtl_prim_type);
665 [rec drawPrimitives:mtl_prim_type indirectBuffer:mtl_indirect_buf indirectBufferOffset:offset];
666 ctx->main_command_buffer.register_draw_counters(1);
674 uint index_count = 0;
677 mtl_elem->flag_can_optimize(
false);
679 id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
683 if (index_buffer != nil) {
686 ctx->ensure_depth_stencil_state(mtl_prim_type);
689 [rec drawIndexedPrimitives:mtl_prim_type
691 indexBuffer:index_buffer
693 indirectBuffer:mtl_indirect_buf
694 indirectBufferOffset:offset];
695 ctx->main_command_buffer.register_draw_counters(1);
698 BLI_assert_msg(
false,
"Index buffer does not have backing Metal buffer");
712id<MTLBuffer> MTLBatch::get_emulated_toplogy_buffer(
GPUPrimType &in_out_prim_type,
713 uint32_t &in_out_v_count)
721 switch (input_prim_type) {
725 BLI_assert_msg(
false,
"Optimal primitive types should not reach here.");
730 BLI_assert_msg(
false,
"Adjacency primitive types should not reach here.");
748 if (this->emulated_topology_buffer_ !=
nullptr &&
749 (emulated_topology_type_ != input_prim_type || topology_buffer_input_v_count_ != v_count))
753 emulated_topology_buffer_->free();
754 emulated_topology_buffer_ =
nullptr;
758 if (this->emulated_topology_buffer_ ==
nullptr) {
761 switch (input_prim_type) {
764 output_prim_count = v_count - 1;
767 output_prim_count = v_count;
771 output_prim_count = v_count - 2;
774 BLI_assert_msg(
false,
"Cannot generate optimized topology buffer for other types.");
780 uint32_t buffer_bytes = output_IB_elems * 4;
790 bool winding_clockwise =
false;
793 switch (input_prim_type) {
797 for (line = 0; line < output_prim_count - 1; line++) {
798 data[line * 2 + 0] = line + 0;
799 data[line * 2 + 1] = line + 1;
802 data[line * 2 + 0] = line + 0;
803 data[line * 2 + 1] = 0;
808 for (
int triangle = 0; triangle < output_prim_count; triangle++) {
809 data[triangle * 3 + 0] = 0;
810 data[triangle * 3 + 1] = triangle + 1;
811 data[triangle * 3 + 2] = triangle + 2;
816 BLI_assert_msg(
false,
"Other primitive types do not require emulation.");
821 this->emulated_topology_buffer_->flush();
823 topology_buffer_input_v_count_ = v_count;
824 topology_buffer_output_v_count_ = output_IB_elems;
825 emulated_topology_type_ = input_prim_type;
829 in_out_v_count = topology_buffer_output_v_count_;
830 in_out_prim_type = output_prim_type;
831 return (emulated_topology_buffer_) ? emulated_topology_buffer_->get_metal_buffer() : nil;
#define BLI_assert_msg(a, msg)
static constexpr int GPU_BATCH_VBO_MAX_LEN
@ GPU_PRIM_LINE_STRIP_ADJ
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
StateManager * state_manager
void draw_indirect(StorageBuf *indirect_buf, intptr_t offset) override
id< MTLRenderCommandEncoder > bind()
void draw(int v_first, int v_count, int i_first, int i_count) override
void unbind(id< MTLRenderCommandEncoder > rec)
gpu::MTLBuffer * allocate(uint64_t size, bool cpu_visible)
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()
MTLCommandBufferManager main_command_buffer
static MTLBufferPool * get_global_memory_manager()
static MTLIndexType gpu_index_type_to_metal(GPUIndexBufType type)
void upload_data() override
void bind_vertex_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
MTLRenderPipelineStateDescriptor & get_pipeline_descriptor()
#define GPU_VAO_STATIC_LEN
#define MTL_LOG_WARNING(info,...)
#define MTL_LOG_DEBUG(info,...)
#define MTL_LOG_ERROR(info,...)
MTLVertexFormat format_resize_comp(MTLVertexFormat mtl_format, uint32_t components)
static MTLPrimitiveType gpu_prim_type_to_metal(GPUPrimType prim_type)
bool mtl_convert_vertex_format(MTLVertexFormat shader_attr_format, GPUVertCompType component_type, uint32_t component_len, GPUVertFetchMode fetch_mode, MTLVertexFormat *r_convertedFormat)
static bool mtl_needs_topology_emulation(GPUPrimType prim_type)
GPUVertFetchMode fetch_mode() const
GPUVertCompType comp_type() const
struct GPUVertAttr::Type type
void reset_vertex_descriptor()
MTLVertexDescriptor vertex_descriptor
MTLVertexAttributeDescriptorPSO attributes[GPU_VERT_ATTR_MAX_LEN]