@@ -135,6 +135,8 @@ class RenderingDeviceDriverMetal;
135135class MDUniformSet;
136136class MDShader;
137137
138+ struct MetalBufferDynamicInfo;
139+
138140#pragma mark - Resource Factory
139141
140142struct ClearAttKey {
@@ -385,11 +387,12 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
385387 BitField<DirtyFlag> dirty = DIRTY_NONE;
386388
387389 LocalVector<MDUniformSet *> uniform_sets;
390+ uint32_t dynamic_offsets = 0 ;
388391 // Bit mask of the uniform sets that are dirty, to prevent redundant binding.
389392 uint64_t uniform_set_mask = 0 ;
390393 uint8_t push_constant_data[MAX_PUSH_CONSTANT_SIZE];
391394 uint32_t push_constant_data_len = 0 ;
392- uint32_t push_constant_bindings[2 ] = { 0 };
395+ uint32_t push_constant_bindings[2 ] = { ~ 0U , ~ 0U };
393396
394397 _FORCE_INLINE_ void reset ();
395398 void end_encoding ();
@@ -505,11 +508,12 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
505508 BitField<DirtyFlag> dirty = DIRTY_NONE;
506509
507510 LocalVector<MDUniformSet *> uniform_sets;
511+ uint32_t dynamic_offsets = 0 ;
508512 // Bit mask of the uniform sets that are dirty, to prevent redundant binding.
509513 uint64_t uniform_set_mask = 0 ;
510514 uint8_t push_constant_data[MAX_PUSH_CONSTANT_SIZE];
511515 uint32_t push_constant_data_len = 0 ;
512- uint32_t push_constant_bindings[1 ] = { 0 };
516+ uint32_t push_constant_bindings[1 ] = { ~ 0U };
513517
514518 _FORCE_INLINE_ void reset ();
515519 void end_encoding ();
@@ -559,8 +563,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
559563
560564#pragma mark - Render Commands
561565
562- void render_bind_uniform_set (RDD::UniformSetID p_uniform_set, RDD::ShaderID p_shader, uint32_t p_set_index);
563- void render_bind_uniform_sets (VectorView<RDD::UniformSetID> p_uniform_sets, RDD::ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count);
566+ void render_bind_uniform_sets (VectorView<RDD::UniformSetID> p_uniform_sets, RDD::ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets);
564567 void render_clear_attachments (VectorView<RDD::AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects);
565568 void render_set_viewport (VectorView<Rect2i> p_viewports);
566569 void render_set_scissor (VectorView<Rect2i> p_scissors);
@@ -593,8 +596,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
593596
594597#pragma mark - Compute Commands
595598
596- void compute_bind_uniform_set (RDD::UniformSetID p_uniform_set, RDD::ShaderID p_shader, uint32_t p_set_index);
597- void compute_bind_uniform_sets (VectorView<RDD::UniformSetID> p_uniform_sets, RDD::ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count);
599+ void compute_bind_uniform_sets (VectorView<RDD::UniformSetID> p_uniform_sets, RDD::ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets);
598600 void compute_dispatch (uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
599601 void compute_dispatch_indirect (RDD::BufferID p_indirect_buffer, uint64_t p_offset);
600602
@@ -647,6 +649,7 @@ struct API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) UniformInfo {
647649
648650struct API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) UniformSet {
649651 LocalVector<UniformInfo> uniforms;
652+ LocalVector<uint32_t > dynamic_uniforms;
650653 uint32_t buffer_size = 0 ;
651654 HashMap<RDC::ShaderStage, uint32_t > offsets;
652655 HashMap<RDC::ShaderStage, id <MTLArgumentEncoder >> encoders;
@@ -715,10 +718,62 @@ struct ShaderCacheEntry {
715718 ~ShaderCacheEntry () = default ;
716719};
717720
721+ // / Godot limits the number of dynamic buffers to 8.
722+ // /
723+ // / This is a minimum guarantee for Vulkan.
724+ constexpr uint32_t MAX_DYNAMIC_BUFFERS = 8 ;
725+
726+ // / Maximum number of queued frames.
727+ // /
728+ // / See setting: rendering/rendering_device/vsync/frame_queue_size
729+ constexpr uint32_t MAX_FRAME_COUNT = 4 ;
730+
731+ class API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) DynamicOffsetLayout {
732+ struct Data {
733+ uint8_t offset : 4 ;
734+ uint8_t count : 4 ;
735+ };
736+
737+ union {
738+ Data data[MAX_DYNAMIC_BUFFERS];
739+ uint64_t _val = 0 ;
740+ };
741+
742+ public:
743+ _FORCE_INLINE_ bool is_empty () const { return _val == 0 ; }
744+
745+ _FORCE_INLINE_ uint32_t get_count (uint32_t p_set_index) const {
746+ return data[p_set_index].count ;
747+ }
748+
749+ _FORCE_INLINE_ uint32_t get_offset (uint32_t p_set_index) const {
750+ return data[p_set_index].offset ;
751+ }
752+
753+ _FORCE_INLINE_ void set_offset_count (uint32_t p_set_index, uint8_t p_offset, uint8_t p_count) {
754+ data[p_set_index].offset = p_offset;
755+ data[p_set_index].count = p_count;
756+ }
757+
758+ _FORCE_INLINE_ uint32_t get_offset_index_shift (uint32_t p_set_index, uint32_t p_dynamic_index = 0 ) const {
759+ return (data[p_set_index].offset + p_dynamic_index) * 4u ;
760+ }
761+ };
762+
763+ class API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) DynamicOffsets {
764+ uint32_t data;
765+
766+ public:
767+ _FORCE_INLINE_ uint32_t get_frame_index (const DynamicOffsetLayout &p_layout) const {
768+ return data;
769+ }
770+ };
771+
718772class API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) MDShader {
719773public:
720774 CharString name;
721775 Vector<UniformSet> sets;
776+ DynamicOffsetLayout dynamic_offset_layout;
722777 bool uses_argument_buffers = true ;
723778
724779 MDShader (CharString p_name, Vector<UniformSet> p_sets, bool p_uses_argument_buffers) :
@@ -786,30 +841,49 @@ struct HashMapComparatorDefault<RDD::ShaderID> {
786841struct BoundUniformSet {
787842 id <MTLBuffer > buffer;
788843 ResourceUsageMap usage_to_resources;
844+ // / Size of the per-frame buffer, which is 0 when there are no dynamic uniforms.
845+ uint32_t frame_size = 0 ;
789846
790847 // / Perform a 2-way merge each key of `ResourceVector` resources from this set into the
791848 // / destination set.
792849 // /
793850 // / Assumes the vectors of resources are sorted.
794851 void merge_into (ResourceUsageMap &p_dst) const ;
852+
853+ // / Returns true if this bound uniform set contains dynamic uniforms.
854+ _FORCE_INLINE_ bool is_dynamic () const { return frame_size > 0 ; }
855+
856+ // / Calculate the offset in the Metal buffer for the current frame.
857+ _FORCE_INLINE_ uint32_t frame_offset (uint32_t p_frame_index) const { return p_frame_index * frame_size; }
858+
859+ // / Calculate the offset in the buffer for the given frame index and base offset.
860+ _FORCE_INLINE_ uint32_t make_offset (uint32_t p_frame_index, uint32_t p_base_offset) const {
861+ return frame_offset (p_frame_index) + p_base_offset;
862+ }
863+
864+ BoundUniformSet () = default ;
865+ BoundUniformSet (id <MTLBuffer > p_buffer, ResourceUsageMap &&p_usage_to_resources, uint32_t p_frame_size) :
866+ buffer (p_buffer), usage_to_resources (std::move (p_usage_to_resources)), frame_size (p_frame_size) {}
795867};
796868
797869class API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) MDUniformSet {
798870private:
799- void bind_uniforms_argument_buffers (MDShader *p_shader, MDCommandBuffer::RenderState &p_state, uint32_t p_set_index);
800- void bind_uniforms_direct (MDShader *p_shader, MDCommandBuffer::RenderState &p_state, uint32_t p_set_index);
801- void bind_uniforms_argument_buffers (MDShader *p_shader, MDCommandBuffer::ComputeState &p_state, uint32_t p_set_index);
802- void bind_uniforms_direct (MDShader *p_shader, MDCommandBuffer::ComputeState &p_state, uint32_t p_set_index);
871+ void bind_uniforms_argument_buffers (MDShader *p_shader, MDCommandBuffer::RenderState &p_state, uint32_t p_set_index, uint32_t p_dynamic_offsets, uint32_t p_frame_idx, uint32_t p_frame_count);
872+ void bind_uniforms_direct (MDShader *p_shader, MDCommandBuffer::RenderState &p_state, uint32_t p_set_index, uint32_t p_dynamic_offsets);
873+ void bind_uniforms_argument_buffers (MDShader *p_shader, MDCommandBuffer::ComputeState &p_state, uint32_t p_set_index, uint32_t p_dynamic_offsets, uint32_t p_frame_idx, uint32_t p_frame_count);
874+ void bind_uniforms_direct (MDShader *p_shader, MDCommandBuffer::ComputeState &p_state, uint32_t p_set_index, uint32_t p_dynamic_offsets);
875+
876+ void update_dynamic_uniforms (MDShader *p_shader, ResourceUsageMap &p_resource_usage, uint32_t p_set_index, BoundUniformSet &p_bound_set, uint32_t p_dynamic_offsets, uint32_t p_frame_idx);
803877
804878public:
805- uint32_t index;
879+ uint32_t index = 0 ;
806880 LocalVector<RDD::BoundUniform> uniforms;
807881 HashMap<MDShader *, BoundUniformSet> bound_uniforms;
808882
809- void bind_uniforms (MDShader *p_shader, MDCommandBuffer::RenderState &p_state, uint32_t p_set_index);
810- void bind_uniforms (MDShader *p_shader, MDCommandBuffer::ComputeState &p_state, uint32_t p_set_index);
883+ void bind_uniforms (MDShader *p_shader, MDCommandBuffer::RenderState &p_state, uint32_t p_set_index, uint32_t p_dynamic_offsets, uint32_t p_frame_idx, uint32_t p_frame_count );
884+ void bind_uniforms (MDShader *p_shader, MDCommandBuffer::ComputeState &p_state, uint32_t p_set_index, uint32_t p_dynamic_offsets, uint32_t p_frame_idx, uint32_t p_frame_count );
811885
812- BoundUniformSet &bound_uniform_set (MDShader *p_shader, id <MTLDevice > p_device, ResourceUsageMap &p_resource_usage, uint32_t p_set_index);
886+ BoundUniformSet &bound_uniform_set (MDShader *p_shader, id <MTLDevice > p_device, ResourceUsageMap &p_resource_usage, uint32_t p_set_index, uint32_t p_dynamic_offsets, uint32_t p_frame_idx, uint32_t p_frame_count );
813887};
814888
815889class API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) MDPipeline {
0 commit comments