Blender V4.3
mtl_context.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#pragma once
9
10#include "MEM_guardedalloc.h"
11
13
14#include "GPU_common_types.hh"
15#include "GPU_context.hh"
16
17/* Don't generate OpenGL deprecation warning. This is a known thing, and is not something easily
18 * solvable in a short term. */
19#ifdef __clang__
20# pragma clang diagnostic ignored "-Wdeprecated-declarations"
21#endif
22
26
27#include "mtl_backend.hh"
28#include "mtl_capabilities.hh"
29#include "mtl_common.hh"
30#include "mtl_framebuffer.hh"
31#include "mtl_memory.hh"
32#include "mtl_shader.hh"
34#include "mtl_texture.hh"
35
36#include <Cocoa/Cocoa.h>
37#include <Metal/Metal.h>
38#include <QuartzCore/QuartzCore.h>
39#include <mutex>
40
41@class CAMetalLayer;
42@class MTLCommandQueue;
43@class MTLRenderPipelineState;
44
45namespace blender::gpu {
46
47/* Forward Declarations */
48class MTLContext;
49class MTLCommandBufferManager;
50class MTLUniformBuf;
51class MTLStorageBuf;
52
53/* Structs containing information on current binding state for textures and samplers. */
58
60 bool used;
62
63 bool operator==(MTLSamplerBinding const &other) const
64 {
65 return (used == other.used && state == other.state);
66 }
67};
68
69/* Caching of resource bindings for active MTLRenderCommandEncoder.
70 * In Metal, resource bindings are local to the MTLCommandEncoder,
71 * not globally to the whole pipeline/cmd buffer. */
73 MTLShader *shader_ = nullptr;
75 void set(MTLShader *shader, uint pso_index)
76 {
77 shader_ = shader;
78 pso_index_ = pso_index;
79 }
80};
81
82/* Caching of CommandEncoder Vertex/Fragment buffer bindings. */
84 /* Whether the given binding slot uses byte data (Push Constant equivalent)
85 * or an MTLBuffer. */
87 id<MTLBuffer> metal_buffer;
89};
90
91/* Caching of CommandEncoder textures bindings. */
93 id<MTLTexture> metal_texture;
94};
95
96/* Cached of CommandEncoder sampler states. */
102
103/* Metal Context Render Pass State -- Used to track active RenderCommandEncoder state based on
104 * bound MTLFrameBuffer's.Owned by MTLContext. */
106 friend class MTLContext;
107
108 public:
109 MTLRenderPassState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager)
110 : ctx(context), cmd(command_buffer_manager){};
111
112 /* Given a RenderPassState is associated with a live RenderCommandEncoder,
113 * this state sits within the MTLCommandBufferManager. */
116
118 id<MTLRenderPipelineState> bound_pso = nil;
119 id<MTLDepthStencilState> bound_ds_state = nil;
121 MTLScissorRect last_scissor_rect;
122
129
130 /* Reset RenderCommandEncoder binding state. */
131 void reset_state();
132
133 /* Texture Binding (RenderCommandEncoder). */
134 void bind_vertex_texture(id<MTLTexture> tex, uint slot);
135 void bind_fragment_texture(id<MTLTexture> tex, uint slot);
136
137 /* Sampler Binding (RenderCommandEncoder). */
139 bool use_argument_buffer_for_samplers,
140 uint slot);
142 bool use_argument_buffer_for_samplers,
143 uint slot);
144
145 /* Buffer binding (RenderCommandEncoder). */
146 void bind_vertex_buffer(id<MTLBuffer> buffer, uint64_t buffer_offset, uint index);
147 void bind_fragment_buffer(id<MTLBuffer> buffer, uint64_t buffer_offset, uint index);
148 void bind_vertex_bytes(const void *bytes, uint64_t length, uint index);
149 void bind_fragment_bytes(const void *bytes, uint64_t length, uint index);
150};
151
152/* Metal Context Compute Pass State -- Used to track active ComputeCommandEncoder state. */
154 friend class MTLContext;
155
156 public:
157 MTLComputeState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager)
158 : ctx(context), cmd(command_buffer_manager){};
159
160 /* Given a ComputePassState is associated with a live ComputeCommandEncoder,
161 * this state sits within the MTLCommandBufferManager. */
164
165 id<MTLComputePipelineState> bound_pso = nil;
169
170 /* Reset ComputeCommandEncoder binding state. */
171 void reset_state();
172
173 /* PSO Binding. */
174 void bind_pso(id<MTLComputePipelineState> pso);
175
176 /* Texture Binding (ComputeCommandEncoder). */
177 void bind_compute_texture(id<MTLTexture> tex, uint slot);
178 /* Sampler Binding (ComputeCommandEncoder). */
180 bool use_argument_buffer_for_samplers,
181 uint slot);
182 /* Buffer binding (ComputeCommandEncoder). */
183 void bind_compute_buffer(id<MTLBuffer> buffer, uint64_t buffer_offset, uint index);
184 void bind_compute_bytes(const void *bytes, uint64_t length, uint index);
185};
186
187/* Depth Stencil State */
189
190 /* Depth State. */
195 MTLCompareFunction depth_function;
201
202 /* Stencil State. */
207 MTLCompareFunction stencil_func;
208
209 MTLStencilOperation stencil_op_front_stencil_fail;
210 MTLStencilOperation stencil_op_front_depth_fail;
212
213 MTLStencilOperation stencil_op_back_stencil_fail;
214 MTLStencilOperation stencil_op_back_depth_fail;
216
217 /* Frame-buffer State -- We need to mark this, in case stencil state remains unchanged,
218 * but attachment state has changed. */
221
222 /* TODO(Metal): Consider optimizing this function using `memcmp`.
223 * Un-used, but differing, stencil state leads to over-generation
224 * of state objects when doing trivial compare. */
226 {
227 bool depth_state_equality = (has_depth_target == other.has_depth_target &&
228 depth_write_enable == other.depth_write_enable &&
229 depth_test_enabled == other.depth_test_enabled &&
230 depth_function == other.depth_function);
231
232 bool stencil_state_equality = true;
233 if (has_stencil_target) {
234 stencil_state_equality =
235 (has_stencil_target == other.has_stencil_target &&
236 stencil_test_enabled == other.stencil_test_enabled &&
237 stencil_op_front_stencil_fail == other.stencil_op_front_stencil_fail &&
238 stencil_op_front_depth_fail == other.stencil_op_front_depth_fail &&
239 stencil_op_front_depthstencil_pass == other.stencil_op_front_depthstencil_pass &&
240 stencil_op_back_stencil_fail == other.stencil_op_back_stencil_fail &&
241 stencil_op_back_depth_fail == other.stencil_op_back_depth_fail &&
242 stencil_op_back_depthstencil_pass == other.stencil_op_back_depthstencil_pass &&
243 stencil_func == other.stencil_func && stencil_read_mask == other.stencil_read_mask &&
244 stencil_write_mask == other.stencil_write_mask);
245 }
246
247 return depth_state_equality && stencil_state_equality;
248 }
249
250 /* Depth stencil state will get hashed in order to prepare
251 * MTLDepthStencilState objects. The hash should comprise of
252 * all elements which fill the MTLDepthStencilDescriptor.
253 * These are bound when [rec setDepthStencilState:...] is called.
254 * Depth bias and stencil reference value are set dynamically on the RenderCommandEncoder:
255 * - setStencilReferenceValue:
256 * - setDepthBias:slopeScale:clamp:
257 */
258 std::size_t hash() const
259 {
260 std::size_t boolean_bitmask = (this->depth_write_enable ? 1 : 0) |
261 ((this->depth_test_enabled ? 1 : 0) << 1) |
262 ((this->depth_bias_enabled_for_points ? 1 : 0) << 2) |
263 ((this->depth_bias_enabled_for_lines ? 1 : 0) << 3) |
264 ((this->depth_bias_enabled_for_tris ? 1 : 0) << 4) |
265 ((this->stencil_test_enabled ? 1 : 0) << 5) |
266 ((this->has_depth_target ? 1 : 0) << 6) |
267 ((this->has_stencil_target ? 1 : 0) << 7);
268
269 std::size_t stencilop_bitmask = ((std::size_t)this->stencil_op_front_stencil_fail) |
270 ((std::size_t)this->stencil_op_front_depth_fail << 3) |
271 ((std::size_t)this->stencil_op_front_depthstencil_pass << 6) |
272 ((std::size_t)this->stencil_op_back_stencil_fail << 9) |
273 ((std::size_t)this->stencil_op_back_depth_fail << 12) |
274 ((std::size_t)this->stencil_op_back_depthstencil_pass << 15);
275
276 std::size_t main_hash = (std::size_t)this->depth_function;
277 if (this->has_stencil_target) {
278 main_hash += (std::size_t)(this->stencil_read_mask & 0xFF) << 8;
279 main_hash += (std::size_t)(this->stencil_write_mask & 0xFF) << 16;
280 }
281 main_hash ^= (std::size_t)this->stencil_func << 16;
282 main_hash ^= stencilop_bitmask;
283
284 std::size_t final_hash = (main_hash << 8) | boolean_bitmask;
285 return final_hash;
286 }
287};
288
290
291 /* Depth Update Utilities */
292 /* Depth texture updates are not directly supported with Blit operations, similarly, we cannot
293 * use a compute shader to write to depth, so we must instead render to a depth target.
294 * These processes use vertex/fragment shaders to render texture data from an intermediate
295 * source, in order to prime the depth buffer. */
298
299 /* Texture Read/Update routines */
316
333
334 template<typename T> void free_cached_pso_map(blender::Map<T, id<MTLComputePipelineState>> &map)
335 {
336 for (typename blender::MutableMapItem<T, id<MTLComputePipelineState>> item : map.items()) {
337 [item.value release];
338 }
339 map.clear();
340 }
341
342 void init()
343 {
344 fullscreen_blit_shader = nullptr;
345 }
346
378};
379
381 private:
382 id<MTLComputePipelineState> buffer_clear_pso_ = nil;
383
384 public:
385 id<MTLComputePipelineState> get_buffer_clear_pso();
386 void cleanup()
387 {
388 if (buffer_clear_pso_) {
389 [buffer_clear_pso_ release];
390 buffer_clear_pso_ = nil;
391 }
392 }
393};
394
395/* Combined sampler state configuration for Argument Buffer caching. */
398 /* MTLSamplerState permutations between 0..256 - slightly more than a byte. */
400 id<MTLSamplerState> mtl_sampler[MTL_MAX_TEXTURE_SLOTS];
401
402 bool operator==(const MTLSamplerArray &other) const
403 {
404 if (this->num_samplers != other.num_samplers) {
405 return false;
406 }
407 return (memcmp(this->mtl_sampler_flags,
408 other.mtl_sampler_flags,
409 sizeof(MTLSamplerState) * this->num_samplers) == 0);
410 }
411
413 {
414 uint32_t hash = this->num_samplers;
415 for (int i = 0; i < this->num_samplers; i++) {
416 hash ^= uint32_t(this->mtl_sampler_flags[i]) << (i % 3);
417 }
418 return hash;
419 }
420};
421
424 /* Whether we need to call setViewport. */
426 /* Whether we need to call setScissor. */
428 /* Whether we need to update/rebind active depth stencil state. */
430 /* Whether we need to update/rebind active PSO. */
432 /* Whether we need to update the frontFacingWinding state. */
434 /* Whether we need to update the culling state. */
436 /* Full pipeline state needs applying. Occurs when beginning a new render pass. */
442
443/* Ignore full flag bit-mask `MTL_PIPELINE_STATE_ALL_FLAG`. */
445
450
455
458
459 /* Whether the pipeline state has been modified since application.
460 * `dirty_flags` is a bitmask of the types of state which have been updated.
461 * This is in order to optimize calls and only re-apply state as needed.
462 * Some state parameters are dynamically applied on the RenderCommandEncoder,
463 * others may be encapsulated in GPU-resident state objects such as
464 * MTLDepthStencilState or MTLRenderPipelineState. */
465 bool dirty;
467
468 /* Shader resources. */
470
471 /* Active Shader State. */
473
474 /* Global Uniform Buffers. */
476
477 /* Storage buffer. */
479
480 /* Context Texture bindings. */
483
484 /* Image bindings. */
486
487 /*** --- Render Pipeline State --- ***/
488 /* Track global render pipeline state for the current context. The functions in GPU_state.hh
489 * modify these parameters. Certain values, tagged [PSO], are parameters which are required to be
490 * passed into PSO creation, rather than dynamic state functions on the RenderCommandEncoder.
491 */
492
493 /* Blending State. */
494 MTLColorWriteMask color_write_mask; /* [PSO] */
495 bool blending_enabled; /* [PSO] */
496 MTLBlendOperation alpha_blend_op; /* [PSO] */
497 MTLBlendOperation rgb_blend_op; /* [PSO] */
498 MTLBlendFactor dest_alpha_blend_factor; /* [PSO] */
499 MTLBlendFactor dest_rgb_blend_factor; /* [PSO] */
500 MTLBlendFactor src_alpha_blend_factor; /* [PSO] */
501 MTLBlendFactor src_rgb_blend_factor; /* [PSO] */
502
503 /* Culling State. */
507
508 /* Depth State. */
510
511 /* Viewport/Scissor Region. */
522
523 /* Image data access state. */
525
526 /* Render parameters. */
527 float point_size = 1.0f;
528 float line_width = 1.0f;
529
530 /* Clipping plane enablement. */
531 bool clip_distance_enabled[6] = {false};
532};
533
534/* Command Buffer Manager - Owned by MTLContext.
535 * The MTLCommandBufferManager represents all work associated with
536 * a command buffer of a given identity. This manager is a fixed-state
537 * on the context, which coordinates the lifetime of command buffers
538 * for particular categories of work.
539 *
540 * This ensures operations on command buffers, and the state associated,
541 * is correctly tracked and managed. Workload submission and MTLCommandEncoder
542 * coordination is managed from here.
543 *
544 * There is currently only one MTLCommandBufferManager for managing submission
545 * of the "main" rendering commands. A secondary upload command buffer track,
546 * or asynchronous compute command buffer track may be added in the future. */
548 friend class MTLContext;
549
550 public:
551 /* Counter for active command buffers. */
553
554 private:
555 /* Associated Context and properties. */
556 MTLContext &context_;
557 bool supports_render_ = false;
558
559 /* CommandBuffer tracking. */
560 id<MTLCommandBuffer> active_command_buffer_ = nil;
561 id<MTLCommandBuffer> last_submitted_command_buffer_ = nil;
562
563 /* Active MTLCommandEncoders. */
564 enum {
565 MTL_NO_COMMAND_ENCODER = 0,
566 MTL_RENDER_COMMAND_ENCODER = 1,
567 MTL_BLIT_COMMAND_ENCODER = 2,
568 MTL_COMPUTE_COMMAND_ENCODER = 3
569 } active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
570
571 id<MTLRenderCommandEncoder> active_render_command_encoder_ = nil;
572 id<MTLBlitCommandEncoder> active_blit_command_encoder_ = nil;
573 id<MTLComputeCommandEncoder> active_compute_command_encoder_ = nil;
574
575 /* State associated with active RenderCommandEncoder. */
576 MTLRenderPassState render_pass_state_;
577 MTLFrameBuffer *active_frame_buffer_ = nullptr;
578 MTLRenderPassDescriptor *active_pass_descriptor_ = nullptr;
579
580 /* State associated with active ComputeCommandEncoder. */
581 MTLComputeState compute_state_;
582
583 /* Workload heuristics - We may need to split command buffers to optimize workload and balancing.
584 */
585 int current_draw_call_count_ = 0;
586 int encoder_count_ = 0;
587 int vertex_submitted_count_ = 0;
588 bool empty_ = true;
589
591 /* Stack tracking all calls to push_debug_group. */
592 std::vector<std::string> debug_group_stack;
593 /* Stack tracking calls resulting in active API calls to pushDebugGroup on the current command
594 * buffer. */
595 std::vector<std::string> debug_group_pushed_stack;
596
597 public:
599 : context_(context), render_pass_state_(context, *this), compute_state_(context, *this){};
600 void prepare(bool supports_render = true);
601
602 /* If wait is true, CPU will stall until GPU work has completed. */
603 bool submit(bool wait);
604
605 /* Fetch/query current encoder. */
607 bool is_inside_blit();
608 bool is_inside_compute();
609 id<MTLRenderCommandEncoder> get_active_render_command_encoder();
610 id<MTLBlitCommandEncoder> get_active_blit_command_encoder();
611 id<MTLComputeCommandEncoder> get_active_compute_command_encoder();
613
614 /* RenderPassState for RenderCommandEncoder. */
616 {
617 /* Render pass state should only be valid if we are inside a render pass. */
619 return render_pass_state_;
620 }
621
622 /* RenderPassState for RenderCommandEncoder. */
624 {
625 /* Render pass state should only be valid if we are inside a compute encoder. */
627 return compute_state_;
628 }
629
630 /* Rendering Heuristics. */
631 void register_draw_counters(int vertex_submission);
632 void reset_counters();
633 bool do_break_submission();
634
635 /* Encoder and Pass management. */
636 /* End currently active MTLCommandEncoder. */
638 id<MTLRenderCommandEncoder> ensure_begin_render_command_encoder(MTLFrameBuffer *ctx_framebuffer,
639 bool force_begin,
640 bool *r_new_pass);
641 id<MTLBlitCommandEncoder> ensure_begin_blit_encoder();
642 id<MTLComputeCommandEncoder> ensure_begin_compute_encoder();
643
644 /* Workload Synchronization. */
645 bool insert_memory_barrier(eGPUBarrier barrier_bits,
646 eGPUStageBarrierBits before_stages,
647 eGPUStageBarrierBits after_stages);
648 void encode_signal_event(id<MTLEvent> event, uint64_t value);
649 void encode_wait_for_event(id<MTLEvent> event, uint64_t value);
650 /* TODO(Metal): Support fences in command buffer class. */
651
652 /* Debug. */
653 void push_debug_group(const char *name, int index);
654 void pop_debug_group();
655
656 private:
657 /* Begin new command buffer. */
658 id<MTLCommandBuffer> ensure_begin();
659
660 void register_encoder_counters();
661
662 /* Debug group management. */
663 void unfold_pending_debug_groups();
664};
665
672class MTLContext : public Context {
673 friend class MTLBackend;
674 friend class MTLRenderPassState;
675 friend class MTLComputeState;
676
677 public:
678 /* Swap-chain and latency management. */
679 static std::atomic<int> max_drawables_in_flight;
680 static std::atomic<int64_t> avg_drawable_latency_us;
682
683 public:
684 /* Shaders and Pipeline state. */
686
687 /* Metal API Resource Handles. */
688 id<MTLCommandQueue> queue = nil;
689 id<MTLDevice> device = nil;
690
691#ifndef NDEBUG
692 /* Label for Context debug name assignment. */
693 NSString *label = nil;
694#endif
695
696 /* Memory Management. */
701
702 /* CommandBuffer managers. */
704
705 private:
706 /* Parent Context. */
707 GHOST_ContextCGL *ghost_context_;
708
709 /* Render Passes and Frame-buffers. */
710 id<MTLTexture> default_fbo_mtltexture_ = nil;
711 gpu::MTLTexture *default_fbo_gputexture_ = nullptr;
712
713 /* Depth-stencil state cache. */
715
716 /* Compute and specialization caches. */
717 MTLContextTextureUtils texture_utils_;
718 MTLContextComputeUtils compute_utils_;
719
720 /* Texture Samplers. */
721 /* Cache of generated #MTLSamplerState objects based on permutations of the members of
722 * `GPUSamplerState`. */
723 id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_EXTEND_MODES_COUNT]
726 id<MTLSamplerState> custom_sampler_state_cache_[GPU_SAMPLER_CUSTOM_TYPES_COUNT];
727 id<MTLSamplerState> default_sampler_state_ = nil;
728
729 /* When texture sampler count exceeds the resource bind limit, an
730 * argument buffer is used to pass samplers to the shader.
731 * Each unique configurations of multiple samplers can be cached, so as to not require
732 * re-generation. `samplers_` stores the current list of bound sampler objects.
733 * `cached_sampler_buffers_` is a cache of encoded argument buffers which can be re-used. */
734 MTLSamplerArray samplers_;
736
737 /* Frame. */
738 bool is_inside_frame_ = false;
739 uint current_frame_index_;
740
741 /* Visibility buffer for MTLQuery results. */
742 gpu::MTLBuffer *visibility_buffer_ = nullptr;
743 bool visibility_is_dirty_ = false;
744
745 /* Null buffers for empty/uninitialized bindings.
746 * Null attribute buffer follows default attribute format of OpenGL Backend. */
747 id<MTLBuffer> null_buffer_; /* All zero's. */
748 id<MTLBuffer> null_attribute_buffer_; /* Value float4(0.0,0.0,0.0,1.0). */
749
751 /* Maximum of 32 texture types. Though most combinations invalid. */
752 gpu::MTLTexture *dummy_textures_[GPU_SAMPLER_TYPE_MAX][GPU_TEXTURE_BUFFER] = {{nullptr}};
753 GPUVertFormat dummy_vertformat_[GPU_SAMPLER_TYPE_MAX];
754 VertBuf *dummy_verts_[GPU_SAMPLER_TYPE_MAX] = {nullptr};
755
756 public:
757 /* GPUContext interface. */
758 MTLContext(void *ghost_window, void *ghost_context);
759 ~MTLContext();
760
761 static void check_error(const char *info);
762
763 void activate() override;
764 void deactivate() override;
765 void begin_frame() override;
766 void end_frame() override;
767
768 void flush() override;
769 void finish() override;
770
771 void memory_statistics_get(int *r_total_mem, int *r_free_mem) override;
772
773 static MTLContext *get()
774 {
775 return static_cast<MTLContext *>(Context::get());
776 }
777
778 void debug_group_begin(const char *name, int index) override;
779 void debug_group_end() override;
780 bool debug_capture_begin(const char *title) override;
781 void debug_capture_end() override;
782 void *debug_capture_scope_create(const char *name) override;
783 bool debug_capture_scope_begin(void *scope) override;
784 void debug_capture_scope_end(void *scope) override;
785
786 void debug_unbind_all_ubo() override{};
787 void debug_unbind_all_ssbo() override{};
788
789 /*** MTLContext Utility functions. */
790 /*
791 * All below functions modify the global state for the context, controlling the flow of
792 * rendering, binding resources, setting global state, resource management etc;
793 */
794
797 /* Bind frame-buffer to context. */
798 void framebuffer_bind(MTLFrameBuffer *framebuffer);
799
800 /* Restore frame-buffer used by active context to default back-buffer. */
801 void framebuffer_restore();
802
803 /* Ensure a render-pass using the Context frame-buffer (active_fb_) is in progress. */
804 id<MTLRenderCommandEncoder> ensure_begin_render_pass();
805
808
809 /* Context Global-State Texture Binding. */
810 void texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit, bool is_image);
811 void sampler_bind(MTLSamplerState, uint sampler_unit);
812 void texture_unbind(gpu::MTLTexture *mtl_texture, bool is_image);
813 void texture_unbind_all(bool is_image);
815 id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state);
816 id<MTLSamplerState> get_default_sampler_state();
817
818 /* Metal Context pipeline state. */
819 void pipeline_state_init();
821
822 /* These functions ensure that the current RenderCommandEncoder has
823 * the correct global state assigned. This should be called prior
824 * to every draw call, to ensure that all state is applied and up
825 * to date. We handle:
826 *
827 * - Buffer bindings (Vertex buffers, Uniforms, UBOs, transform feedback)
828 * - Texture bindings
829 * - Sampler bindings (+ argument buffer bindings)
830 * - Dynamic Render pipeline state (on encoder)
831 * - Baking Pipeline State Objects (PSOs) for current shader, based
832 * on final pipeline state.
833 *
834 * `ensure_render_pipeline_state` will return false if the state is
835 * invalid and cannot be applied. This should cancel a draw call. */
836 bool ensure_render_pipeline_state(MTLPrimitiveType prim_type);
837 bool ensure_buffer_bindings(id<MTLRenderCommandEncoder> rec,
838 const MTLShaderInterface *shader_interface,
839 const MTLRenderPipelineStateInstance *pipeline_state_instance);
840 bool ensure_buffer_bindings(id<MTLComputeCommandEncoder> rec,
841 const MTLShaderInterface *shader_interface,
842 const MTLComputePipelineStateInstance *pipeline_state_instance);
843 void ensure_texture_bindings(id<MTLRenderCommandEncoder> rec,
844 MTLShaderInterface *shader_interface,
845 const MTLRenderPipelineStateInstance *pipeline_state_instance);
846 void ensure_texture_bindings(id<MTLComputeCommandEncoder> rec,
847 MTLShaderInterface *shader_interface,
848 const MTLComputePipelineStateInstance *pipeline_state_instance);
849 void ensure_depth_stencil_state(MTLPrimitiveType prim_type);
850
851 id<MTLBuffer> get_null_buffer();
852 id<MTLBuffer> get_null_attribute_buffer();
855
856 /* Compute. */
857 /* Ensure compute pipeline state for current config is compiled and return PSO instance. */
859 void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len);
860 void compute_dispatch_indirect(StorageBuf *indirect_buf);
861
862 /* State assignment. */
863 void set_viewport(int origin_x, int origin_y, int width, int height);
864 void set_viewports(int count, const int (&viewports)[GPU_MAX_VIEWPORTS][4]);
865 void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height);
866 void set_scissor_enabled(bool scissor_enabled);
867
868 /* Visibility buffer control. */
871
872 /* Flag whether the visibility buffer for query results
873 * has changed. This requires a new RenderPass in order
874 * to update. */
875 bool is_visibility_dirty() const;
876
877 /* Reset dirty flag state for visibility buffer. */
879
880 /* Texture utilities. */
882 {
883 return texture_utils_;
884 }
885
886 /* Compute utilities. */
888 {
889 return compute_utils_;
890 }
891
893 {
894 return is_active_;
895 }
896
898 {
899 return is_inside_frame_;
900 }
901
903 {
904 return current_frame_index_;
905 }
906
911
922
936
942
943 /* Swap-chain and latency management. */
944 static void latency_resolve_average(int64_t frame_latency_us)
945 {
946 int64_t avg = 0;
947 int64_t frame_c = 0;
948 for (int i = MTL_FRAME_AVERAGE_COUNT - 1; i > 0; i--) {
951 frame_c += (MTLContext::frame_latency[i] > 0) ? 1 : 0;
952 }
953 MTLContext::frame_latency[0] = frame_latency_us;
955 if (frame_c > 0) {
956 avg /= frame_c;
957 }
958 else {
959 avg = 0;
960 }
962 }
963
964 private:
965 void set_ghost_context(GHOST_ContextHandle ghostCtxHandle);
966 void set_ghost_window(GHOST_WindowHandle ghostWinHandle);
967};
968
969/* GHOST Context callback and present. */
970void present(MTLRenderPassDescriptor *blit_descriptor,
971 id<MTLRenderPipelineState> blit_pso,
972 id<MTLTexture> swapchain_texture,
973 id<CAMetalDrawable> drawable);
974
975} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:50
unsigned int uint
#define ENUM_OPERATORS(_type, _max)
eGPUFrontFace
#define GPU_MAX_VIEWPORTS
void GPU_shader_free(GPUShader *shader)
eGPUStageBarrierBits
Definition GPU_state.hh:65
eGPUFaceCullTest
Definition GPU_state.hh:132
eGPUBarrier
Definition GPU_state.hh:29
static const int GPU_SAMPLER_FILTERING_TYPES_COUNT
#define GPU_SAMPLER_CUSTOM_TYPES_COUNT
#define GPU_SAMPLER_EXTEND_MODES_COUNT
Read Guarded memory(de)allocation.
struct GPUShader GPUShader
void clear()
Definition BLI_map.hh:989
ItemIterator items() const
Definition BLI_map.hh:864
static Context * get()
void encode_signal_event(id< MTLEvent > event, uint64_t value)
id< MTLComputeCommandEncoder > get_active_compute_command_encoder()
MTLCommandBufferManager(MTLContext &context)
void register_draw_counters(int vertex_submission)
void prepare(bool supports_render=true)
MTLRenderPassState & get_render_pass_state()
id< MTLRenderCommandEncoder > ensure_begin_render_command_encoder(MTLFrameBuffer *ctx_framebuffer, bool force_begin, bool *r_new_pass)
id< MTLComputeCommandEncoder > ensure_begin_compute_encoder()
bool insert_memory_barrier(eGPUBarrier barrier_bits, eGPUStageBarrierBits before_stages, eGPUStageBarrierBits after_stages)
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()
MTLComputeState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager)
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< MTLComputePipelineState > get_buffer_clear_pso()
bool ensure_render_pipeline_state(MTLPrimitiveType prim_type)
MTLFrameBuffer * get_current_framebuffer()
MTLFrameBuffer * get_default_framebuffer()
static std::atomic< int64_t > avg_drawable_latency_us
MTLContextComputeUtils & get_compute_utils()
const MTLComputePipelineStateInstance * ensure_compute_pipeline_state()
id< MTLSamplerState > get_sampler_from_state(MTLSamplerState state)
MTLContext(void *ghost_window, void *ghost_context)
void deactivate() override
static void latency_resolve_average(int64_t frame_latency_us)
gpu::MTLBuffer * get_visibility_buffer() const
void debug_unbind_all_ubo() override
void set_visibility_buffer(gpu::MTLBuffer *buffer)
void set_scissor_enabled(bool scissor_enabled)
void framebuffer_bind(MTLFrameBuffer *framebuffer)
id< MTLRenderCommandEncoder > ensure_begin_render_pass()
static MTLContext * get()
id< MTLBuffer > get_null_buffer()
id< MTLBuffer > get_null_attribute_buffer()
static void global_memory_manager_release_ref()
void activate() override
MTLScratchBufferManager memory_manager
MTLContextGlobalShaderPipelineState pipeline_state
void ensure_depth_stencil_state(MTLPrimitiveType prim_type)
bool debug_capture_begin(const char *title) override
Definition mtl_debug.mm:62
void * debug_capture_scope_create(const char *name) override
Definition mtl_debug.mm:89
void debug_capture_scope_end(void *scope) override
Definition mtl_debug.mm:114
static MTLBufferPool * global_memory_manager
void end_frame() override
static int global_memory_manager_refcount
MTLShader * get_active_shader()
void set_viewport(int origin_x, int origin_y, int width, int height)
static int64_t frame_latency[MTL_FRAME_AVERAGE_COUNT]
static std::mutex global_memory_manager_reflock
void sampler_bind(MTLSamplerState, uint sampler_unit)
void texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit, bool is_image)
gpu::MTLTexture * get_dummy_texture(eGPUTextureType type, eGPUSamplerFormat sampler_format)
void begin_frame() override
void set_viewports(int count, const int(&viewports)[GPU_MAX_VIEWPORTS][4])
void ensure_texture_bindings(id< MTLRenderCommandEncoder > rec, MTLShaderInterface *shader_interface, const MTLRenderPipelineStateInstance *pipeline_state_instance)
void compute_dispatch_indirect(StorageBuf *indirect_buf)
void debug_group_begin(const char *name, int index) override
Definition mtl_debug.mm:48
static void check_error(const char *info)
void texture_unbind(gpu::MTLTexture *mtl_texture, bool is_image)
void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height)
bool debug_capture_scope_begin(void *scope) override
Definition mtl_debug.mm:104
MTLCommandBufferManager main_command_buffer
void debug_group_end() override
Definition mtl_debug.mm:55
id< MTLSamplerState > get_default_sampler_state()
bool is_visibility_dirty() const
void texture_unbind_all(bool is_image)
static void global_memory_manager_acquire_ref()
void memory_statistics_get(int *r_total_mem, int *r_free_mem) override
bool ensure_buffer_bindings(id< MTLRenderCommandEncoder > rec, const MTLShaderInterface *shader_interface, const MTLRenderPipelineStateInstance *pipeline_state_instance)
MTLScratchBufferManager & get_scratchbuffer_manager()
void debug_unbind_all_ssbo() override
void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len)
MTLContextTextureUtils & get_texture_utils()
static MTLBufferPool * get_global_memory_manager()
void debug_capture_end() override
Definition mtl_debug.mm:79
static std::atomic< int > max_drawables_in_flight
MTLRenderPassState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager)
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]
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)
int count
static ulong state[N]
#define MTL_MAX_SAMPLER_SLOTS
#define MTL_MAX_BUFFER_BINDINGS
#define MTL_MAX_TEXTURE_SLOTS
#define MTL_FRAME_AVERAGE_COUNT
Definition mtl_common.hh:10
void present(MTLRenderPassDescriptor *blit_descriptor, id< MTLRenderPipelineState > blit_pso, id< MTLTexture > swapchain_texture, id< CAMetalDrawable > drawable)
static int sampler_binding(int32_t program, uint32_t uniform_index, int32_t uniform_location, int *sampler_len)
@ MTL_PIPELINE_STATE_CULLMODE_FLAG
@ MTL_PIPELINE_STATE_PSO_FLAG
@ MTL_PIPELINE_STATE_SCISSOR_FLAG
@ MTL_PIPELINE_STATE_FRONT_FACING_FLAG
@ MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG
@ MTL_PIPELINE_STATE_NULL_FLAG
@ MTL_PIPELINE_STATE_VIEWPORT_FLAG
@ MTL_PIPELINE_STATE_ALL_FLAG
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
unsigned __int64 uint64_t
Definition stdint.h:90
void set(MTLShader *shader, uint pso_index)
bool operator==(const MTLContextDepthStencilState &other) const
MTLStencilOperation stencil_op_back_depthstencil_pass
MTLStencilOperation stencil_op_front_stencil_fail
MTLStencilOperation stencil_op_front_depthstencil_pass
MTLStorageBufferBinding ssbo_bindings[MTL_MAX_BUFFER_BINDINGS]
MTLTextureBinding texture_bindings[MTL_MAX_TEXTURE_SLOTS]
MTLUniformBufferBinding ubo_bindings[MTL_MAX_BUFFER_BINDINGS]
MTLTextureBinding image_bindings[MTL_MAX_TEXTURE_SLOTS]
MTLSamplerBinding sampler_bindings[MTL_MAX_SAMPLER_SLOTS]
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_1d_array_read_compute_psos
void free_cached_pso_map(blender::Map< T, id< MTLComputePipelineState > > &map)
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_cube_update_compute_psos
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_3d_update_compute_psos
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_1d_update_compute_psos
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_3d_read_compute_psos
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_cube_read_compute_psos
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_1d_array_update_compute_psos
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_1d_read_compute_psos
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_buffer_read_compute_psos
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_2d_array_update_compute_psos
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_buffer_update_compute_psos
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_2d_array_read_compute_psos
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_2d_read_compute_psos
blender::Map< DepthTextureUpdateRoutineSpecialisation, GPUShader * > depth_2d_update_shaders
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_cube_array_update_compute_psos
blender::Map< TextureReadRoutineSpecialisation, id< MTLComputePipelineState > > texture_cube_array_read_compute_psos
blender::Map< TextureUpdateRoutineSpecialisation, id< MTLComputePipelineState > > texture_2d_update_compute_psos
MTLSamplerState mtl_sampler_flags[MTL_MAX_TEXTURE_SLOTS]
bool operator==(const MTLSamplerArray &other) const
id< MTLSamplerState > mtl_sampler[MTL_MAX_TEXTURE_SLOTS]
bool operator==(MTLSamplerBinding const &other) const
gpu::MTLTexture * texture_resource