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,
110 bool buffer_added =
false;
112 int buffer_stride =
format->stride;
114 int buffer_index = -1;
115 int attribute_offset = 0;
119 for (uint32_t a_idx = 0; a_idx <
format->attr_len; a_idx++) {
120 const GPUVertAttr *a = &
format->attrs[a_idx];
122 if (
format->deinterleaved) {
123 attribute_offset += ((a_idx == 0) ? 0 :
format->attrs[a_idx - 1].size) *
verts->vertex_len;
124 buffer_stride = a->
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 (instanced) ? MTLVertexStepFunctionPerInstance : 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_INFO(
" -- [Batch] Adding source %s buffer (Index: %d, Stride: %d)",
172 (instanced) ?
"instance" :
"vertex",
178 desc.vertex_descriptor.buffer_layouts[buffer_index].stride = buffer_stride;
191 "only mat4 attributes currently supported -- Not ready to handle other long "
192 "component length attributes yet");
199 "mat4 type expected but there are fewer components");
200 BLI_assert_msg(mtl_attr.size == 16,
"Expecting subtype 'vec4' with 16 bytes");
202 mtl_attr.format == MTLVertexFormatFloat4,
203 "Per-attribute vertex format MUST be float4 for an input type of 'mat4'");
208 desc.vertex_descriptor.attributes[mtl_attr.location +
i].format =
209 MTLVertexFormatFloat4;
212 desc.vertex_descriptor.attributes[mtl_attr.location +
i].offset =
213 attribute_offset +
i * 16;
215 desc.vertex_descriptor.attributes[mtl_attr.location +
i].buffer_index =
219 desc.vertex_descriptor.total_attributes++;
220 desc.vertex_descriptor.max_attribute_value =
max_ii(
221 mtl_attr.location +
i, desc.vertex_descriptor.max_attribute_value);
222 MTL_LOG_INFO(
"-- Sub-Attrib Location: %d, offset: %d, buffer index: %d",
223 mtl_attr.location +
i,
224 attribute_offset +
i * 16,
228 attr_mask &= ~(1 << (mtl_attr.location +
i));
231 "Float4x4 attribute type added for '%s' at attribute locations: %d to %d",
234 mtl_attr.location + 3);
238 BLI_assert(desc.vertex_descriptor.max_attribute_value <
264 MTLVertexFormat converted_format;
273 if (can_use_internal_conversion) {
274 desc.vertex_descriptor.attributes[mtl_attr.location].format = converted_format;
275 desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
278 BLI_assert(converted_format != MTLVertexFormatInvalid);
295 desc.vertex_descriptor.attributes[mtl_attr.location].format = converted_format;
296 desc.vertex_descriptor.attributes[mtl_attr.location].format_conversion_mode =
298 BLI_assert(desc.vertex_descriptor.attributes[mtl_attr.location].format !=
299 MTLVertexFormatInvalid);
301 desc.vertex_descriptor.attributes[mtl_attr.location].offset = attribute_offset;
302 desc.vertex_descriptor.attributes[mtl_attr.location].buffer_index = buffer_index;
303 desc.vertex_descriptor.max_attribute_value =
304 ((mtl_attr.location) > desc.vertex_descriptor.max_attribute_value) ?
305 (mtl_attr.location) :
306 desc.vertex_descriptor.max_attribute_value;
307 desc.vertex_descriptor.total_attributes++;
313 " -- Batch Attribute(%d): ORIG Shader Format: %d, ORIG Vert format: %d, Vert "
314 "components: %d, Fetch Mode %d --> FINAL FORMAT: %d",
316 (
int)mtl_attr.format,
320 (
int)desc.vertex_descriptor.attributes[mtl_attr.location].format);
323 " -- [Batch] matching %s attribute '%s' (Attribute Index: %d, Buffer index: %d, "
325 (instanced) ?
"instance" :
"vertex",
356 if (active_shader_ ==
nullptr || !active_shader_->is_valid()) {
370 if (mtl_elem !=
nullptr) {
380 prepare_vertex_descriptor_and_bindings(
buffers, num_buffers);
384 for (
int i = 0;
i < num_buffers;
i++) {
386 if (buf_at_index ==
nullptr) {
389 "Total buffer count does not match highest buffer index, could be gaps in bindings");
408 [rec pushDebugGroup:[NSString stringWithFormat:
@"Draw Commands%@ (GPUShader: %s)",
409 this->elem ?
@"(indexed)" :
@"",
410 active_shader_->get_interface()->get_name()]];
411 [rec insertDebugSignpost:[NSString
412 stringWithFormat:
@"Draw Commands %@ (GPUShader: %s)",
413 this->elem ?
@"(indexed)" :
@"",
414 active_shader_->get_interface()->get_name()]];
423 MTL_LOG_ERROR(
"Failed to prepare and apply render pipeline state.");
429 for (
int i = 0;
i < num_buffers;
i++) {
431 if (buf_at_index ==
nullptr) {
434 "Total buffer count does not match highest buffer index, could be gaps in bindings");
442 id<MTLBuffer> mtl_buffer = mtlvbo->get_metal_buffer();
460void MTLBatch::prepare_vertex_descriptor_and_bindings(
MTLVertBuf **
buffers,
int &num_buffers)
469 uint16_t attr_mask =
interface->get_enabled_attribute_mask();
502 buffer_is_instanced[bid] =
true;
506 buffer_is_instanced[bid] =
false;
512 VertexDescriptorShaderInterfacePair pair{};
516 pair.bufferIds[
i].id = -1;
517 pair.bufferIds[
i].is_instance = 0;
518 pair.bufferIds[
i].used = 0;
525 MTL_LOG_INFO(
" -- [Batch] Checking bindings for bound instance buffer %p", mtl_inst[
v]);
526 int buffer_ind = this->prepare_vertex_binding(
527 mtl_inst[
v], desc,
interface, attr_mask,
true);
528 if (buffer_ind >= 0) {
530 buffer_is_instanced[buffer_ind] =
true;
532 pair.bufferIds[buffer_ind].id =
v;
533 pair.bufferIds[buffer_ind].used = 1;
534 pair.bufferIds[buffer_ind].is_instance = 1;
535 num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers;
542 if (mtl_verts[
v] !=
nullptr) {
543 MTL_LOG_INFO(
" -- [Batch] Checking bindings for bound vertex buffer %p", mtl_verts[
v]);
544 int buffer_ind = this->prepare_vertex_binding(
545 mtl_verts[
v], desc,
interface, attr_mask,
false);
546 if (buffer_ind >= 0) {
548 buffer_is_instanced[buffer_ind] =
false;
550 pair.bufferIds[buffer_ind].id =
v;
551 pair.bufferIds[buffer_ind].used = 1;
552 pair.bufferIds[buffer_ind].is_instance = 0;
553 num_buffers = ((buffer_ind + 1) > num_buffers) ? (buffer_ind + 1) : num_buffers;
559 pair.attr_mask = attr_mask;
561 pair.num_buffers = num_buffers;
562 if (!this->vao_cache.insert(pair)) {
564 "[Performance Warning] cache is full (Size: %d), vertex descriptor will not be cached\n",
570#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
571 if (attr_mask != 0) {
573 for (
int i = 0;
i < active_shader_->get_interface()->get_total_attributes();
i++) {
574 const MTLShaderInputAttribute &attr = active_shader_->get_interface()->get_attribute(
i);
575 if (attr_mask & (1 << attr.location)) {
577 "Warning: Missing expected attribute '%s' with location: %u in shader %s (attr "
579 active_shader_->get_interface()->get_name_at_offset(attr.name_offset),
581 active_shader_->name_get(),
587 MTLVertexFormatInvalid);
594void MTLBatch::draw_advanced(
int v_first,
int v_count,
int i_first,
int i_count)
600 id<MTLRenderCommandEncoder> rec = this->
bind();
608 MTLIndexBuf *mtl_elem =
static_cast<MTLIndexBuf *
>(
reinterpret_cast<IndexBuf *
>(this->elem));
612 if (mtl_elem ==
nullptr) {
617 uint32_t emulated_v_count = v_count;
618 id<MTLBuffer> generated_index_buffer = this->get_emulated_toplogy_buffer(emulated_prim_type,
626 [rec setCullMode:MTLCullModeNone];
628 if (generated_index_buffer != nil) {
629 BLI_assert(emulated_mtl_prim_type == MTLPrimitiveTypeTriangle ||
630 emulated_mtl_prim_type == MTLPrimitiveTypeLine);
631 if (emulated_mtl_prim_type == MTLPrimitiveTypeTriangle) {
634 if (emulated_mtl_prim_type == MTLPrimitiveTypeLine) {
639 ctx->ensure_depth_stencil_state(emulated_mtl_prim_type);
641 [rec drawIndexedPrimitives:emulated_mtl_prim_type
642 indexCount:emulated_v_count
643 indexType:MTLIndexTypeUInt32
644 indexBuffer:generated_index_buffer
646 instanceCount:i_count
648 baseInstance:i_first];
651 printf(
"[Note] Cannot draw batch -- Emulated Topology mode: %u not yet supported\n",
657 ctx->ensure_depth_stencil_state(mtl_prim_type);
660 [rec drawPrimitives:mtl_prim_type
663 instanceCount:i_count
664 baseInstance:i_first];
666 ctx->main_command_buffer.register_draw_counters(v_count * i_count);
672 uint32_t base_index = mtl_elem->index_base_;
674 uint32_t v_first_ofs = ((v_first + mtl_elem->index_start_) * index_size);
676 "Index offset is not 2/4-byte aligned as per METAL spec");
682 uint index_count = v_count;
684 id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
688 if (index_buffer != nil) {
691 ctx->ensure_depth_stencil_state(mtl_prim_type);
694 [rec drawIndexedPrimitives:mtl_prim_type
695 indexCount:index_count
697 indexBuffer:index_buffer
698 indexBufferOffset:v_first_ofs
699 instanceCount:i_count
700 baseVertex:base_index
701 baseInstance:i_first];
702 ctx->main_command_buffer.register_draw_counters(index_count * i_count);
705 BLI_assert_msg(
false,
"Index buffer does not have backing Metal buffer");
713void MTLBatch::draw_advanced_indirect(GPUStorageBuf *indirect_buf, intptr_t offset)
717 id<MTLRenderCommandEncoder> rec = this->
bind();
719 printf(
"Failed to open Render Command encoder for DRAW INDIRECT\n");
727 MTLStorageBuf *mtlssbo =
static_cast<MTLStorageBuf *
>(
unwrap(indirect_buf));
728 id<MTLBuffer> mtl_indirect_buf = mtlssbo->get_metal_buffer();
730 if (mtl_indirect_buf == nil) {
740 "TriangleFan is not supported in Metal for Indirect draws.");
743 MTLIndexBuf *mtl_elem =
static_cast<MTLIndexBuf *
>(
reinterpret_cast<IndexBuf *
>(this->elem));
747 BLI_assert_msg(
false,
"Metal Topology emulation unsupported for draw indirect.\n");
754 if (mtl_elem ==
nullptr) {
756 ctx->ensure_depth_stencil_state(mtl_prim_type);
759 [rec drawPrimitives:mtl_prim_type indirectBuffer:mtl_indirect_buf indirectBufferOffset:offset];
760 ctx->main_command_buffer.register_draw_counters(1);
768 uint index_count = 0;
771 mtl_elem->flag_can_optimize(
false);
773 id<MTLBuffer> index_buffer = mtl_elem->get_index_buffer(final_prim_type, index_count);
777 if (index_buffer != nil) {
780 ctx->ensure_depth_stencil_state(mtl_prim_type);
783 [rec drawIndexedPrimitives:mtl_prim_type
785 indexBuffer:index_buffer
787 indirectBuffer:mtl_indirect_buf
788 indirectBufferOffset:offset];
789 ctx->main_command_buffer.register_draw_counters(1);
792 BLI_assert_msg(
false,
"Index buffer does not have backing Metal buffer");
806id<MTLBuffer> MTLBatch::get_emulated_toplogy_buffer(
GPUPrimType &in_out_prim_type,
807 uint32_t &in_out_v_count)
815 switch (input_prim_type) {
819 BLI_assert_msg(
false,
"Optimal primitive types should not reach here.");
824 BLI_assert_msg(
false,
"Adjacency primitive types should not reach here.");
842 if (this->emulated_topology_buffer_ !=
nullptr &&
843 (emulated_topology_type_ != input_prim_type || topology_buffer_input_v_count_ != v_count))
847 emulated_topology_buffer_->free();
848 emulated_topology_buffer_ =
nullptr;
852 if (this->emulated_topology_buffer_ ==
nullptr) {
855 switch (input_prim_type) {
858 output_prim_count = v_count - 1;
861 output_prim_count = v_count;
865 output_prim_count = v_count - 2;
868 BLI_assert_msg(
false,
"Cannot generate optimized topology buffer for other types.");
874 uint32_t buffer_bytes = output_IB_elems * 4;
884 bool winding_clockwise =
false;
887 switch (input_prim_type) {
891 for (line = 0; line < output_prim_count - 1; line++) {
892 data[line * 2 + 0] = line + 0;
893 data[line * 2 + 1] = line + 1;
896 data[line * 2 + 0] = line + 0;
897 data[line * 2 + 1] = 0;
902 for (
int triangle = 0; triangle < output_prim_count; triangle++) {
903 data[triangle * 3 + 0] = 0;
904 data[triangle * 3 + 1] = triangle + 1;
905 data[triangle * 3 + 2] = triangle + 2;
910 BLI_assert_msg(
false,
"Other primitive types do not require emulation.");
915 this->emulated_topology_buffer_->flush();
917 topology_buffer_input_v_count_ = v_count;
918 topology_buffer_output_v_count_ = output_IB_elems;
919 emulated_topology_type_ = input_prim_type;
923 in_out_v_count = topology_buffer_output_v_count_;
924 in_out_prim_type = output_prim_type;
925 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)
static constexpr int GPU_BATCH_VBO_MAX_LEN
static constexpr int GPU_BATCH_INST_VBO_MAX_LEN
@ GPU_PRIM_LINE_STRIP_ADJ
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
StateManager * state_manager
id< MTLRenderCommandEncoder > bind()
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
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_MAX_VERTEX_INPUT_ATTRIBUTES
#define MTL_LOG_INFO(info,...)
#define MTL_LOG_WARNING(info,...)
#define MTL_LOG_ERROR(info,...)
MTLVertexFormat format_resize_comp(MTLVertexFormat mtl_format, uint32_t components)
static Context * unwrap(GPUContext *ctx)
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)
void reset_vertex_descriptor()
MTLVertexDescriptor vertex_descriptor
MTLVertexAttributeDescriptorPSO attributes[GPU_VERT_ATTR_MAX_LEN]