Blender V5.0
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
11
12#include "GPU_common_types.hh"
13
14/* Don't generate OpenGL deprecation warning. This is a known thing, and is not something easily
15 * solvable in a short term. */
16#ifdef __clang__
17# pragma clang diagnostic ignored "-Wdeprecated-declarations"
18#endif
19
23
24#include "mtl_backend.hh"
25#include "mtl_capabilities.hh"
26#include "mtl_common.hh"
27#include "mtl_framebuffer.hh"
28#include "mtl_memory.hh"
29#include "mtl_shader.hh"
31#include "mtl_texture.hh"
32
33#include <Cocoa/Cocoa.h>
34#include <Metal/Metal.h>
35#include <QuartzCore/QuartzCore.h>
36#include <chrono>
37#include <mutex>
38
39@class CAMetalLayer;
40@class MTLCommandQueue;
41@class MTLRenderPipelineState;
42
43namespace blender::gpu {
44
45/* Forward Declarations */
46class MTLContext;
48class MTLUniformBuf;
49class MTLStorageBuf;
50
51/* Structs containing information on current binding state for textures and samplers. */
56
58 bool used;
60
61 bool operator==(MTLSamplerBinding const &other) const
62 {
63 return (used == other.used && state == other.state);
64 }
65};
66
67/* Caching of resource bindings for active MTLRenderCommandEncoder.
68 * In Metal, resource bindings are local to the MTLCommandEncoder,
69 * not globally to the whole pipeline/cmd buffer. */
71 MTLShader *shader_ = nullptr;
73 void set(MTLShader *shader, uint pso_index)
74 {
76 pso_index_ = pso_index;
77 }
78};
79
80/* Caching of CommandEncoder Vertex/Fragment buffer bindings. */
82 /* Whether the given binding slot uses byte data (Push Constant equivalent)
83 * or an MTLBuffer. */
85 id<MTLBuffer> metal_buffer;
87};
88
89/* Caching of CommandEncoder textures bindings. */
91 id<MTLTexture> metal_texture;
92};
93
94/* Cached of CommandEncoder sampler states. */
100
101/* Metal Context Render Pass State -- Used to track active RenderCommandEncoder state based on
102 * bound MTLFrameBuffer's.Owned by MTLContext. */
104 friend class MTLContext;
105
106 public:
107 MTLRenderPassState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager)
108 : ctx(context), cmd(command_buffer_manager) {};
109
110 /* Given a RenderPassState is associated with a live RenderCommandEncoder,
111 * this state sits within the MTLCommandBufferManager. */
114
116 id<MTLRenderPipelineState> bound_pso = nil;
117 id<MTLDepthStencilState> bound_ds_state = nil;
119 MTLScissorRect last_scissor_rect;
120
127
128 /* Reset RenderCommandEncoder binding state. */
129 void reset_state();
130
131 /* Texture Binding (RenderCommandEncoder). */
132 void bind_vertex_texture(id<MTLTexture> tex, uint slot);
133 void bind_fragment_texture(id<MTLTexture> tex, uint slot);
134
135 /* Sampler Binding (RenderCommandEncoder). */
137 bool use_argument_buffer_for_samplers,
138 uint slot);
140 bool use_argument_buffer_for_samplers,
141 uint slot);
142
143 /* Buffer binding (RenderCommandEncoder). */
144 void bind_vertex_buffer(id<MTLBuffer> buffer, uint64_t buffer_offset, uint index);
145 void bind_fragment_buffer(id<MTLBuffer> buffer, uint64_t buffer_offset, uint index);
146 void bind_vertex_bytes(const void *bytes, uint64_t length, uint index);
147 void bind_fragment_bytes(const void *bytes, uint64_t length, uint index);
148};
149
150/* Metal Context Compute Pass State -- Used to track active ComputeCommandEncoder state. */
152 friend class MTLContext;
153
154 public:
155 MTLComputeState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager)
156 : ctx(context), cmd(command_buffer_manager) {};
157
158 /* Given a ComputePassState is associated with a live ComputeCommandEncoder,
159 * this state sits within the MTLCommandBufferManager. */
162
163 id<MTLComputePipelineState> bound_pso = nil;
167
168 /* Reset ComputeCommandEncoder binding state. */
169 void reset_state();
170
171 /* PSO Binding. */
172 void bind_pso(id<MTLComputePipelineState> pso);
173
174 /* Texture Binding (ComputeCommandEncoder). */
175 void bind_compute_texture(id<MTLTexture> tex, uint slot);
176 /* Sampler Binding (ComputeCommandEncoder). */
178 bool use_argument_buffer_for_samplers,
179 uint slot);
180 /* Buffer binding (ComputeCommandEncoder). */
181 void bind_compute_buffer(id<MTLBuffer> buffer, uint64_t buffer_offset, uint index);
182 void bind_compute_bytes(const void *bytes, uint64_t length, uint index);
183};
184
185/* Depth Stencil State */
187
188 /* Depth State. */
193 MTLCompareFunction depth_function;
199
200 /* Stencil State. */
205 MTLCompareFunction stencil_func;
206
207 MTLStencilOperation stencil_op_front_stencil_fail;
208 MTLStencilOperation stencil_op_front_depth_fail;
210
211 MTLStencilOperation stencil_op_back_stencil_fail;
212 MTLStencilOperation stencil_op_back_depth_fail;
214
215 /* Frame-buffer State -- We need to mark this, in case stencil state remains unchanged,
216 * but attachment state has changed. */
219
220 /* TODO(Metal): Consider optimizing this function using `memcmp`.
221 * Un-used, but differing, stencil state leads to over-generation
222 * of state objects when doing trivial compare. */
224 {
225 bool depth_state_equality = (has_depth_target == other.has_depth_target &&
229
230 bool stencil_state_equality = true;
231 if (has_stencil_target) {
232 stencil_state_equality =
243 }
244
245 return depth_state_equality && stencil_state_equality;
246 }
247
248 /* Depth stencil state will get hashed in order to prepare
249 * MTLDepthStencilState objects. The hash should comprise of
250 * all elements which fill the MTLDepthStencilDescriptor.
251 * These are bound when [rec setDepthStencilState:...] is called.
252 * Depth bias and stencil reference value are set dynamically on the RenderCommandEncoder:
253 * - setStencilReferenceValue:
254 * - setDepthBias:slopeScale:clamp:
255 */
256 std::size_t hash() const
257 {
258 std::size_t boolean_bitmask = (this->depth_write_enable ? 1 : 0) |
259 ((this->depth_test_enabled ? 1 : 0) << 1) |
260 ((this->depth_bias_enabled_for_points ? 1 : 0) << 2) |
261 ((this->depth_bias_enabled_for_lines ? 1 : 0) << 3) |
262 ((this->depth_bias_enabled_for_tris ? 1 : 0) << 4) |
263 ((this->stencil_test_enabled ? 1 : 0) << 5) |
264 ((this->has_depth_target ? 1 : 0) << 6) |
265 ((this->has_stencil_target ? 1 : 0) << 7);
266
267 std::size_t stencilop_bitmask = ((std::size_t)this->stencil_op_front_stencil_fail) |
268 ((std::size_t)this->stencil_op_front_depth_fail << 3) |
269 ((std::size_t)this->stencil_op_front_depthstencil_pass << 6) |
270 ((std::size_t)this->stencil_op_back_stencil_fail << 9) |
271 ((std::size_t)this->stencil_op_back_depth_fail << 12) |
272 ((std::size_t)this->stencil_op_back_depthstencil_pass << 15);
273
274 std::size_t main_hash = (std::size_t)this->depth_function;
275 if (this->has_stencil_target) {
276 main_hash += (std::size_t)(this->stencil_read_mask & 0xFF) << 8;
277 main_hash += (std::size_t)(this->stencil_write_mask & 0xFF) << 16;
278 }
279 main_hash ^= (std::size_t)this->stencil_func << 16;
280 main_hash ^= stencilop_bitmask;
281
282 std::size_t final_hash = (main_hash << 8) | boolean_bitmask;
283 return final_hash;
284 }
285};
286
288
289 /* Depth Update Utilities */
290 /* Depth texture updates are not directly supported with Blit operations, similarly, we cannot
291 * use a compute shader to write to depth, so we must instead render to a depth target.
292 * These processes use vertex/fragment shaders to render texture data from an intermediate
293 * source, in order to prime the depth buffer. */
296
297 /* Texture Read/Update routines */
314
331
332 template<typename T> void free_cached_pso_map(blender::Map<T, id<MTLComputePipelineState>> &map)
333 {
334 for (typename blender::MutableMapItem<T, id<MTLComputePipelineState>> item : map.items()) {
335 [item.value release];
336 }
337 map.clear();
338 }
339
340 void init()
341 {
342 fullscreen_blit_shader = nullptr;
343 }
344
376};
377
379 private:
380 id<MTLComputePipelineState> buffer_clear_pso_ = nil;
381
382 public:
383 id<MTLComputePipelineState> get_buffer_clear_pso();
384 void cleanup()
385 {
386 if (buffer_clear_pso_) {
387 [buffer_clear_pso_ release];
388 buffer_clear_pso_ = nil;
389 }
390 }
391};
392
393/* Combined sampler state configuration for Argument Buffer caching. */
396 /* MTLSamplerState permutations between 0..256 - slightly more than a byte. */
398 id<MTLSamplerState> mtl_sampler[MTL_MAX_TEXTURE_SLOTS];
399
400 bool operator==(const MTLSamplerArray &other) const
401 {
402 if (this->num_samplers != other.num_samplers) {
403 return false;
404 }
405 return (memcmp(this->mtl_sampler_flags,
406 other.mtl_sampler_flags,
407 sizeof(MTLSamplerState) * this->num_samplers) == 0);
408 }
409
410 uint32_t hash() const
411 {
412 uint32_t hash = this->num_samplers;
413 for (int i = 0; i < this->num_samplers; i++) {
414 hash ^= uint32_t(this->mtl_sampler_flags[i]) << (i % 3);
415 }
416 return hash;
417 }
418};
419
422 /* Whether we need to call setViewport. */
424 /* Whether we need to call setScissor. */
426 /* Whether we need to update/rebind active depth stencil state. */
428 /* Whether we need to update/rebind active PSO. */
430 /* Whether we need to update the frontFacingWinding state. */
432 /* Whether we need to update the culling state. */
434 /* Full pipeline state needs applying. Occurs when beginning a new render pass. */
439};
440
441/* Ignore full flag bit-mask `MTL_PIPELINE_STATE_ALL_FLAG`. */
443
448
453
455 bool initialised = false;
456
457 /* Whether the pipeline state has been modified since application.
458 * `dirty_flags` is a bitmask of the types of state which have been updated.
459 * This is in order to optimize calls and only re-apply state as needed.
460 * Some state parameters are dynamically applied on the RenderCommandEncoder,
461 * others may be encapsulated in GPU-resident state objects such as
462 * MTLDepthStencilState or MTLRenderPipelineState. */
463 bool dirty = true;
465
466 /* Shader resources. */
468
469 /* Active Shader State. */
471
472 /* Global Uniform Buffers. */
474
475 /* Storage buffer. */
477
478 /* Context Texture bindings. */
481
482 /* Image bindings. */
484
485 /*** --- Render Pipeline State --- ***/
486 /* Track global render pipeline state for the current context. The functions in GPU_state.hh
487 * modify these parameters. Certain values, tagged [PSO], are parameters which are required to be
488 * passed into PSO creation, rather than dynamic state functions on the RenderCommandEncoder.
489 */
490
491 /* Blending State. */
492 MTLColorWriteMask color_write_mask; /* [PSO] */
493 bool blending_enabled; /* [PSO] */
494 MTLBlendOperation alpha_blend_op; /* [PSO] */
495 MTLBlendOperation rgb_blend_op; /* [PSO] */
496 MTLBlendFactor dest_alpha_blend_factor; /* [PSO] */
497 MTLBlendFactor dest_rgb_blend_factor; /* [PSO] */
498 MTLBlendFactor src_alpha_blend_factor; /* [PSO] */
499 MTLBlendFactor src_rgb_blend_factor; /* [PSO] */
500
501 /* Culling State. */
505
506 /* Depth State. */
508
509 /* Viewport/Scissor Region. */
520
521 /* Image data access state. */
523
524 /* Render parameters. */
525 float point_size = 1.0f;
526 float line_width = 1.0f;
527
528 /* Clipping plane enablement. */
529 bool clip_distance_enabled[6] = {false};
530};
531
532/* Command Buffer Manager - Owned by MTLContext.
533 * The MTLCommandBufferManager represents all work associated with
534 * a command buffer of a given identity. This manager is a fixed-state
535 * on the context, which coordinates the lifetime of command buffers
536 * for particular categories of work.
537 *
538 * This ensures operations on command buffers, and the state associated,
539 * is correctly tracked and managed. Workload submission and MTLCommandEncoder
540 * coordination is managed from here.
541 *
542 * There is currently only one MTLCommandBufferManager for managing submission
543 * of the "main" rendering commands. A secondary upload command buffer track,
544 * or asynchronous compute command buffer track may be added in the future. */
546 friend class MTLContext;
547
548 public:
549 /* Counter for all active command buffers. */
550 static volatile std::atomic<int> num_active_cmd_bufs_in_system;
551
552 private:
553 /* Associated Context and properties. */
554 MTLContext &context_;
555 bool supports_render_ = false;
556
557 /* CommandBuffer tracking. */
558 id<MTLCommandBuffer> active_command_buffer_ = nil;
559 id<MTLCommandBuffer> last_submitted_command_buffer_ = nil;
560 volatile std::atomic<int> num_active_cmd_bufs = 0;
561
562 /* Active MTLCommandEncoders. */
563 enum {
564 MTL_NO_COMMAND_ENCODER = 0,
565 MTL_RENDER_COMMAND_ENCODER = 1,
566 MTL_BLIT_COMMAND_ENCODER = 2,
567 MTL_COMPUTE_COMMAND_ENCODER = 3
568 } active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
569
570 id<MTLRenderCommandEncoder> active_render_command_encoder_ = nil;
571 id<MTLBlitCommandEncoder> active_blit_command_encoder_ = nil;
572 id<MTLComputeCommandEncoder> active_compute_command_encoder_ = nil;
573
574 /* State associated with active RenderCommandEncoder. */
575 MTLRenderPassState render_pass_state_;
576 MTLFrameBuffer *active_frame_buffer_ = nullptr;
577 MTLRenderPassDescriptor *active_pass_descriptor_ = nullptr;
578
579 /* State associated with active ComputeCommandEncoder. */
580 MTLComputeState compute_state_;
581
582 /* Workload heuristics - We may need to split command buffers to optimize workload and balancing.
583 */
584 int current_draw_call_count_ = 0;
585 int encoder_count_ = 0;
586 int vertex_submitted_count_ = 0;
587 bool empty_ = true;
588
590 /* Stack tracking all calls to push_debug_group. */
591 std::vector<std::string> debug_group_stack;
592 /* Stack tracking calls resulting in active API calls to pushDebugGroup on the current command
593 * buffer. */
594 std::vector<std::string> debug_group_pushed_stack;
595
596 public:
598 : context_(context), render_pass_state_(context, *this), compute_state_(context, *this) {};
599 void prepare(bool supports_render = true);
600
601 /* If wait is true, CPU will stall until GPU work has completed. */
602 bool submit(bool wait);
603
604 /* Fetch/query current encoder. */
606 bool is_inside_blit();
607 bool is_inside_compute();
608 id<MTLRenderCommandEncoder> get_active_render_command_encoder();
609 id<MTLBlitCommandEncoder> get_active_blit_command_encoder();
610 id<MTLComputeCommandEncoder> get_active_compute_command_encoder();
612
613 /* RenderPassState for RenderCommandEncoder. */
615 {
616 /* Render pass state should only be valid if we are inside a render pass. */
618 return render_pass_state_;
619 }
620
621 /* RenderPassState for RenderCommandEncoder. */
623 {
624 /* Render pass state should only be valid if we are inside a compute encoder. */
626 return compute_state_;
627 }
628
629 /* Rendering Heuristics. */
630 void register_draw_counters(int vertex_submission);
631 void reset_counters();
632 bool do_break_submission();
633
634 /* Encoder and Pass management. */
635 /* End currently active MTLCommandEncoder. */
636 bool end_active_command_encoder(bool retain_framebuffers = false);
637 id<MTLRenderCommandEncoder> ensure_begin_render_command_encoder(MTLFrameBuffer *ctx_framebuffer,
638 bool force_begin,
639 bool *r_new_pass);
640 id<MTLBlitCommandEncoder> ensure_begin_blit_encoder();
641 id<MTLComputeCommandEncoder> ensure_begin_compute_encoder();
642
643 /* Workload Synchronization. */
644 bool insert_memory_barrier(GPUBarrier barrier_bits,
645 GPUStageBarrierBits before_stages,
646 GPUStageBarrierBits after_stages);
647 void encode_signal_event(id<MTLEvent> event, uint64_t value);
648 void encode_wait_for_event(id<MTLEvent> event, uint64_t value);
649 /* TODO(Metal): Support fences in command buffer class. */
650
651 /* Debug. */
652 void push_debug_group(const char *name, int index);
653 void pop_debug_group();
654
656 {
658 num_active_cmd_bufs++;
659 }
660
662 {
663 BLI_assert(num_active_cmd_bufs_in_system > 0 && num_active_cmd_bufs > 0);
665 num_active_cmd_bufs--;
666 }
667
669 {
670 return num_active_cmd_bufs;
671 }
672
674 {
676 std::this_thread::yield();
677 }
678 }
679
680 private:
681 /* Begin new command buffer. */
682 id<MTLCommandBuffer> ensure_begin();
683
684 void register_encoder_counters();
685
686 /* Debug group management. */
687 void unfold_pending_debug_groups();
688};
689
696class MTLContext : public Context {
697 friend class MTLBackend;
698 friend class MTLRenderPassState;
699 friend class MTLComputeState;
700
701 public:
702 /* Swap-chain and latency management. */
703 static std::atomic<int> max_drawables_in_flight;
704 static std::atomic<int64_t> avg_drawable_latency_us;
706
707 public:
708 /* Shaders and Pipeline state. */
710
711 /* Metal API Resource Handles. */
712 id<MTLCommandQueue> queue = nil;
713 id<MTLDevice> device = nil;
714
715#ifndef NDEBUG
716 /* Label for Context debug name assignment. */
717 NSString *label = nil;
718#endif
719
720 /* Memory Management. */
725
726 /* CommandBuffer managers. */
728
729 private:
730 /* Parent Context. */
731 GHOST_ContextMTL *ghost_context_;
732
733 /* Render Passes and Frame-buffers. */
734 id<MTLTexture> default_fbo_mtltexture_ = nil;
735 gpu::MTLTexture *default_fbo_gputexture_ = nullptr;
736
737 /* Depth-stencil state cache. */
739
740 /* Compute and specialization caches. */
741 MTLContextTextureUtils texture_utils_;
742 MTLContextComputeUtils compute_utils_;
743
744 /* Texture Samplers. */
745 /* Cache of generated #MTLSamplerState objects based on permutations of the members of
746 * `GPUSamplerState`. */
747 id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_EXTEND_MODES_COUNT]
750 id<MTLSamplerState> custom_sampler_state_cache_[GPU_SAMPLER_CUSTOM_TYPES_COUNT];
751 id<MTLSamplerState> default_sampler_state_ = nil;
752
753 /* When texture sampler count exceeds the resource bind limit, an
754 * argument buffer is used to pass samplers to the shader.
755 * Each unique configurations of multiple samplers can be cached, so as to not require
756 * re-generation. `samplers_` stores the current list of bound sampler objects.
757 * `cached_sampler_buffers_` is a cache of encoded argument buffers which can be re-used. */
758 MTLSamplerArray samplers_;
760
761 /* Frame. */
762 bool is_inside_frame_ = false;
763 uint current_frame_index_;
764
765 /* Visibility buffer for MTLQuery results. */
766 gpu::MTLBuffer *visibility_buffer_ = nullptr;
767 bool visibility_is_dirty_ = false;
768
769 /* Null buffers for empty/uninitialized bindings.
770 * Null attribute buffer follows default attribute format of OpenGL Backend. */
771 id<MTLBuffer> null_buffer_; /* All zero's. */
772 id<MTLBuffer> null_attribute_buffer_; /* Value float4(0.0,0.0,0.0,1.0). */
773
775 /* Maximum of 32 texture types. Though most combinations invalid. */
776 gpu::MTLTexture *dummy_textures_[GPU_SAMPLER_TYPE_MAX][GPU_TEXTURE_BUFFER] = {{nullptr}};
777 GPUVertFormat dummy_vertformat_[GPU_SAMPLER_TYPE_MAX];
778 VertBuf *dummy_verts_[GPU_SAMPLER_TYPE_MAX] = {nullptr};
779
780 /* Debug scope timings. Adapted form GLContext::TimeQuery.
781 * Only supports CPU timings for now. */
782 struct ScopeTimings {
783 using Clock = std::chrono::steady_clock;
784 using TimePoint = Clock::time_point;
785 using Nanoseconds = std::chrono::nanoseconds;
786
787 static TimePoint epoch;
788
789 std::string name;
790 bool finished;
791 TimePoint cpu_start, cpu_end;
792 };
793 Vector<ScopeTimings> scope_timings;
794
795 void process_frame_timings();
796
797 public:
798 /* GPUContext interface. */
799 MTLContext(void *ghost_window, void *ghost_context);
800 ~MTLContext();
801
802 static void check_error(const char *info);
803
804 void activate() override;
805 void deactivate() override;
806 void begin_frame() override;
807 void end_frame() override;
808
809 void flush() override;
810 void finish() override;
811
812 void memory_statistics_get(int *r_total_mem, int *r_free_mem) override;
813
814 static MTLContext *get()
815 {
816 return static_cast<MTLContext *>(Context::get());
817 }
818
819 void debug_group_begin(const char *name, int index) override;
820 void debug_group_end() override;
821 bool debug_capture_begin(const char *title) override;
822 void debug_capture_end() override;
823 void *debug_capture_scope_create(const char *name) override;
824 bool debug_capture_scope_begin(void *scope) override;
825 void debug_capture_scope_end(void *scope) override;
826
827 void debug_unbind_all_ubo() override {};
828 void debug_unbind_all_ssbo() override {};
829
830 /*** MTLContext Utility functions. */
831 /*
832 * All below functions modify the global state for the context, controlling the flow of
833 * rendering, binding resources, setting global state, resource management etc;
834 */
835
837
838 /* Bind frame-buffer to context. */
839 void framebuffer_bind(MTLFrameBuffer *framebuffer);
840
841 /* Restore frame-buffer used by active context to default back-buffer. */
842 void framebuffer_restore();
843
844 /* Ensure a render-pass using the Context frame-buffer (active_fb_) is in progress. */
845 id<MTLRenderCommandEncoder> ensure_begin_render_pass();
846
849
850 /* Context Global-State Texture Binding. */
851 void texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit, bool is_image);
852 void sampler_bind(MTLSamplerState, uint sampler_unit);
853 void texture_unbind(gpu::MTLTexture *mtl_texture, bool is_image, StateManager *state_manager);
854 void texture_unbind_all(bool is_image);
856 id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state);
857 id<MTLSamplerState> get_default_sampler_state();
858
859 /* Active shader specialization constants state. */
861
863
864 /* Metal Context pipeline state. */
865 void pipeline_state_init();
867
868 /* These functions ensure that the current RenderCommandEncoder has
869 * the correct global state assigned. This should be called prior
870 * to every draw call, to ensure that all state is applied and up
871 * to date. We handle:
872 *
873 * - Buffer bindings (Vertex buffers, Uniforms, UBOs)
874 * - Texture bindings
875 * - Sampler bindings (+ argument buffer bindings)
876 * - Dynamic Render pipeline state (on encoder)
877 * - Baking Pipeline State Objects (PSOs) for current shader, based
878 * on final pipeline state.
879 *
880 * `ensure_render_pipeline_state` will return false if the state is
881 * invalid and cannot be applied. This should cancel a draw call. */
882 bool ensure_render_pipeline_state(MTLPrimitiveType prim_type);
883 bool ensure_buffer_bindings(id<MTLRenderCommandEncoder> rec,
884 const MTLShaderInterface *shader_interface,
885 const MTLRenderPipelineStateInstance *pipeline_state_instance);
886 bool ensure_buffer_bindings(id<MTLComputeCommandEncoder> rec,
887 const MTLShaderInterface *shader_interface,
888 const MTLComputePipelineStateInstance *pipeline_state_instance);
889 void ensure_texture_bindings(id<MTLRenderCommandEncoder> rec,
890 MTLShaderInterface *shader_interface,
891 const MTLRenderPipelineStateInstance *pipeline_state_instance);
892 void ensure_texture_bindings(id<MTLComputeCommandEncoder> rec,
893 MTLShaderInterface *shader_interface,
894 const MTLComputePipelineStateInstance *pipeline_state_instance);
895 void ensure_depth_stencil_state(MTLPrimitiveType prim_type);
896
897 id<MTLBuffer> get_null_buffer();
898 id<MTLBuffer> get_null_attribute_buffer();
901
902 /* Compute. */
903 /* Ensure compute pipeline state for current config is compiled and return PSO instance. */
905 void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len);
906 void compute_dispatch_indirect(StorageBuf *indirect_buf);
907
908 /* State assignment. */
909 void set_viewport(int origin_x, int origin_y, int width, int height);
910 void set_viewports(int count, const int (&viewports)[GPU_MAX_VIEWPORTS][4]);
911 void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height);
912 void set_scissor_enabled(bool scissor_enabled);
913
914 /* Visibility buffer control. */
917
918 /* Flag whether the visibility buffer for query results
919 * has changed. This requires a new RenderPass in order
920 * to update. */
921 bool is_visibility_dirty() const;
922
923 /* Reset dirty flag state for visibility buffer. */
925
926 /* Texture utilities. */
928 {
929 return texture_utils_;
930 }
931
932 /* Compute utilities. */
934 {
935 return compute_utils_;
936 }
937
939 {
940 return is_active_;
941 }
942
944 {
945 return is_inside_frame_;
946 }
947
949 {
950 return current_frame_index_;
951 }
952
954 {
955 return this->memory_manager;
956 }
957
968
982
988
989 /* Swap-chain and latency management. */
990 static void latency_resolve_average(int64_t frame_latency_us)
991 {
992 int64_t avg = 0;
993 int64_t frame_c = 0;
994 for (int i = MTL_FRAME_AVERAGE_COUNT - 1; i > 0; i--) {
997 frame_c += (MTLContext::frame_latency[i] > 0) ? 1 : 0;
998 }
999 MTLContext::frame_latency[0] = frame_latency_us;
1000 avg += MTLContext::frame_latency[0];
1001 if (frame_c > 0) {
1002 avg /= frame_c;
1003 }
1004 else {
1005 avg = 0;
1006 }
1008 }
1009
1010 private:
1011 void set_ghost_context(GHOST_ContextHandle ghostCtxHandle);
1012 void set_ghost_window(GHOST_WindowHandle ghostWinHandle);
1013};
1014
1015/* GHOST Context callback and present. */
1016void present(MTLRenderPassDescriptor *blit_descriptor,
1017 id<MTLRenderPipelineState> blit_pso,
1018 id<MTLTexture> swapchain_texture,
1019 id<CAMetalDrawable> drawable);
1020
1021} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
#define ENUM_OPERATORS(_type, _max)
GPUFrontFace
static constexpr int GPU_MAX_VIEWPORTS
void GPU_shader_free(blender::gpu::Shader *shader)
GPUBarrier
Definition GPU_state.hh:29
GPUStageBarrierBits
Definition GPU_state.hh:65
GPUFaceCullTest
Definition GPU_state.hh:135
static const int GPU_SAMPLER_FILTERING_TYPES_COUNT
#define GPU_SAMPLER_CUSTOM_TYPES_COUNT
#define GPU_SAMPLER_EXTEND_MODES_COUNT
long long int int64_t
unsigned long long int uint64_t
static Context * get()
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()
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(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()
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)
shader::SpecializationConstants constants_state
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()
friend class MTLRenderPassState
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:125
void * debug_capture_scope_create(const char *name) override
Definition mtl_debug.mm:152
void debug_capture_scope_end(void *scope) override
Definition mtl_debug.mm:177
static MTLBufferPool * global_memory_manager
void end_frame() override
static int global_memory_manager_refcount
MTLShader * get_active_shader()
void texture_unbind(gpu::MTLTexture *mtl_texture, bool is_image, StateManager *state_manager)
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)
void specialization_constants_set(const shader::SpecializationConstants *constants_state)
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:50
static void check_error(const char *info)
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:167
MTLCommandBufferManager main_command_buffer
void debug_group_end() override
Definition mtl_debug.mm:68
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()
id< MTLCommandQueue > queue
gpu::MTLTexture * get_dummy_texture(GPUTextureType type, GPUSamplerFormat sampler_format)
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:142
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)
float length(VecOp< float, D >) RET
int count
static ulong state[N]
#define T
#define MTL_MAX_SAMPLER_SLOTS
#define MTL_MAX_BUFFER_BINDINGS
#define MTL_MAX_TEXTURE_SLOTS
#define MTL_FRAME_AVERAGE_COUNT
Definition mtl_common.hh:9
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
const char * name
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< DepthTextureUpdateRoutineSpecialisation, gpu::Shader * > depth_2d_update_shaders
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< 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
i
Definition text_draw.cc:230