@@ -5,7 +5,7 @@ use core::ops::Range;
5
5
use crate :: command:: Command as TraceCommand ;
6
6
use crate :: {
7
7
api_log,
8
- command:: EncoderStateError ,
8
+ command:: { CommandBufferMutable , CommandEncoder , EncoderStateError } ,
9
9
device:: { DeviceError , MissingFeatures } ,
10
10
get_lowest_common_denom,
11
11
global:: Global ,
@@ -119,74 +119,7 @@ impl Global {
119
119
let cmd_enc = hub. command_encoders . get ( command_encoder_id) ;
120
120
let mut cmd_buf_data = cmd_enc. data . lock ( ) ;
121
121
cmd_buf_data. record_with ( |cmd_buf_data| -> Result < ( ) , ClearError > {
122
- #[ cfg( feature = "trace" ) ]
123
- if let Some ( ref mut list) = cmd_buf_data. trace_commands {
124
- list. push ( TraceCommand :: ClearBuffer { dst, offset, size } ) ;
125
- }
126
-
127
- cmd_enc. device . check_is_valid ( ) ?;
128
-
129
- let dst_buffer = hub. buffers . get ( dst) . get ( ) ?;
130
-
131
- dst_buffer. same_device_as ( cmd_enc. as_ref ( ) ) ?;
132
-
133
- let dst_pending = cmd_buf_data
134
- . trackers
135
- . buffers
136
- . set_single ( & dst_buffer, wgt:: BufferUses :: COPY_DST ) ;
137
-
138
- let snatch_guard = dst_buffer. device . snatchable_lock . read ( ) ;
139
- let dst_raw = dst_buffer. try_raw ( & snatch_guard) ?;
140
- dst_buffer. check_usage ( BufferUsages :: COPY_DST ) ?;
141
-
142
- // Check if offset & size are valid.
143
- if offset % wgt:: COPY_BUFFER_ALIGNMENT != 0 {
144
- return Err ( ClearError :: UnalignedBufferOffset ( offset) ) ;
145
- }
146
-
147
- let size = size. unwrap_or ( dst_buffer. size . saturating_sub ( offset) ) ;
148
- if size % wgt:: COPY_BUFFER_ALIGNMENT != 0 {
149
- return Err ( ClearError :: UnalignedFillSize ( size) ) ;
150
- }
151
- let end_offset =
152
- offset
153
- . checked_add ( size)
154
- . ok_or ( ClearError :: OffsetPlusSizeExceeds64BitBounds {
155
- start_offset : offset,
156
- requested_size : size,
157
- } ) ?;
158
- if end_offset > dst_buffer. size {
159
- return Err ( ClearError :: BufferOverrun {
160
- start_offset : offset,
161
- end_offset,
162
- buffer_size : dst_buffer. size ,
163
- } ) ;
164
- }
165
-
166
- if offset == end_offset {
167
- log:: trace!( "Ignoring fill_buffer of size 0" ) ;
168
- return Ok ( ( ) ) ;
169
- }
170
-
171
- // Mark dest as initialized.
172
- cmd_buf_data. buffer_memory_init_actions . extend (
173
- dst_buffer. initialization_status . read ( ) . create_action (
174
- & dst_buffer,
175
- offset..end_offset,
176
- MemoryInitKind :: ImplicitlyInitialized ,
177
- ) ,
178
- ) ;
179
-
180
- // actual hal barrier & operation
181
- let dst_barrier =
182
- dst_pending. map ( |pending| pending. into_hal ( & dst_buffer, & snatch_guard) ) ;
183
- let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
184
- unsafe {
185
- cmd_buf_raw. transition_buffers ( dst_barrier. as_slice ( ) ) ;
186
- cmd_buf_raw. clear_buffer ( dst_raw, offset..end_offset) ;
187
- }
188
-
189
- Ok ( ( ) )
122
+ clear_buffer ( cmd_buf_data, hub, & cmd_enc, dst, offset, size)
190
123
} )
191
124
}
192
125
@@ -204,83 +137,181 @@ impl Global {
204
137
let cmd_enc = hub. command_encoders . get ( command_encoder_id) ;
205
138
let mut cmd_buf_data = cmd_enc. data . lock ( ) ;
206
139
cmd_buf_data. record_with ( |cmd_buf_data| -> Result < ( ) , ClearError > {
207
- #[ cfg( feature = "trace" ) ]
208
- if let Some ( ref mut list) = cmd_buf_data. trace_commands {
209
- list. push ( TraceCommand :: ClearTexture {
210
- dst,
211
- subresource_range : * subresource_range,
212
- } ) ;
213
- }
140
+ clear_texture_cmd ( cmd_buf_data, hub, & cmd_enc, dst, subresource_range)
141
+ } )
142
+ }
143
+ }
214
144
215
- cmd_enc. device . check_is_valid ( ) ?;
145
+ pub ( super ) fn clear_buffer (
146
+ cmd_buf_data : & mut CommandBufferMutable ,
147
+ hub : & crate :: hub:: Hub ,
148
+ cmd_enc : & Arc < CommandEncoder > ,
149
+ dst : BufferId ,
150
+ offset : BufferAddress ,
151
+ size : Option < BufferAddress > ,
152
+ ) -> Result < ( ) , ClearError > {
153
+ #[ cfg( feature = "trace" ) ]
154
+ if let Some ( ref mut list) = cmd_buf_data. trace_commands {
155
+ list. push ( TraceCommand :: ClearBuffer { dst, offset, size } ) ;
156
+ }
216
157
217
- cmd_enc
218
- . device
219
- . require_features ( wgt:: Features :: CLEAR_TEXTURE ) ?;
158
+ cmd_enc. device . check_is_valid ( ) ?;
220
159
221
- let dst_texture = hub. textures . get ( dst) . get ( ) ?;
160
+ let dst_buffer = hub. buffers . get ( dst) . get ( ) ?;
222
161
223
- dst_texture . same_device_as ( cmd_enc. as_ref ( ) ) ?;
162
+ dst_buffer . same_device_as ( cmd_enc. as_ref ( ) ) ?;
224
163
225
- // Check if subresource aspects are valid.
226
- let clear_aspects =
227
- hal:: FormatAspects :: new ( dst_texture. desc . format , subresource_range. aspect ) ;
228
- if clear_aspects. is_empty ( ) {
229
- return Err ( ClearError :: MissingTextureAspect {
230
- texture_format : dst_texture. desc . format ,
231
- subresource_range_aspects : subresource_range. aspect ,
232
- } ) ;
233
- } ;
164
+ let dst_pending = cmd_buf_data
165
+ . trackers
166
+ . buffers
167
+ . set_single ( & dst_buffer, wgt:: BufferUses :: COPY_DST ) ;
234
168
235
- // Check if subresource level range is valid
236
- let subresource_mip_range =
237
- subresource_range. mip_range ( dst_texture. full_range . mips . end ) ;
238
- if dst_texture. full_range . mips . start > subresource_mip_range. start
239
- || dst_texture. full_range . mips . end < subresource_mip_range. end
240
- {
241
- return Err ( ClearError :: InvalidTextureLevelRange {
242
- texture_level_range : dst_texture. full_range . mips . clone ( ) ,
243
- subresource_base_mip_level : subresource_range. base_mip_level ,
244
- subresource_mip_level_count : subresource_range. mip_level_count ,
245
- } ) ;
246
- }
247
- // Check if subresource layer range is valid
248
- let subresource_layer_range =
249
- subresource_range. layer_range ( dst_texture. full_range . layers . end ) ;
250
- if dst_texture. full_range . layers . start > subresource_layer_range. start
251
- || dst_texture. full_range . layers . end < subresource_layer_range. end
252
- {
253
- return Err ( ClearError :: InvalidTextureLayerRange {
254
- texture_layer_range : dst_texture. full_range . layers . clone ( ) ,
255
- subresource_base_array_layer : subresource_range. base_array_layer ,
256
- subresource_array_layer_count : subresource_range. array_layer_count ,
257
- } ) ;
258
- }
169
+ let snatch_guard = dst_buffer. device . snatchable_lock . read ( ) ;
170
+ let dst_raw = dst_buffer. try_raw ( & snatch_guard) ?;
171
+ dst_buffer. check_usage ( BufferUsages :: COPY_DST ) ?;
259
172
260
- let device = & cmd_enc. device ;
261
- device. check_is_valid ( ) ?;
262
- let ( encoder, tracker) = cmd_buf_data. open_encoder_and_tracker ( ) ?;
263
-
264
- let snatch_guard = device. snatchable_lock . read ( ) ;
265
- clear_texture (
266
- & dst_texture,
267
- TextureInitRange {
268
- mip_range : subresource_mip_range,
269
- layer_range : subresource_layer_range,
270
- } ,
271
- encoder,
272
- & mut tracker. textures ,
273
- & device. alignments ,
274
- device. zero_buffer . as_ref ( ) ,
275
- & snatch_guard,
276
- device. instance_flags ,
277
- ) ?;
278
-
279
- Ok ( ( ) )
280
- } )
173
+ // Check if offset & size are valid.
174
+ if offset % wgt:: COPY_BUFFER_ALIGNMENT != 0 {
175
+ return Err ( ClearError :: UnalignedBufferOffset ( offset) ) ;
176
+ }
177
+
178
+ let size = size. unwrap_or ( dst_buffer. size . saturating_sub ( offset) ) ;
179
+ if size % wgt:: COPY_BUFFER_ALIGNMENT != 0 {
180
+ return Err ( ClearError :: UnalignedFillSize ( size) ) ;
181
+ }
182
+ let end_offset =
183
+ offset
184
+ . checked_add ( size)
185
+ . ok_or ( ClearError :: OffsetPlusSizeExceeds64BitBounds {
186
+ start_offset : offset,
187
+ requested_size : size,
188
+ } ) ?;
189
+ if end_offset > dst_buffer. size {
190
+ return Err ( ClearError :: BufferOverrun {
191
+ start_offset : offset,
192
+ end_offset,
193
+ buffer_size : dst_buffer. size ,
194
+ } ) ;
281
195
}
196
+
197
+ if offset == end_offset {
198
+ log:: trace!( "Ignoring fill_buffer of size 0" ) ;
199
+ return Ok ( ( ) ) ;
200
+ }
201
+
202
+ // Mark dest as initialized.
203
+ cmd_buf_data. buffer_memory_init_actions . extend (
204
+ dst_buffer. initialization_status . read ( ) . create_action (
205
+ & dst_buffer,
206
+ offset..end_offset,
207
+ MemoryInitKind :: ImplicitlyInitialized ,
208
+ ) ,
209
+ ) ;
210
+
211
+ // actual hal barrier & operation
212
+ let dst_barrier = dst_pending. map ( |pending| pending. into_hal ( & dst_buffer, & snatch_guard) ) ;
213
+ let cmd_buf_raw = cmd_buf_data. encoder . open ( ) ?;
214
+ unsafe {
215
+ cmd_buf_raw. transition_buffers ( dst_barrier. as_slice ( ) ) ;
216
+ cmd_buf_raw. clear_buffer ( dst_raw, offset..end_offset) ;
217
+ }
218
+
219
+ Ok ( ( ) )
220
+ }
221
+
222
+ /// Validate and encode a "Clear Texture" command.
223
+ ///
224
+ /// This function implements `CommandEncoder::clear_texture` when invoked via
225
+ /// the command encoder APIs or trace playback. It has the suffix `_cmd` to
226
+ /// distinguish it from [`clear_texture`]. [`clear_texture`], used internally by
227
+ /// this function, is a lower-level function that encodes a texture clear
228
+ /// operation without validating it.
229
+ pub ( super ) fn clear_texture_cmd (
230
+ cmd_buf_data : & mut CommandBufferMutable ,
231
+ hub : & crate :: hub:: Hub ,
232
+ cmd_enc : & Arc < CommandEncoder > ,
233
+ dst : TextureId ,
234
+ subresource_range : & ImageSubresourceRange ,
235
+ ) -> Result < ( ) , ClearError > {
236
+ #[ cfg( feature = "trace" ) ]
237
+ if let Some ( ref mut list) = cmd_buf_data. trace_commands {
238
+ list. push ( TraceCommand :: ClearTexture {
239
+ dst,
240
+ subresource_range : * subresource_range,
241
+ } ) ;
242
+ }
243
+
244
+ cmd_enc. device . check_is_valid ( ) ?;
245
+
246
+ cmd_enc
247
+ . device
248
+ . require_features ( wgt:: Features :: CLEAR_TEXTURE ) ?;
249
+
250
+ let dst_texture = hub. textures . get ( dst) . get ( ) ?;
251
+
252
+ dst_texture. same_device_as ( cmd_enc. as_ref ( ) ) ?;
253
+
254
+ // Check if subresource aspects are valid.
255
+ let clear_aspects = hal:: FormatAspects :: new ( dst_texture. desc . format , subresource_range. aspect ) ;
256
+ if clear_aspects. is_empty ( ) {
257
+ return Err ( ClearError :: MissingTextureAspect {
258
+ texture_format : dst_texture. desc . format ,
259
+ subresource_range_aspects : subresource_range. aspect ,
260
+ } ) ;
261
+ } ;
262
+
263
+ // Check if subresource level range is valid
264
+ let subresource_mip_range = subresource_range. mip_range ( dst_texture. full_range . mips . end ) ;
265
+ if dst_texture. full_range . mips . start > subresource_mip_range. start
266
+ || dst_texture. full_range . mips . end < subresource_mip_range. end
267
+ {
268
+ return Err ( ClearError :: InvalidTextureLevelRange {
269
+ texture_level_range : dst_texture. full_range . mips . clone ( ) ,
270
+ subresource_base_mip_level : subresource_range. base_mip_level ,
271
+ subresource_mip_level_count : subresource_range. mip_level_count ,
272
+ } ) ;
273
+ }
274
+ // Check if subresource layer range is valid
275
+ let subresource_layer_range = subresource_range. layer_range ( dst_texture. full_range . layers . end ) ;
276
+ if dst_texture. full_range . layers . start > subresource_layer_range. start
277
+ || dst_texture. full_range . layers . end < subresource_layer_range. end
278
+ {
279
+ return Err ( ClearError :: InvalidTextureLayerRange {
280
+ texture_layer_range : dst_texture. full_range . layers . clone ( ) ,
281
+ subresource_base_array_layer : subresource_range. base_array_layer ,
282
+ subresource_array_layer_count : subresource_range. array_layer_count ,
283
+ } ) ;
284
+ }
285
+
286
+ let device = & cmd_enc. device ;
287
+ device. check_is_valid ( ) ?;
288
+ let ( encoder, tracker) = cmd_buf_data. open_encoder_and_tracker ( ) ?;
289
+
290
+ let snatch_guard = device. snatchable_lock . read ( ) ;
291
+ clear_texture (
292
+ & dst_texture,
293
+ TextureInitRange {
294
+ mip_range : subresource_mip_range,
295
+ layer_range : subresource_layer_range,
296
+ } ,
297
+ encoder,
298
+ & mut tracker. textures ,
299
+ & device. alignments ,
300
+ device. zero_buffer . as_ref ( ) ,
301
+ & snatch_guard,
302
+ device. instance_flags ,
303
+ ) ?;
304
+
305
+ Ok ( ( ) )
282
306
}
283
307
308
+ /// Encode a texture clear operation.
309
+ ///
310
+ /// This function encodes a texture clear operation without validating it.
311
+ /// Texture clears requested via the API call this function via
312
+ /// [`clear_texture_cmd`], which does the validation. This function is also
313
+ /// called directly from various places within wgpu that need to clear a
314
+ /// texture.
284
315
pub ( crate ) fn clear_texture < T : TextureTrackerSetSingle > (
285
316
dst_texture : & Arc < Texture > ,
286
317
range : TextureInitRange ,
0 commit comments