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];
81 debug_group_stack.clear();
82 debug_group_pushed_stack.clear();
85 return active_command_buffer_;
92 if (empty_ || active_command_buffer_ == nil) {
98 BLI_assert(active_command_encoder_type_ == MTL_NO_COMMAND_ENCODER);
114 id<MTLCommandBuffer> cmd_buffer_ref = active_command_buffer_;
115 [cmd_buffer_ref retain];
117 [cmd_buffer_ref addCompletedHandler:^(id<MTLCommandBuffer> ) {
123 [cmd_buffer_ref release];
130 [active_command_buffer_ commit];
139 "Maximum number of command buffers in flight. Host will wait until GPU work has "
140 "completed. Consider increasing GHOST_ContextCGL::max_command_buffer_count or reducing "
141 "work fragmentation to better utilize system hardware. Command buffers are flushed upon "
142 "GPUContext switches, this is the most common cause of excessive command buffer "
148 [active_command_buffer_ waitUntilCompleted];
154 NSError *
error = [active_command_buffer_
error];
163 if (last_submitted_command_buffer_ != nil) {
166 [last_submitted_command_buffer_ autorelease];
167 last_submitted_command_buffer_ = nil;
169 last_submitted_command_buffer_ = active_command_buffer_;
170 active_command_buffer_ = nil;
184 return (active_command_encoder_type_ == MTL_RENDER_COMMAND_ENCODER);
189 return (active_command_encoder_type_ == MTL_BLIT_COMMAND_ENCODER);
194 return (active_command_encoder_type_ == MTL_COMPUTE_COMMAND_ENCODER);
200 return active_render_command_encoder_;
206 return active_blit_command_encoder_;
212 return active_compute_command_encoder_;
219 return active_frame_buffer_;
230 if (active_command_encoder_type_ != MTL_NO_COMMAND_ENCODER) {
232 switch (active_command_encoder_type_) {
233 case MTL_RENDER_COMMAND_ENCODER: {
235 BLI_assert(active_render_command_encoder_ != nil);
238 [active_render_command_encoder_ endEncoding];
239 [active_render_command_encoder_ release];
240 active_render_command_encoder_ = nil;
241 active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
244 active_frame_buffer_ =
nullptr;
245 active_pass_descriptor_ =
nullptr;
249 case MTL_BLIT_COMMAND_ENCODER: {
251 BLI_assert(active_blit_command_encoder_ != nil);
252 [active_blit_command_encoder_ endEncoding];
253 [active_blit_command_encoder_ release];
254 active_blit_command_encoder_ = nil;
255 active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
259 case MTL_COMPUTE_COMMAND_ENCODER: {
261 BLI_assert(active_compute_command_encoder_ != nil);
262 [active_compute_command_encoder_ endEncoding];
263 [active_compute_command_encoder_ release];
264 active_compute_command_encoder_ = nil;
265 active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
270 BLI_assert(
false &&
"Invalid command encoder type");
277 BLI_assert(active_render_command_encoder_ == nil);
278 BLI_assert(active_blit_command_encoder_ == nil);
279 BLI_assert(active_compute_command_encoder_ == nil);
285 MTLFrameBuffer *ctx_framebuffer,
bool force_begin,
bool *r_new_pass)
291 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
296 if (active_command_encoder_type_ != MTL_RENDER_COMMAND_ENCODER ||
297 active_frame_buffer_ != ctx_framebuffer || force_begin)
302 bool is_rebind = (active_frame_buffer_ == ctx_framebuffer);
306 active_frame_buffer_ = ctx_framebuffer;
312 this->active_pass_descriptor_.visibilityResultBuffer =
317 BLI_assert(active_render_command_encoder_ == nil);
321 unfold_pending_debug_groups();
325 active_render_command_encoder_ = [cmd_buf
326 renderCommandEncoderWithDescriptor:active_pass_descriptor_];
327 [active_render_command_encoder_ retain];
328 active_command_encoder_type_ = MTL_RENDER_COMMAND_ENCODER;
332 std::string debug_name =
"RenderCmdEncoder: Unnamed";
333 if (!debug_group_pushed_stack.empty()) {
334 debug_name =
"RenderCmdEncoder: " + debug_group_pushed_stack.back();
336 debug_name +=
" (FrameBuffer: " + std::string(active_frame_buffer_->
name_get()) +
")";
337 active_render_command_encoder_.label = [NSString stringWithUTF8String:debug_name.c_str()];
341 this->register_encoder_counters();
362 BLI_assert(active_render_command_encoder_ != nil);
363 return active_render_command_encoder_;
369 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
373 if (active_command_encoder_type_ != MTL_BLIT_COMMAND_ENCODER) {
378 if (active_blit_command_encoder_ == nil) {
381 unfold_pending_debug_groups();
384 active_blit_command_encoder_ = [cmd_buf blitCommandEncoder];
385 BLI_assert(active_blit_command_encoder_ != nil);
386 [active_blit_command_encoder_ retain];
387 active_command_encoder_type_ = MTL_BLIT_COMMAND_ENCODER;
391 std::string debug_name =
"BlitCmdEncoder: Unnamed";
392 if (!debug_group_pushed_stack.empty()) {
393 debug_name =
"BlitCmdEncoder: " + debug_group_pushed_stack.back();
395 active_blit_command_encoder_.label = [NSString stringWithUTF8String:debug_name.c_str()];
399 this->register_encoder_counters();
401 BLI_assert(active_blit_command_encoder_ != nil);
402 return active_blit_command_encoder_;
408 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
412 if (active_command_encoder_type_ != MTL_COMPUTE_COMMAND_ENCODER) {
417 if (active_compute_command_encoder_ == nil) {
420 unfold_pending_debug_groups();
423 active_compute_command_encoder_ = [cmd_buf computeCommandEncoder];
424 BLI_assert(active_compute_command_encoder_ != nil);
425 [active_compute_command_encoder_ retain];
426 active_command_encoder_type_ = MTL_COMPUTE_COMMAND_ENCODER;
430 std::string debug_name =
"ComputeCmdEncoder: Unnamed";
431 if (!debug_group_pushed_stack.empty()) {
432 debug_name =
"ComputeCmdEncoder: " + debug_group_pushed_stack.back();
434 active_compute_command_encoder_.label = [NSString stringWithUTF8String:debug_name.c_str()];
438 this->register_encoder_counters();
443 BLI_assert(active_compute_command_encoder_ != nil);
444 return active_compute_command_encoder_;
456 current_draw_call_count_++;
457 vertex_submitted_count_ += vertex_submission;
465 current_draw_call_count_ = 0;
467 vertex_submitted_count_ = 0;
474 if (active_command_buffer_ == nil) {
483 return ((current_draw_call_count_ > 30000) || (vertex_submitted_count_ > 100000000) ||
484 (encoder_count_ > 25));
502 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
503 if (![capture_manager isCapturing]) {
507 id<MTLCommandBuffer> cmd = this->ensure_begin();
509 if (active_command_encoder_type_ != MTL_NO_COMMAND_ENCODER) {
513 debug_group_stack.push_back(std::string(name));
520 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
521 if (![capture_manager isCapturing]) {
525 id<MTLCommandBuffer> cmd = this->ensure_begin();
527 if (active_command_encoder_type_ != MTL_NO_COMMAND_ENCODER) {
531#if METAL_DEBUG_CAPTURE_HIDE_EMPTY == 0
533 unfold_pending_debug_groups();
537 if (debug_group_stack.size() > 0) {
538 debug_group_stack.pop_back();
542 if (debug_group_pushed_stack.size() > 0) {
543 debug_group_pushed_stack.pop_back();
553void MTLCommandBufferManager::unfold_pending_debug_groups()
556 MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
557 if (![capture_manager isCapturing]) {
561 if (active_command_buffer_ != nil) {
562 for (
const std::string &name : debug_group_stack) {
564 [active_command_buffer_ pushDebugGroup:[NSString stringWithFormat:
@"%s", name.c_str()]];
566 debug_group_pushed_stack.push_back(name);
568 debug_group_stack.clear();
586 if (is_tile_based_arch) {
587 if (active_command_encoder_type_ == MTL_RENDER_COMMAND_ENCODER) {
599 MTLBarrierScope scope = 0;
601 bool is_compute = (active_command_encoder_type_ != MTL_RENDER_COMMAND_ENCODER);
602 scope |= (is_compute ? 0 : MTLBarrierScopeRenderTargets) | MTLBarrierScopeTextures;
608 scope = scope | MTLBarrierScopeBuffers;
613 switch (active_command_encoder_type_) {
614 case MTL_NO_COMMAND_ENCODER:
615 case MTL_BLIT_COMMAND_ENCODER: {
621 case MTL_RENDER_COMMAND_ENCODER: {
624 MTLRenderStages before_stage_flags = 0;
625 MTLRenderStages after_stage_flags = 0;
629 before_stage_flags = before_stage_flags | MTLRenderStageVertex;
632 before_stage_flags = before_stage_flags | MTLRenderStageFragment;
635 after_stage_flags = after_stage_flags | MTLRenderStageVertex;
638 after_stage_flags = MTLRenderStageFragment;
643 [rec memoryBarrierWithScope:scope
644 afterStages:after_stage_flags
645 beforeStages:before_stage_flags];
650 case MTL_COMPUTE_COMMAND_ENCODER: {
653 [rec memoryBarrierWithScope:scope];
665 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
668 [cmd_buf encodeSignalEvent:
event value:signal_value];
669 register_encoder_counters();
675 id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
678 [cmd_buf encodeWaitForEvent:
event value:signal_value];
679 register_encoder_counters();
705 (
uint)((fb !=
nullptr) ?
fb->get_width() : 0),
706 (
uint)((
fb !=
nullptr) ?
fb->get_height() : 0)};
757 [rec setVertexTexture:
tex atIndex:slot];
767 [rec setFragmentTexture:
tex atIndex:slot];
777 [rec setTexture:
tex atIndex:slot];
784 bool use_argument_buffer_for_samplers,
790 BLI_assert(slot <= shader_interface->get_max_texture_index());
797 use_argument_buffer_for_samplers)
803 if (!use_argument_buffer_for_samplers) {
807 [rec setVertexSamplerState:sampler_state atIndex:slot];
814 use_argument_buffer_for_samplers;
824 bool use_argument_buffer_for_samplers,
830 BLI_assert(slot <= shader_interface->get_max_texture_index());
838 use_argument_buffer_for_samplers)
844 if (!use_argument_buffer_for_samplers) {
848 [rec setFragmentSamplerState:sampler_state atIndex:slot];
855 use_argument_buffer_for_samplers;
865 bool use_argument_buffer_for_samplers,
871 BLI_assert(slot <= shader_interface->get_max_texture_index());
879 use_argument_buffer_for_samplers)
885 if (!use_argument_buffer_for_samplers) {
889 [rec setSamplerState:sampler_state atIndex:slot];
896 use_argument_buffer_for_samplers;
914 if (current_vert_ubo_binding.
offset != buffer_offset ||
923 [rec setVertexBufferOffset:buffer_offset atIndex:index];
927 [rec setVertexBuffer:buffer offset:buffer_offset atIndex:index];
946 if (current_frag_ubo_binding.
offset != buffer_offset ||
955 [rec setFragmentBufferOffset:buffer_offset atIndex:index];
959 [rec setFragmentBuffer:buffer offset:buffer_offset atIndex:index];
976 if (current_comp_ubo_binding.
offset != buffer_offset ||
985 [rec setBufferOffset:buffer_offset atIndex:index];
989 [rec setBuffer:buffer offset:buffer_offset atIndex:index];
1008 [rec setVertexBytes:bytes
length:length atIndex:index];
1019 memcpy(range.data, bytes, length);
1033 [rec setFragmentBytes:bytes
length:length atIndex:index];
1044 memcpy(range.data, bytes, length);
1058 [rec setBytes:bytes
length:length atIndex:index];
1069 memcpy(range.data, bytes, length);
1078 [rec setComputePipelineState:pso];
#define UNUSED_VARS_NDEBUG(...)
@ GPU_BARRIER_STAGE_FRAGMENT
@ GPU_BARRIER_STAGE_VERTEX
@ 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
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
static const int max_command_buffer_count
const char *const name_get() const
static MTLBackend * get()
MTLSafeFreeList * get_current_safe_list()
id< MTLBuffer > get_metal_buffer() const
MTLFrameBuffer * get_active_framebuffer()
void encode_signal_event(id< MTLEvent > event, uint64_t value)
id< MTLComputeCommandEncoder > get_active_compute_command_encoder()
bool end_active_command_encoder()
bool do_break_submission()
void register_draw_counters(int vertex_submission)
void prepare(bool supports_render=true)
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(eGPUBarrier barrier_bits, eGPUStageBarrierBits before_stages, eGPUStageBarrierBits after_stages)
static int num_active_cmd_bufs
id< MTLBlitCommandEncoder > ensure_begin_blit_encoder()
void push_debug_group(const char *name, int index)
id< MTLRenderCommandEncoder > get_active_render_command_encoder()
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]
void clear_visibility_dirty()
id< MTLSamplerState > get_sampler_from_state(MTLSamplerState state)
gpu::MTLBuffer * get_visibility_buffer() const
MTLScratchBufferManager memory_manager
MTLContextGlobalShaderPipelineState pipeline_state
id< MTLSamplerState > get_default_sampler_state()
MTLScratchBufferManager & get_scratchbuffer_manager()
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()
MTLTemporaryBuffer scratch_buffer_allocate_range_aligned(uint64_t alloc_size, uint alignment)
void flush_active_scratch_buffer()
void ensure_increment_scratch_buffer()
MTLShaderInterface * get_interface()
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,...)
static int sampler_binding(int32_t program, uint32_t uniform_index, int32_t uniform_location, int *sampler_len)
const MTLSamplerState DEFAULT_SAMPLER_STATE
unsigned __int64 uint64_t
id< MTLBuffer > metal_buffer
void set(MTLShader *shader, uint pso_index)
id< MTLBuffer > metal_buffer
MTLShader * active_shader
MTLSamplerState mtl_sampler_flags[MTL_MAX_TEXTURE_SLOTS]
id< MTLSamplerState > mtl_sampler[MTL_MAX_TEXTURE_SLOTS]
bool is_arg_buffer_binding
MTLSamplerState binding_state
id< MTLSamplerState > sampler_state
id< MTLTexture > metal_texture