31 render_pass_state_.reset_state();
32 compute_state_.reset_state();
35void MTLCommandBufferManager::register_encoder_counters()
41id<MTLCommandBuffer> MTLCommandBufferManager::ensure_begin()
43 if (active_command_buffer_ == nil) {
58 MTLCommandBufferDescriptor *desc = [[MTLCommandBufferDescriptor alloc]
init];
59 desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
60 desc.retainedReferences = YES;
62 active_command_buffer_ = [context_.
queue commandBufferWithDescriptor:desc];
66 if (active_command_buffer_ == nil) {
67 active_command_buffer_ = [context_.
queue commandBuffer];
70 [active_command_buffer_ retain];
71 context_.main_command_buffer.inc_active_command_buffer_count();
74 MTLScratchBufferManager &mem = context_.memory_manager;
81 debug_group_stack.clear();
82 debug_group_pushed_stack.clear();
85 return active_command_buffer_;
92 if (empty_ || active_command_buffer_ == nil) {
104 BLI_assert(active_command_encoder_type_ == MTL_NO_COMMAND_ENCODER);
107 context_.memory_manager.flush_active_scratch_buffer();
120 id<MTLCommandBuffer> cmd_buffer_ref = active_command_buffer_;
121 [cmd_buffer_ref retain];
123 [cmd_buffer_ref addCompletedHandler:^(id<MTLCommandBuffer> ) {
129 [cmd_buffer_ref release];
132 context_.main_command_buffer.dec_active_command_buffer_count();
136 [active_command_buffer_ commit];
145 "Maximum number of command buffers in flight. Host will wait until GPU work has "
146 "completed. Consider increasing GHOST_ContextMTL::max_command_buffer_count or reducing "
147 "work fragmentation to better utilize system hardware. Command buffers are flushed upon "
148 "GPUContext switches, this is the most common cause of excessive command buffer "
154 [active_command_buffer_ waitUntilCompleted];
160 NSError *
error = [active_command_buffer_
error];
169 if (last_submitted_command_buffer_ != nil) {
172 [last_submitted_command_buffer_ autorelease];
173 last_submitted_command_buffer_ = nil;
175 last_submitted_command_buffer_ = active_command_buffer_;
176 active_command_buffer_ = nil;
190 return (active_command_encoder_type_ == MTL_RENDER_COMMAND_ENCODER);
195 return (active_command_encoder_type_ == MTL_BLIT_COMMAND_ENCODER);
200 return (active_command_encoder_type_ == MTL_COMPUTE_COMMAND_ENCODER);
206 return active_render_command_encoder_;
212 return active_blit_command_encoder_;
218 return active_compute_command_encoder_;
225 return active_frame_buffer_;
236 if (active_command_encoder_type_ != MTL_NO_COMMAND_ENCODER) {
238 switch (active_command_encoder_type_) {
239 case MTL_RENDER_COMMAND_ENCODER: {
241 BLI_assert(active_render_command_encoder_ != nil);
244 [active_render_command_encoder_ endEncoding];
245 [active_render_command_encoder_ release];
246 active_render_command_encoder_ = nil;
247 active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
250 if (!retain_framebuffers) {
251 active_frame_buffer_ =
nullptr;
252 active_pass_descriptor_ =
nullptr;
257 case MTL_BLIT_COMMAND_ENCODER: {
259 BLI_assert(active_blit_command_encoder_ != nil);
260 [active_blit_command_encoder_ endEncoding];
261 [active_blit_command_encoder_ release];
262 active_blit_command_encoder_ = nil;
263 active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
267 case MTL_COMPUTE_COMMAND_ENCODER: {
269 BLI_assert(active_compute_command_encoder_ != nil);
270 [active_compute_command_encoder_ endEncoding];
271 [active_compute_command_encoder_ release];
272 active_compute_command_encoder_ = nil;
273 active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
278 BLI_assert(
false &&
"Invalid command encoder type");
285 BLI_assert(active_render_command_encoder_ == nil);
286 BLI_assert(active_blit_command_encoder_ == nil);
287 BLI_assert(active_compute_command_encoder_ == nil);
293 MTLFrameBuffer *ctx_framebuffer,
bool force_begin,
bool *r_new_pass)
299 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
304 if (active_command_encoder_type_ != MTL_RENDER_COMMAND_ENCODER ||
305 active_frame_buffer_ != ctx_framebuffer || force_begin)
310 bool is_rebind = (active_frame_buffer_ == ctx_framebuffer);
314 active_frame_buffer_ = ctx_framebuffer;
316 is_rebind && (!active_frame_buffer_->get_pending_clear()));
319 gpu::MTLBuffer *visibility_buffer = context_.get_visibility_buffer();
320 this->active_pass_descriptor_.visibilityResultBuffer =
322 context_.clear_visibility_dirty();
325 BLI_assert(active_render_command_encoder_ == nil);
329 unfold_pending_debug_groups();
333 active_render_command_encoder_ = [cmd_buf
334 renderCommandEncoderWithDescriptor:active_pass_descriptor_];
335 [active_render_command_encoder_ retain];
336 active_command_encoder_type_ = MTL_RENDER_COMMAND_ENCODER;
340 std::string debug_name =
"RenderCmdEncoder: Unnamed";
341 if (!debug_group_pushed_stack.empty()) {
342 debug_name =
"RenderCmdEncoder: " + debug_group_pushed_stack.back();
344 debug_name +=
" (FrameBuffer: " + std::string(active_frame_buffer_->name_get()) +
")";
345 active_render_command_encoder_.label = [NSString stringWithUTF8String:debug_name.c_str()];
349 this->register_encoder_counters();
353 active_frame_buffer_->apply_state();
357 active_frame_buffer_->mark_cleared();
360 render_pass_state_.reset_state();
370 BLI_assert(active_render_command_encoder_ != nil);
371 return active_render_command_encoder_;
377 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
381 if (active_command_encoder_type_ != MTL_BLIT_COMMAND_ENCODER) {
386 if (active_blit_command_encoder_ == nil) {
389 unfold_pending_debug_groups();
392 active_blit_command_encoder_ = [cmd_buf blitCommandEncoder];
393 BLI_assert(active_blit_command_encoder_ != nil);
394 [active_blit_command_encoder_ retain];
395 active_command_encoder_type_ = MTL_BLIT_COMMAND_ENCODER;
399 std::string debug_name =
"BlitCmdEncoder: Unnamed";
400 if (!debug_group_pushed_stack.empty()) {
401 debug_name =
"BlitCmdEncoder: " + debug_group_pushed_stack.back();
403 active_blit_command_encoder_.label = [NSString stringWithUTF8String:debug_name.c_str()];
407 this->register_encoder_counters();
409 BLI_assert(active_blit_command_encoder_ != nil);
410 return active_blit_command_encoder_;
416 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
420 if (active_command_encoder_type_ != MTL_COMPUTE_COMMAND_ENCODER) {
425 if (active_compute_command_encoder_ == nil) {
428 unfold_pending_debug_groups();
431 active_compute_command_encoder_ = [cmd_buf computeCommandEncoder];
432 BLI_assert(active_compute_command_encoder_ != nil);
433 [active_compute_command_encoder_ retain];
434 active_command_encoder_type_ = MTL_COMPUTE_COMMAND_ENCODER;
438 std::string debug_name =
"ComputeCmdEncoder: Unnamed";
439 if (!debug_group_pushed_stack.empty()) {
440 debug_name =
"ComputeCmdEncoder: " + debug_group_pushed_stack.back();
442 active_compute_command_encoder_.label = [NSString stringWithUTF8String:debug_name.c_str()];
446 this->register_encoder_counters();
449 compute_state_.reset_state();
451 BLI_assert(active_compute_command_encoder_ != nil);
452 return active_compute_command_encoder_;
464 current_draw_call_count_++;
465 vertex_submitted_count_ += vertex_submission;
473 current_draw_call_count_ = 0;
475 vertex_submitted_count_ = 0;
482 if (active_command_buffer_ == nil) {
491 return ((current_draw_call_count_ > 30000) || (vertex_submitted_count_ > 100000000) ||
492 (encoder_count_ > 25));
508 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
509 if (![capture_manager isCapturing]) {
513 id<MTLCommandBuffer> cmd = this->ensure_begin();
515 if (active_command_encoder_type_ != MTL_NO_COMMAND_ENCODER) {
519 debug_group_stack.emplace_back(
name);
526 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
527 if (![capture_manager isCapturing]) {
531 id<MTLCommandBuffer> cmd = this->ensure_begin();
533 if (active_command_encoder_type_ != MTL_NO_COMMAND_ENCODER) {
537#if METAL_DEBUG_CAPTURE_HIDE_EMPTY == 0
539 unfold_pending_debug_groups();
543 if (!debug_group_stack.empty()) {
544 debug_group_stack.pop_back();
548 if (!debug_group_pushed_stack.empty()) {
549 debug_group_pushed_stack.pop_back();
559void MTLCommandBufferManager::unfold_pending_debug_groups()
562 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
563 if (![capture_manager isCapturing]) {
567 if (active_command_buffer_ != nil) {
568 for (
const std::string &
name : debug_group_stack) {
570 [active_command_buffer_ pushDebugGroup:[NSString stringWithFormat:
@"%s",
name.c_str()]];
572 debug_group_pushed_stack.push_back(
name);
574 debug_group_stack.clear();
592 if (is_tile_based_arch) {
593 if (active_command_encoder_type_ == MTL_RENDER_COMMAND_ENCODER) {
603 MTLBarrierScope scope = 0;
605 bool is_compute = (active_command_encoder_type_ != MTL_RENDER_COMMAND_ENCODER);
606 scope |= (is_compute ? 0 : MTLBarrierScopeRenderTargets) | MTLBarrierScopeTextures;
612 scope = scope | MTLBarrierScopeBuffers;
617 switch (active_command_encoder_type_) {
618 case MTL_NO_COMMAND_ENCODER:
619 case MTL_BLIT_COMMAND_ENCODER: {
625 case MTL_RENDER_COMMAND_ENCODER: {
628 MTLRenderStages before_stage_flags = 0;
629 MTLRenderStages after_stage_flags = 0;
633 before_stage_flags = before_stage_flags | MTLRenderStageVertex;
636 before_stage_flags = before_stage_flags | MTLRenderStageFragment;
639 after_stage_flags = after_stage_flags | MTLRenderStageVertex;
642 after_stage_flags = MTLRenderStageFragment;
647 [rec memoryBarrierWithScope:scope
648 afterStages:after_stage_flags
649 beforeStages:before_stage_flags];
654 case MTL_COMPUTE_COMMAND_ENCODER: {
657 [rec memoryBarrierWithScope:scope];
669 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
672 [cmd_buf encodeSignalEvent:
event value:signal_value];
673 register_encoder_counters();
679 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
682 [cmd_buf encodeWaitForEvent:
event value:signal_value];
683 register_encoder_counters();
709 (
uint)((
fb !=
nullptr) ?
fb->get_width() : 0),
710 (
uint)((
fb !=
nullptr) ?
fb->get_height() : 0)};
759 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
761 [rec setVertexTexture:tex atIndex:slot];
769 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
771 [rec setFragmentTexture:tex atIndex:slot];
779 id<MTLComputeCommandEncoder> rec = this->
cmd.get_active_compute_command_encoder();
781 [rec setTexture:tex atIndex:slot];
788 bool use_argument_buffer_for_samplers,
794 BLI_assert(slot <= shader_interface->get_max_texture_index());
801 use_argument_buffer_for_samplers)
805 ctx.get_default_sampler_state() :
807 if (!use_argument_buffer_for_samplers) {
809 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
811 [rec setVertexSamplerState:sampler_state atIndex:slot];
818 use_argument_buffer_for_samplers;
822 ctx.samplers_.mtl_sampler[slot] = sampler_state;
828 bool use_argument_buffer_for_samplers,
834 BLI_assert(slot <= shader_interface->get_max_texture_index());
842 use_argument_buffer_for_samplers)
846 ctx.get_default_sampler_state() :
848 if (!use_argument_buffer_for_samplers) {
850 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
852 [rec setFragmentSamplerState:sampler_state atIndex:slot];
859 use_argument_buffer_for_samplers;
863 ctx.samplers_.mtl_sampler[slot] = sampler_state;
869 bool use_argument_buffer_for_samplers,
875 BLI_assert(slot <= shader_interface->get_max_texture_index());
883 use_argument_buffer_for_samplers)
887 ctx.get_default_sampler_state() :
889 if (!use_argument_buffer_for_samplers) {
891 id<MTLComputeCommandEncoder> rec = this->
cmd.get_active_compute_command_encoder();
893 [rec setSamplerState:sampler_state atIndex:slot];
900 use_argument_buffer_for_samplers;
904 ctx.samplers_.mtl_sampler[slot] = sampler_state;
918 if (current_vert_ubo_binding.
offset != buffer_offset ||
922 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
927 [rec setVertexBufferOffset:buffer_offset atIndex:index];
931 [rec setVertexBuffer:buffer offset:buffer_offset atIndex:index];
950 if (current_frag_ubo_binding.
offset != buffer_offset ||
954 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
959 [rec setFragmentBufferOffset:buffer_offset atIndex:index];
963 [rec setFragmentBuffer:buffer offset:buffer_offset atIndex:index];
980 if (current_comp_ubo_binding.
offset != buffer_offset ||
984 id<MTLComputeCommandEncoder> rec = this->
cmd.get_active_compute_command_encoder();
989 [rec setBufferOffset:buffer_offset atIndex:index];
993 [rec setBuffer:buffer offset:buffer_offset atIndex:index];
1011 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
1012 [rec setVertexBytes:bytes
length:
length atIndex:index];
1022 ctx.get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(
length, 256);
1036 id<MTLRenderCommandEncoder> rec = this->
cmd.get_active_render_command_encoder();
1037 [rec setFragmentBytes:bytes
length:
length atIndex:index];
1047 ctx.get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(
length, 256);
1061 id<MTLComputeCommandEncoder> rec = this->
cmd.get_active_compute_command_encoder();
1072 ctx.get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(
length, 256);
1081 id<MTLComputeCommandEncoder> rec = this->
cmd.get_active_compute_command_encoder();
1082 [rec setComputePipelineState:pso];
#define UNUSED_VARS_NDEBUG(...)
@ GPU_BARRIER_SHADER_STORAGE
@ GPU_BARRIER_TEXTURE_FETCH
@ GPU_BARRIER_BUFFER_UPDATE
@ GPU_BARRIER_ELEMENT_ARRAY
@ GPU_BARRIER_SHADER_IMAGE_ACCESS
@ GPU_BARRIER_VERTEX_ATTRIB_ARRAY
@ GPU_BARRIER_STAGE_FRAGMENT
@ GPU_BARRIER_STAGE_VERTEX
unsigned long long int uint64_t
static const int max_command_buffer_count
static MTLBackend * get()
MTLSafeFreeList * get_current_safe_list()
id< MTLBuffer > get_metal_buffer() const
MTLFrameBuffer * get_active_framebuffer()
bool end_active_command_encoder(bool retain_framebuffers=false)
void encode_signal_event(id< MTLEvent > event, uint64_t value)
id< MTLComputeCommandEncoder > get_active_compute_command_encoder()
bool do_break_submission()
void register_draw_counters(int vertex_submission)
void prepare(bool supports_render=true)
void wait_until_active_command_buffers_complete()
id< MTLRenderCommandEncoder > ensure_begin_render_command_encoder(MTLFrameBuffer *ctx_framebuffer, bool force_begin, bool *r_new_pass)
bool is_inside_render_pass()
id< MTLComputeCommandEncoder > ensure_begin_compute_encoder()
bool insert_memory_barrier(GPUBarrier barrier_bits, GPUStageBarrierBits before_stages, GPUStageBarrierBits after_stages)
id< MTLBlitCommandEncoder > ensure_begin_blit_encoder()
void push_debug_group(const char *name, int index)
id< MTLRenderCommandEncoder > get_active_render_command_encoder()
static volatile std::atomic< int > num_active_cmd_bufs_in_system
void encode_wait_for_event(id< MTLEvent > event, uint64_t value)
id< MTLBlitCommandEncoder > get_active_blit_command_encoder()
void bind_compute_bytes(const void *bytes, uint64_t length, uint index)
id< MTLComputePipelineState > bound_pso
void bind_compute_sampler(MTLSamplerBinding &sampler_binding, bool use_argument_buffer_for_samplers, uint slot)
MTLCommandBufferManager & cmd
BufferBindingCached cached_compute_buffer_bindings[MTL_MAX_BUFFER_BINDINGS]
void bind_compute_texture(id< MTLTexture > tex, uint slot)
TextureBindingCached cached_compute_texture_bindings[MTL_MAX_TEXTURE_SLOTS]
void bind_compute_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
void bind_pso(id< MTLComputePipelineState > pso)
SamplerStateBindingCached cached_compute_sampler_state_bindings[MTL_MAX_TEXTURE_SLOTS]
id< MTLCommandQueue > queue
static MTLBufferPool * get_global_memory_manager()
MTLRenderPassDescriptor * bake_render_pass_descriptor(bool load_contents)
void bind_fragment_sampler(MTLSamplerBinding &sampler_binding, bool use_argument_buffer_for_samplers, uint slot)
void bind_fragment_bytes(const void *bytes, uint64_t length, uint index)
SamplerStateBindingCached cached_fragment_sampler_state_bindings[MTL_MAX_TEXTURE_SLOTS]
void bind_vertex_sampler(MTLSamplerBinding &sampler_binding, bool use_argument_buffer_for_samplers, uint slot)
void bind_vertex_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
void bind_vertex_texture(id< MTLTexture > tex, uint slot)
void bind_vertex_bytes(const void *bytes, uint64_t length, uint index)
id< MTLDepthStencilState > bound_ds_state
TextureBindingCached cached_vertex_texture_bindings[MTL_MAX_TEXTURE_SLOTS]
SamplerStateBindingCached cached_vertex_sampler_state_bindings[MTL_MAX_TEXTURE_SLOTS]
MTLScissorRect last_scissor_rect
uint last_used_stencil_ref_value
MTLCommandBufferManager & cmd
BufferBindingCached cached_fragment_buffer_bindings[MTL_MAX_BUFFER_BINDINGS]
id< MTLRenderPipelineState > bound_pso
BufferBindingCached cached_vertex_buffer_bindings[MTL_MAX_BUFFER_BINDINGS]
TextureBindingCached cached_fragment_texture_bindings[MTL_MAX_TEXTURE_SLOTS]
MTLBoundShaderState last_bound_shader_state
void bind_fragment_texture(id< MTLTexture > tex, uint slot)
void bind_fragment_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
void increment_reference()
void decrement_reference()
void ensure_increment_scratch_buffer()
float length(VecOp< float, D >) RET
BLI_INLINE float fb(float length, float L)
static void error(const char *str)
#define MTL_MAX_BUFFER_BINDINGS
#define MTL_MAX_TEXTURE_SLOTS
#define MTL_MAX_SET_BYTES_SIZE
#define METAL_DEBUG_CAPTURE_MAX_NESTED_GROUPS
#define MTL_LOG_WARNING(info,...)
MTLBufferRange MTLTemporaryBuffer
static int sampler_binding(int32_t program, uint32_t uniform_index, int32_t uniform_location, int *sampler_len)
const MTLSamplerState DEFAULT_SAMPLER_STATE
static void init(bNodeTree *, bNode *node)
id< MTLBuffer > metal_buffer
id< MTLBuffer > metal_buffer