@@ -82,6 +82,9 @@ MTL_CLASS(Texture)
8282
8383} // namespace MTL
8484
85+ // / Metal buffer index for the view mask when rendering multi-view.
86+ const uint32_t VIEW_MASK_BUFFER_INDEX = 24 ;
87+
8588enum ShaderStageUsage : uint32_t {
8689 None = 0 ,
8790 Vertex = RDD::SHADER_STAGE_VERTEX_BIT,
@@ -142,6 +145,12 @@ struct ClearAttKey {
142145 const static uint32_t STENCIL_INDEX = DEPTH_INDEX + 1 ;
143146 const static uint32_t ATTACHMENT_COUNT = STENCIL_INDEX + 1 ;
144147
148+ enum Flags : uint16_t {
149+ CLEAR_FLAGS_NONE = 0 ,
150+ CLEAR_FLAGS_LAYERED = 1 << 0 ,
151+ };
152+
153+ Flags flags = CLEAR_FLAGS_NONE;
145154 uint16_t sample_count = 0 ;
146155 uint16_t pixel_formats[ATTACHMENT_COUNT] = { 0 };
147156
@@ -150,19 +159,22 @@ struct ClearAttKey {
150159 _FORCE_INLINE_ void set_stencil_format (MTLPixelFormat p_fmt) { pixel_formats[STENCIL_INDEX] = p_fmt; }
151160 _FORCE_INLINE_ MTLPixelFormat depth_format () const { return (MTLPixelFormat )pixel_formats[DEPTH_INDEX]; }
152161 _FORCE_INLINE_ MTLPixelFormat stencil_format () const { return (MTLPixelFormat )pixel_formats[STENCIL_INDEX]; }
162+ _FORCE_INLINE_ void enable_layered_rendering () { flags::set (flags, CLEAR_FLAGS_LAYERED); }
153163
154164 _FORCE_INLINE_ bool is_enabled (uint32_t p_idx) const { return pixel_formats[p_idx] != 0 ; }
155165 _FORCE_INLINE_ bool is_depth_enabled () const { return pixel_formats[DEPTH_INDEX] != 0 ; }
156166 _FORCE_INLINE_ bool is_stencil_enabled () const { return pixel_formats[STENCIL_INDEX] != 0 ; }
167+ _FORCE_INLINE_ bool is_layered_rendering_enabled () const { return flags::any (flags, CLEAR_FLAGS_LAYERED); }
157168
158169 _FORCE_INLINE_ bool operator==(const ClearAttKey &p_rhs) const {
159170 return memcmp (this, &p_rhs, sizeof (ClearAttKey)) == 0 ;
160171 }
161172
162173 uint32_t hash () const {
163- uint32_t h = hash_murmur3_one_32 (sample_count);
174+ uint32_t h = hash_murmur3_one_32 (flags);
175+ h = hash_murmur3_one_32 (sample_count, h);
164176 h = hash_murmur3_buffer (pixel_formats, ATTACHMENT_COUNT * sizeof (pixel_formats[0 ]), h);
165- return h ;
177+ return hash_fmix32 (h) ;
166178 }
167179};
168180
@@ -206,6 +218,97 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) MDResourceCache {
206218 ~MDResourceCache () = default ;
207219};
208220
221+ enum class MDAttachmentType : uint8_t {
222+ None = 0 ,
223+ Color = 1 << 0 ,
224+ Depth = 1 << 1 ,
225+ Stencil = 1 << 2 ,
226+ };
227+
228+ _FORCE_INLINE_ MDAttachmentType &operator|=(MDAttachmentType &p_a, MDAttachmentType p_b) {
229+ flags::set (p_a, p_b);
230+ return p_a;
231+ }
232+
233+ _FORCE_INLINE_ bool operator&(MDAttachmentType p_a, MDAttachmentType p_b) {
234+ return uint8_t (p_a) & uint8_t (p_b);
235+ }
236+
237+ struct MDSubpass {
238+ uint32_t subpass_index = 0 ;
239+ uint32_t view_count = 0 ;
240+ LocalVector<RDD::AttachmentReference> input_references;
241+ LocalVector<RDD::AttachmentReference> color_references;
242+ RDD::AttachmentReference depth_stencil_reference;
243+ LocalVector<RDD::AttachmentReference> resolve_references;
244+
245+ MTLFmtCaps getRequiredFmtCapsForAttachmentAt (uint32_t p_index) const ;
246+ };
247+
248+ struct API_AVAILABLE (macos(11.0 ), ios(14.0 )) MDAttachment {
249+ private:
250+ uint32_t index = 0 ;
251+ uint32_t firstUseSubpassIndex = 0 ;
252+ uint32_t lastUseSubpassIndex = 0 ;
253+
254+ public:
255+ MTLPixelFormat format = MTLPixelFormatInvalid ;
256+ MDAttachmentType type = MDAttachmentType::None;
257+ MTLLoadAction loadAction = MTLLoadActionDontCare ;
258+ MTLStoreAction storeAction = MTLStoreActionDontCare ;
259+ MTLLoadAction stencilLoadAction = MTLLoadActionDontCare ;
260+ MTLStoreAction stencilStoreAction = MTLStoreActionDontCare ;
261+ uint32_t samples = 1 ;
262+
263+ /* !
264+ * @brief Returns true if this attachment is first used in the given subpass.
265+ * @param p_subpass
266+ * @return
267+ */
268+ _FORCE_INLINE_ bool isFirstUseOf (MDSubpass const &p_subpass) const {
269+ return p_subpass.subpass_index == firstUseSubpassIndex;
270+ }
271+
272+ /* !
273+ * @brief Returns true if this attachment is last used in the given subpass.
274+ * @param p_subpass
275+ * @return
276+ */
277+ _FORCE_INLINE_ bool isLastUseOf (MDSubpass const &p_subpass) const {
278+ return p_subpass.subpass_index == lastUseSubpassIndex;
279+ }
280+
281+ void linkToSubpass (MDRenderPass const &p_pass);
282+
283+ MTLStoreAction getMTLStoreAction (MDSubpass const &p_subpass,
284+ bool p_is_rendering_entire_area,
285+ bool p_has_resolve,
286+ bool p_can_resolve,
287+ bool p_is_stencil) const ;
288+ bool configureDescriptor (MTLRenderPassAttachmentDescriptor *p_desc,
289+ PixelFormats &p_pf,
290+ MDSubpass const &p_subpass,
291+ id <MTLTexture > p_attachment,
292+ bool p_is_rendering_entire_area,
293+ bool p_has_resolve,
294+ bool p_can_resolve,
295+ bool p_is_stencil) const ;
296+ /* * Returns whether this attachment should be cleared in the subpass. */
297+ bool shouldClear (MDSubpass const &p_subpass, bool p_is_stencil) const ;
298+ };
299+
300+ class API_AVAILABLE (macos(11.0 ), ios(14.0 )) MDRenderPass {
301+ public:
302+ Vector<MDAttachment> attachments;
303+ Vector<MDSubpass> subpasses;
304+
305+ uint32_t get_sample_count () const {
306+ return attachments.is_empty () ? 1 : attachments[0 ].samples ;
307+ }
308+
309+ MDRenderPass (Vector<MDAttachment> &p_attachments, Vector<MDSubpass> &p_subpasses);
310+ };
311+
209312class API_AVAILABLE (macos(11.0 ), ios(14.0 )) MDCommandBuffer {
210313private:
211314 RenderingDeviceDriverMetal *device_driver = nullptr ;
@@ -220,8 +323,8 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) MDCommandBuffer {
220323 void _render_set_dirty_state ();
221324 void _render_bind_uniform_sets ();
222325
223- static void _populate_vertices (simd::float4 *p_vertices, Size2i p_fb_size, VectorView<Rect2i> p_rects);
224- static uint32_t _populate_vertices (simd::float4 *p_vertices, uint32_t p_index, Rect2i const &p_rect, Size2i p_fb_size);
326+ void _populate_vertices (simd::float4 *p_vertices, Size2i p_fb_size, VectorView<Rect2i> p_rects);
327+ uint32_t _populate_vertices (simd::float4 *p_vertices, uint32_t p_index, Rect2i const &p_rect, Size2i p_fb_size);
225328 void _end_render_pass ();
226329 void _render_clear_render_area ();
227330
@@ -268,34 +371,14 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) MDCommandBuffer {
268371 // Bit mask of the uniform sets that are dirty, to prevent redundant binding.
269372 uint64_t uniform_set_mask = 0 ;
270373
271- _FORCE_INLINE_ void reset () {
272- pass = nil ;
273- frameBuffer = nil ;
274- pipeline = nil ;
275- current_subpass = UINT32_MAX;
276- render_area = {};
277- is_rendering_entire_area = false ;
278- desc = nil ;
279- encoder = nil ;
280- index_buffer = nil ;
281- index_type = MTLIndexTypeUInt16 ;
282- dirty = DIRTY_NONE;
283- uniform_sets.clear ();
284- uniform_set_mask = 0 ;
285- clear_values.clear ();
286- viewports.clear ();
287- scissors.clear ();
288- blend_constants.reset ();
289- vertex_buffers.clear ();
290- vertex_offsets.clear ();
291- // Keep the keys, as they are likely to be used again.
292- for (KeyValue<StageResourceUsage, LocalVector<__unsafe_unretained id <MTLResource >>> &kv : resource_usage) {
293- kv.value .clear ();
294- }
295- }
296-
374+ _FORCE_INLINE_ void reset ();
297375 void end_encoding ();
298376
377+ _ALWAYS_INLINE_ const MDSubpass &get_subpass () const {
378+ DEV_ASSERT (pass != nullptr );
379+ return pass->subpasses [current_subpass];
380+ }
381+
299382 _FORCE_INLINE_ void mark_viewport_dirty () {
300383 if (viewports.is_empty ()) {
301384 return ;
@@ -649,6 +732,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) MDRenderShader final : public MDShad
649732 uint32_t size = 0 ;
650733 } frag;
651734 } push_constants;
735+ bool needs_view_mask_buffer = false ;
652736
653737 MDLibrary *vert;
654738 MDLibrary *frag;
@@ -659,7 +743,10 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) MDRenderShader final : public MDShad
659743
660744 void encode_push_constant_data (VectorView<uint32_t > p_data, MDCommandBuffer *p_cb) final;
661745
662- MDRenderShader (CharString p_name, Vector<UniformSet> p_sets, MDLibrary *p_vert, MDLibrary *p_frag);
746+ MDRenderShader (CharString p_name,
747+ bool p_needs_view_mask_buffer,
748+ Vector<UniformSet> p_sets,
749+ MDLibrary *p_vert, MDLibrary *p_frag);
663750};
664751
665752_FORCE_INLINE_ StageResourceUsage &operator|=(StageResourceUsage &p_a, uint32_t p_b) {
@@ -702,96 +789,6 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) MDUniformSet {
702789 BoundUniformSet &boundUniformSetForShader (MDShader *p_shader, id <MTLDevice > p_device);
703790};
704791
705- enum class MDAttachmentType : uint8_t {
706- None = 0 ,
707- Color = 1 << 0 ,
708- Depth = 1 << 1 ,
709- Stencil = 1 << 2 ,
710- };
711-
712- _FORCE_INLINE_ MDAttachmentType &operator|=(MDAttachmentType &p_a, MDAttachmentType p_b) {
713- flags::set (p_a, p_b);
714- return p_a;
715- }
716-
717- _FORCE_INLINE_ bool operator&(MDAttachmentType p_a, MDAttachmentType p_b) {
718- return uint8_t (p_a) & uint8_t (p_b);
719- }
720-
721- struct MDSubpass {
722- uint32_t subpass_index = 0 ;
723- LocalVector<RDD::AttachmentReference> input_references;
724- LocalVector<RDD::AttachmentReference> color_references;
725- RDD::AttachmentReference depth_stencil_reference;
726- LocalVector<RDD::AttachmentReference> resolve_references;
727-
728- MTLFmtCaps getRequiredFmtCapsForAttachmentAt (uint32_t p_index) const ;
729- };
730-
731- struct API_AVAILABLE (macos(11.0 ), ios(14.0 )) MDAttachment {
732- private:
733- uint32_t index = 0 ;
734- uint32_t firstUseSubpassIndex = 0 ;
735- uint32_t lastUseSubpassIndex = 0 ;
736-
737- public:
738- MTLPixelFormat format = MTLPixelFormatInvalid ;
739- MDAttachmentType type = MDAttachmentType::None;
740- MTLLoadAction loadAction = MTLLoadActionDontCare ;
741- MTLStoreAction storeAction = MTLStoreActionDontCare ;
742- MTLLoadAction stencilLoadAction = MTLLoadActionDontCare ;
743- MTLStoreAction stencilStoreAction = MTLStoreActionDontCare ;
744- uint32_t samples = 1 ;
745-
746- /* !
747- * @brief Returns true if this attachment is first used in the given subpass.
748- * @param p_subpass
749- * @return
750- */
751- _FORCE_INLINE_ bool isFirstUseOf (MDSubpass const &p_subpass) const {
752- return p_subpass.subpass_index == firstUseSubpassIndex;
753- }
754-
755- /* !
756- * @brief Returns true if this attachment is last used in the given subpass.
757- * @param p_subpass
758- * @return
759- */
760- _FORCE_INLINE_ bool isLastUseOf (MDSubpass const &p_subpass) const {
761- return p_subpass.subpass_index == lastUseSubpassIndex;
762- }
763-
764- void linkToSubpass (MDRenderPass const &p_pass);
765-
766- MTLStoreAction getMTLStoreAction (MDSubpass const &p_subpass,
767- bool p_is_rendering_entire_area,
768- bool p_has_resolve,
769- bool p_can_resolve,
770- bool p_is_stencil) const ;
771- bool configureDescriptor (MTLRenderPassAttachmentDescriptor *p_desc,
772- PixelFormats &p_pf,
773- MDSubpass const &p_subpass,
774- id <MTLTexture > p_attachment,
775- bool p_is_rendering_entire_area,
776- bool p_has_resolve,
777- bool p_can_resolve,
778- bool p_is_stencil) const ;
779- /* * Returns whether this attachment should be cleared in the subpass. */
780- bool shouldClear (MDSubpass const &p_subpass, bool p_is_stencil) const ;
781- };
782-
783- class API_AVAILABLE (macos(11.0 ), ios(14.0 )) MDRenderPass {
784- public:
785- Vector<MDAttachment> attachments;
786- Vector<MDSubpass> subpasses;
787-
788- uint32_t get_sample_count () const {
789- return attachments.is_empty () ? 1 : attachments[0 ].samples ;
790- }
791-
792- MDRenderPass (Vector<MDAttachment> &p_attachments, Vector<MDSubpass> &p_subpasses);
793- };
794-
795792class API_AVAILABLE (macos(11.0 ), ios(14.0 )) MDPipeline {
796793public:
797794 MDPipelineType type;
@@ -892,13 +889,39 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) MDComputePipeline final : public MDP
892889};
893890
894891class API_AVAILABLE (macos(11.0 ), ios(14.0 )) MDFrameBuffer {
895- public:
896892 Vector<MTL::Texture> textures;
893+
894+ public:
897895 Size2i size;
898896 MDFrameBuffer (Vector<MTL::Texture> p_textures, Size2i p_size) :
899897 textures (p_textures), size (p_size) {}
900898 MDFrameBuffer () {}
901899
900+ // / Returns the texture at the given index.
901+ _ALWAYS_INLINE_ MTL::Texture get_texture (uint32_t p_idx) const {
902+ return textures[p_idx];
903+ }
904+
905+ // / Returns true if the texture at the given index is not nil.
906+ _ALWAYS_INLINE_ bool has_texture (uint32_t p_idx) const {
907+ return textures[p_idx] != nil ;
908+ }
909+
910+ // / Set the texture at the given index.
911+ _ALWAYS_INLINE_ void set_texture (uint32_t p_idx, MTL::Texture p_texture) {
912+ textures.write [p_idx] = p_texture;
913+ }
914+
915+ // / Unset or nil the texture at the given index.
916+ _ALWAYS_INLINE_ void unset_texture (uint32_t p_idx) {
917+ textures.write [p_idx] = nil ;
918+ }
919+
920+ // / Resizes buffers to the specified size.
921+ _ALWAYS_INLINE_ void set_texture_count (uint32_t p_size) {
922+ textures.resize (p_size);
923+ }
924+
902925 virtual ~MDFrameBuffer () = default ;
903926};
904927
0 commit comments