@@ -309,9 +309,23 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDRenderPass {
309309
310310class API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) MDCommandBuffer {
311311private:
312+ #pragma mark - Common State
313+
314+ // From RenderingDevice
315+ static constexpr uint32_t MAX_PUSH_CONSTANT_SIZE = 128 ;
316+
312317 RenderingDeviceDriverMetal *device_driver = nullptr ;
313318 id <MTLCommandQueue > queue = nil ;
314319 id <MTLCommandBuffer > commandBuffer = nil ;
320+ bool state_begin = false ;
321+
322+ _FORCE_INLINE_ id <MTLCommandBuffer > command_buffer () {
323+ DEV_ASSERT (state_begin);
324+ if (commandBuffer == nil ) {
325+ commandBuffer = queue.commandBuffer ;
326+ }
327+ return commandBuffer;
328+ }
315329
316330 void _end_compute_dispatch ();
317331 void _end_blit ();
@@ -326,6 +340,11 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
326340 void _end_render_pass ();
327341 void _render_clear_render_area ();
328342
343+ #pragma mark - Compute
344+
345+ void _compute_set_dirty_state ();
346+ void _compute_bind_uniform_sets ();
347+
329348public:
330349 MDCommandBufferStateType type = MDCommandBufferStateType::None;
331350
@@ -349,25 +368,28 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
349368 LocalVector<NSUInteger > vertex_offsets;
350369 ResourceUsageMap resource_usage;
351370 // clang-format off
352- enum DirtyFlag: uint8_t {
353- DIRTY_NONE = 0b0000'0000 ,
354- DIRTY_PIPELINE = 0b0000'0001 , // ! pipeline state
355- DIRTY_UNIFORMS = 0b0000'0010 , // ! uniform sets
356- DIRTY_DEPTH = 0b0000'0100 , // ! depth / stencil state
357- DIRTY_VERTEX = 0b0000'1000 , // ! vertex buffers
358- DIRTY_VIEWPORT = 0b0001'0000 , // ! viewport rectangles
359- DIRTY_SCISSOR = 0b0010'0000 , // ! scissor rectangles
360- DIRTY_BLEND = 0b0100'0000 , // ! blend state
361- DIRTY_RASTER = 0b1000'0000 , // ! encoder state like cull mode
362-
363- DIRTY_ALL = 0xff ,
371+ enum DirtyFlag: uint16_t {
372+ DIRTY_NONE = 0 ,
373+ DIRTY_PIPELINE = 1 << 0 , // ! pipeline state
374+ DIRTY_UNIFORMS = 1 << 1 , // ! uniform sets
375+ DIRTY_PUSH = 1 << 2 , // ! push constants
376+ DIRTY_DEPTH = 1 << 3 , // ! depth / stencil state
377+ DIRTY_VERTEX = 1 << 4 , // ! vertex buffers
378+ DIRTY_VIEWPORT = 1 << 5 , // ! viewport rectangles
379+ DIRTY_SCISSOR = 1 << 6 , // ! scissor rectangles
380+ DIRTY_BLEND = 1 << 7 , // ! blend state
381+ DIRTY_RASTER = 1 << 8 , // ! encoder state like cull mode
382+ DIRTY_ALL = ( 1 << 9 ) - 1 ,
364383 };
365384 // clang-format on
366385 BitField<DirtyFlag> dirty = DIRTY_NONE;
367386
368387 LocalVector<MDUniformSet *> uniform_sets;
369388 // Bit mask of the uniform sets that are dirty, to prevent redundant binding.
370389 uint64_t uniform_set_mask = 0 ;
390+ uint8_t push_constant_data[MAX_PUSH_CONSTANT_SIZE];
391+ uint32_t push_constant_data_len = 0 ;
392+ uint32_t push_constant_bindings[2 ] = { 0 };
371393
372394 _FORCE_INLINE_ void reset ();
373395 void end_encoding ();
@@ -422,6 +444,13 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
422444 dirty.set_flag (DirtyFlag::DIRTY_UNIFORMS);
423445 }
424446
447+ _FORCE_INLINE_ void mark_push_constants_dirty () {
448+ if (push_constant_data_len == 0 ) {
449+ return ;
450+ }
451+ dirty.set_flag (DirtyFlag::DIRTY_PUSH);
452+ }
453+
425454 _FORCE_INLINE_ void mark_blend_dirty () {
426455 if (!blend_constants.has_value ()) {
427456 return ;
@@ -464,16 +493,46 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
464493 MDComputePipeline *pipeline = nullptr ;
465494 id <MTLComputeCommandEncoder > encoder = nil ;
466495 ResourceUsageMap resource_usage;
467- _FORCE_INLINE_ void reset () {
468- pipeline = nil;
469- encoder = nil;
470- // Keep the keys, as they are likely to be used again.
471- for (KeyValue<StageResourceUsage, LocalVector<__unsafe_unretained id<MTLResource>>> &kv : resource_usage) {
472- kv.value .clear ();
496+ // clang-format off
497+ enum DirtyFlag: uint16_t {
498+ DIRTY_NONE = 0 ,
499+ DIRTY_PIPELINE = 1 << 0 , // ! pipeline state
500+ DIRTY_UNIFORMS = 1 << 1 , // ! uniform sets
501+ DIRTY_PUSH = 1 << 2 , // ! push constants
502+ DIRTY_ALL = (1 << 3 ) - 1 ,
503+ };
504+ // clang-format on
505+ BitField<DirtyFlag> dirty = DIRTY_NONE;
506+
507+ LocalVector<MDUniformSet *> uniform_sets;
508+ // Bit mask of the uniform sets that are dirty, to prevent redundant binding.
509+ uint64_t uniform_set_mask = 0 ;
510+ uint8_t push_constant_data[MAX_PUSH_CONSTANT_SIZE];
511+ uint32_t push_constant_data_len = 0 ;
512+ uint32_t push_constant_bindings[1 ] = { 0 };
513+
514+ _FORCE_INLINE_ void reset ();
515+ void end_encoding ();
516+
517+ _FORCE_INLINE_ void mark_uniforms_dirty (void ) {
518+ if (uniform_sets.is_empty ()) {
519+ return ;
473520 }
521+ for (uint32_t i = 0 ; i < uniform_sets.size (); i++) {
522+ if (uniform_sets[i] != nullptr ) {
523+ uniform_set_mask |= 1 << i;
524+ }
525+ }
526+ dirty.set_flag (DirtyFlag::DIRTY_UNIFORMS);
527+ }
528+
529+ _FORCE_INLINE_ void mark_push_constants_dirty () {
530+ if (push_constant_data_len == 0 ) {
531+ return ;
532+ }
533+ dirty.set_flag (DirtyFlag::DIRTY_PUSH);
474534 }
475535
476- void end_encoding ();
477536 } compute;
478537
479538 // State specific to a blit pass.
@@ -496,6 +555,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDCommandBuffer {
496555 void encodeRenderCommandEncoderWithDescriptor (MTLRenderPassDescriptor *p_desc, NSString *p_label);
497556
498557 void bind_pipeline (RDD::PipelineID p_pipeline);
558+ void encode_push_constant_data (RDD::ShaderID p_shader, VectorView<uint32_t > p_data);
499559
500560#pragma mark - Render Commands
501561
@@ -661,8 +721,6 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDShader {
661721 Vector<UniformSet> sets;
662722 bool uses_argument_buffers = true ;
663723
664- virtual void encode_push_constant_data (VectorView<uint32_t > p_data, MDCommandBuffer *p_cb) = 0 ;
665-
666724 MDShader (CharString p_name, Vector<UniformSet> p_sets, bool p_uses_argument_buffers) :
667725 name (p_name), sets (p_sets), uses_argument_buffers (p_uses_argument_buffers) {}
668726 virtual ~MDShader () = default ;
@@ -671,15 +729,13 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDShader {
671729class API_AVAILABLE (macos(11.0 ), ios(14.0 ), tvos(14.0 )) MDComputeShader final : public MDShader {
672730public:
673731 struct {
674- uint32_t binding = -1 ;
732+ int32_t binding = -1 ;
675733 uint32_t size = 0 ;
676734 } push_constants;
677735 MTLSize local = {};
678736
679737 MDLibrary *kernel;
680738
681- void encode_push_constant_data (VectorView<uint32_t > p_data, MDCommandBuffer *p_cb) final ;
682-
683739 MDComputeShader (CharString p_name, Vector<UniformSet> p_sets, bool p_uses_argument_buffers, MDLibrary *p_kernel);
684740};
685741
@@ -700,8 +756,6 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDRenderShader final : p
700756 MDLibrary *vert;
701757 MDLibrary *frag;
702758
703- void encode_push_constant_data (VectorView<uint32_t > p_data, MDCommandBuffer *p_cb) final ;
704-
705759 MDRenderShader (CharString p_name,
706760 Vector<UniformSet> p_sets,
707761 bool p_needs_view_mask_buffer,
0 commit comments