@@ -114,6 +114,53 @@ impl CommandEncoderStatus {
114114 }
115115 }
116116
117+ /// Record commands using the supplied closure.
118+ ///
119+ /// If the encoder is in the [`Self::Recording`] state, calls the closure to
120+ /// record commands. If the closure returns an error, stores that error in
121+ /// the encoder for later reporting when `finish()` is called. Returns
122+ /// `Ok(())` even if the closure returned an error.
123+ ///
124+ /// If the encoder is not in the [`Self::Recording`] state, the closure will
125+ /// not be called and nothing will be recorded. The encoder will be
126+ /// invalidated (if it is not already). If the error is a [validation error
127+ /// that should be raised immediately][ves], returns it in `Err`, otherwise,
128+ /// returns `Ok(())`.
129+ ///
130+ /// [ves]: https://www.w3.org/TR/webgpu/#abstract-opdef-validate-the-encoder-state
131+ fn record_with <
132+ F : FnOnce ( & mut CommandBufferMutable ) -> Result < ( ) , E > ,
133+ E : Clone + Into < CommandEncoderError > ,
134+ > (
135+ & mut self ,
136+ f : F ,
137+ ) -> Result < ( ) , EncoderStateError > {
138+ let err = match self . record ( ) {
139+ Ok ( guard) => {
140+ guard. record ( f) ;
141+ return Ok ( ( ) ) ;
142+ }
143+ Err ( err) => err,
144+ } ;
145+ match err {
146+ err @ EncoderStateError :: Locked => {
147+ // Invalidate the encoder and do not record anything, but do not
148+ // return an immediate validation error.
149+ self . invalidate ( err) ;
150+ Ok ( ( ) )
151+ }
152+ err @ EncoderStateError :: Ended => {
153+ // Invalidate the encoder, do not record anything, and return an
154+ // immediate validation error.
155+ Err ( self . invalidate ( err) )
156+ }
157+ // Encoder is already invalid. Do not record anything, but do not
158+ // return an immediate validation error.
159+ EncoderStateError :: Invalid => Ok ( ( ) ) ,
160+ EncoderStateError :: Unlocked | EncoderStateError :: Submitted => unreachable ! ( ) ,
161+ }
162+ }
163+
117164 #[ cfg( feature = "trace" ) ]
118165 fn get_inner ( & mut self ) -> & mut CommandBufferMutable {
119166 match self {
@@ -230,6 +277,21 @@ impl<'a> RecordingGuard<'a> {
230277 pub ( crate ) fn mark_successful ( self ) {
231278 mem:: forget ( self )
232279 }
280+
281+ fn record <
282+ F : FnOnce ( & mut CommandBufferMutable ) -> Result < ( ) , E > ,
283+ E : Clone + Into < CommandEncoderError > ,
284+ > (
285+ mut self ,
286+ f : F ,
287+ ) {
288+ match f ( & mut self ) {
289+ Ok ( ( ) ) => self . mark_successful ( ) ,
290+ Err ( err) => {
291+ self . inner . invalidate ( err) ;
292+ }
293+ }
294+ }
233295}
234296
235297impl < ' a > Drop for RecordingGuard < ' a > {
@@ -859,104 +921,98 @@ impl Global {
859921 & self ,
860922 encoder_id : id:: CommandEncoderId ,
861923 label : & str ,
862- ) -> Result < ( ) , CommandEncoderError > {
924+ ) -> Result < ( ) , EncoderStateError > {
863925 profiling:: scope!( "CommandEncoder::push_debug_group" ) ;
864926 api_log ! ( "CommandEncoder::push_debug_group {label}" ) ;
865927
866928 let hub = & self . hub ;
867929
868930 let cmd_buf = hub. command_buffers . get ( encoder_id. into_command_buffer_id ( ) ) ;
869931 let mut cmd_buf_data = cmd_buf. data . lock ( ) ;
870- let mut cmd_buf_data_guard = cmd_buf_data. record ( ) ?;
871- let cmd_buf_data = & mut * cmd_buf_data_guard;
872-
873- #[ cfg( feature = "trace" ) ]
874- if let Some ( ref mut list) = cmd_buf_data. commands {
875- list. push ( TraceCommand :: PushDebugGroup ( label. to_owned ( ) ) ) ;
876- }
932+ cmd_buf_data. record_with ( |cmd_buf_data| -> Result < ( ) , CommandEncoderError > {
933+ #[ cfg( feature = "trace" ) ]
934+ if let Some ( ref mut list) = cmd_buf_data. commands {
935+ list. push ( TraceCommand :: PushDebugGroup ( label. to_owned ( ) ) ) ;
936+ }
877937
878- let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
879- if !cmd_buf
880- . device
881- . instance_flags
882- . contains ( wgt:: InstanceFlags :: DISCARD_HAL_LABELS )
883- {
884- unsafe {
885- cmd_buf_raw. begin_debug_marker ( label) ;
938+ let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
939+ if !cmd_buf
940+ . device
941+ . instance_flags
942+ . contains ( wgt:: InstanceFlags :: DISCARD_HAL_LABELS )
943+ {
944+ unsafe {
945+ cmd_buf_raw. begin_debug_marker ( label) ;
946+ }
886947 }
887- }
888948
889- cmd_buf_data_guard . mark_successful ( ) ;
890- Ok ( ( ) )
949+ Ok ( ( ) )
950+ } )
891951 }
892952
893953 pub fn command_encoder_insert_debug_marker (
894954 & self ,
895955 encoder_id : id:: CommandEncoderId ,
896956 label : & str ,
897- ) -> Result < ( ) , CommandEncoderError > {
957+ ) -> Result < ( ) , EncoderStateError > {
898958 profiling:: scope!( "CommandEncoder::insert_debug_marker" ) ;
899959 api_log ! ( "CommandEncoder::insert_debug_marker {label}" ) ;
900960
901961 let hub = & self . hub ;
902962
903963 let cmd_buf = hub. command_buffers . get ( encoder_id. into_command_buffer_id ( ) ) ;
904964 let mut cmd_buf_data = cmd_buf. data . lock ( ) ;
905- let mut cmd_buf_data_guard = cmd_buf_data. record ( ) ?;
906- let cmd_buf_data = & mut * cmd_buf_data_guard;
907-
908- #[ cfg( feature = "trace" ) ]
909- if let Some ( ref mut list) = cmd_buf_data. commands {
910- list. push ( TraceCommand :: InsertDebugMarker ( label. to_owned ( ) ) ) ;
911- }
965+ cmd_buf_data. record_with ( |cmd_buf_data| -> Result < ( ) , CommandEncoderError > {
966+ #[ cfg( feature = "trace" ) ]
967+ if let Some ( ref mut list) = cmd_buf_data. commands {
968+ list. push ( TraceCommand :: InsertDebugMarker ( label. to_owned ( ) ) ) ;
969+ }
912970
913- if !cmd_buf
914- . device
915- . instance_flags
916- . contains ( wgt:: InstanceFlags :: DISCARD_HAL_LABELS )
917- {
918- let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
919- unsafe {
920- cmd_buf_raw. insert_debug_marker ( label) ;
971+ if !cmd_buf
972+ . device
973+ . instance_flags
974+ . contains ( wgt:: InstanceFlags :: DISCARD_HAL_LABELS )
975+ {
976+ let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
977+ unsafe {
978+ cmd_buf_raw. insert_debug_marker ( label) ;
979+ }
921980 }
922- }
923981
924- cmd_buf_data_guard . mark_successful ( ) ;
925- Ok ( ( ) )
982+ Ok ( ( ) )
983+ } )
926984 }
927985
928986 pub fn command_encoder_pop_debug_group (
929987 & self ,
930988 encoder_id : id:: CommandEncoderId ,
931- ) -> Result < ( ) , CommandEncoderError > {
989+ ) -> Result < ( ) , EncoderStateError > {
932990 profiling:: scope!( "CommandEncoder::pop_debug_marker" ) ;
933991 api_log ! ( "CommandEncoder::pop_debug_group" ) ;
934992
935993 let hub = & self . hub ;
936994
937995 let cmd_buf = hub. command_buffers . get ( encoder_id. into_command_buffer_id ( ) ) ;
938996 let mut cmd_buf_data = cmd_buf. data . lock ( ) ;
939- let mut cmd_buf_data_guard = cmd_buf_data. record ( ) ?;
940- let cmd_buf_data = & mut * cmd_buf_data_guard;
941-
942- #[ cfg( feature = "trace" ) ]
943- if let Some ( ref mut list) = cmd_buf_data. commands {
944- list. push ( TraceCommand :: PopDebugGroup ) ;
945- }
997+ cmd_buf_data. record_with ( |cmd_buf_data| -> Result < ( ) , CommandEncoderError > {
998+ #[ cfg( feature = "trace" ) ]
999+ if let Some ( ref mut list) = cmd_buf_data. commands {
1000+ list. push ( TraceCommand :: PopDebugGroup ) ;
1001+ }
9461002
947- let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
948- if !cmd_buf
949- . device
950- . instance_flags
951- . contains ( wgt:: InstanceFlags :: DISCARD_HAL_LABELS )
952- {
953- unsafe {
954- cmd_buf_raw. end_debug_marker ( ) ;
1003+ let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
1004+ if !cmd_buf
1005+ . device
1006+ . instance_flags
1007+ . contains ( wgt:: InstanceFlags :: DISCARD_HAL_LABELS )
1008+ {
1009+ unsafe {
1010+ cmd_buf_raw. end_debug_marker ( ) ;
1011+ }
9551012 }
956- }
9571013
958- cmd_buf_data_guard . mark_successful ( ) ;
959- Ok ( ( ) )
1014+ Ok ( ( ) )
1015+ } )
9601016 }
9611017
9621018 fn validate_pass_timestamp_writes (
0 commit comments