197197< a href ="#196 " id ="196 "> 196</ a >
198198< a href ="#197 " id ="197 "> 197</ a >
199199< a href ="#198 " id ="198 "> 198</ a >
200- < a href ="#199 " id ="199 "> 199</ a > </ pre > </ div > < pre class ="rust "> < code > < span class ="kw "> use crate</ span > ::{
200+ < a href ="#199 " id ="199 "> 199</ a >
201+ < a href ="#200 " id ="200 "> 200</ a >
202+ < a href ="#201 " id ="201 "> 201</ a >
203+ < a href ="#202 " id ="202 "> 202</ a >
204+ < a href ="#203 " id ="203 "> 203</ a >
205+ < a href ="#204 " id ="204 "> 204</ a >
206+ < a href ="#205 " id ="205 "> 205</ a >
207+ < a href ="#206 " id ="206 "> 206</ a >
208+ < a href ="#207 " id ="207 "> 207</ a >
209+ < a href ="#208 " id ="208 "> 208</ a >
210+ < a href ="#209 " id ="209 "> 209</ a >
211+ < a href ="#210 " id ="210 "> 210</ a >
212+ < a href ="#211 " id ="211 "> 211</ a >
213+ < a href ="#212 " id ="212 "> 212</ a >
214+ < a href ="#213 " id ="213 "> 213</ a >
215+ < a href ="#214 " id ="214 "> 214</ a >
216+ < a href ="#215 " id ="215 "> 215</ a >
217+ < a href ="#216 " id ="216 "> 216</ a >
218+ < a href ="#217 " id ="217 "> 217</ a >
219+ < a href ="#218 " id ="218 "> 218</ a >
220+ < a href ="#219 " id ="219 "> 219</ a >
221+ < a href ="#220 " id ="220 "> 220</ a >
222+ < a href ="#221 " id ="221 "> 221</ a >
223+ < a href ="#222 " id ="222 "> 222</ a >
224+ < a href ="#223 " id ="223 "> 223</ a >
225+ < a href ="#224 " id ="224 "> 224</ a >
226+ < a href ="#225 " id ="225 "> 225</ a >
227+ < a href ="#226 " id ="226 "> 226</ a >
228+ < a href ="#227 " id ="227 "> 227</ a >
229+ < a href ="#228 " id ="228 "> 228</ a >
230+ < a href ="#229 " id ="229 "> 229</ a >
231+ < a href ="#230 " id ="230 "> 230</ a >
232+ < a href ="#231 " id ="231 "> 231</ a >
233+ < a href ="#232 " id ="232 "> 232</ a >
234+ < a href ="#233 " id ="233 "> 233</ a >
235+ < a href ="#234 " id ="234 "> 234</ a >
236+ < a href ="#235 " id ="235 "> 235</ a >
237+ < a href ="#236 " id ="236 "> 236</ a >
238+ < a href ="#237 " id ="237 "> 237</ a >
239+ < a href ="#238 " id ="238 "> 238</ a >
240+ < a href ="#239 " id ="239 "> 239</ a >
241+ < a href ="#240 " id ="240 "> 240</ a >
242+ < a href ="#241 " id ="241 "> 241</ a >
243+ < a href ="#242 " id ="242 "> 242</ a >
244+ < a href ="#243 " id ="243 "> 243</ a >
245+ < a href ="#244 " id ="244 "> 244</ a >
246+ < a href ="#245 " id ="245 "> 245</ a >
247+ < a href ="#246 " id ="246 "> 246</ a >
248+ < a href ="#247 " id ="247 "> 247</ a >
249+ < a href ="#248 " id ="248 "> 248</ a >
250+ < a href ="#249 " id ="249 "> 249</ a >
251+ < a href ="#250 " id ="250 "> 250</ a >
252+ < a href ="#251 " id ="251 "> 251</ a >
253+ < a href ="#252 " id ="252 "> 252</ a >
254+ < a href ="#253 " id ="253 "> 253</ a >
255+ < a href ="#254 " id ="254 "> 254</ a >
256+ < a href ="#255 " id ="255 "> 255</ a >
257+ < a href ="#256 " id ="256 "> 256</ a >
258+ < a href ="#257 " id ="257 "> 257</ a >
259+ < a href ="#258 " id ="258 "> 258</ a >
260+ < a href ="#259 " id ="259 "> 259</ a >
261+ < a href ="#260 " id ="260 "> 260</ a >
262+ < a href ="#261 " id ="261 "> 261</ a >
263+ < a href ="#262 " id ="262 "> 262</ a >
264+ < a href ="#263 " id ="263 "> 263</ a >
265+ < a href ="#264 " id ="264 "> 264</ a >
266+ < a href ="#265 " id ="265 "> 265</ a >
267+ < a href ="#266 " id ="266 "> 266</ a >
268+ < a href ="#267 " id ="267 "> 267</ a >
269+ < a href ="#268 " id ="268 "> 268</ a >
270+ < a href ="#269 " id ="269 "> 269</ a >
271+ < a href ="#270 " id ="270 "> 270</ a >
272+ < a href ="#271 " id ="271 "> 271</ a >
273+ < a href ="#272 " id ="272 "> 272</ a > </ pre > </ div > < pre class ="rust "> < code > < span class ="kw "> use crate</ span > ::{
201274 util::align_to, Buffer, BufferAddress, BufferDescriptor, BufferSize, BufferUsages,
202275 BufferViewMut, CommandEncoder, Device, MapMode,
203276};
204277< span class ="kw "> use </ span > std::fmt;
205- < span class ="kw "> use </ span > std::sync::{mpsc, Arc};
206-
207- < span class ="kw "> struct </ span > Chunk {
208- buffer: Arc<Buffer>,
209- size: BufferAddress,
210- offset: BufferAddress,
211- }
212-
213- < span class ="doccomment "> /// `Sync` wrapper that works by providing only exclusive access.
214- ///
215- /// See https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html
216- </ span > < span class ="kw "> struct </ span > Exclusive<T>(T);
217-
218- < span class ="kw "> unsafe impl</ span > <T> Sync < span class ="kw "> for </ span > Exclusive<T> {}
219-
220- < span class ="kw "> impl</ span > <T> Exclusive<T> {
221- < span class ="kw "> fn </ span > new(value: T) -> < span class ="self "> Self </ span > {
222- < span class ="self "> Self</ span > (value)
223- }
224-
225- < span class ="kw "> fn </ span > get_mut(< span class ="kw-2 "> &mut </ span > < span class ="self "> self</ span > ) -> < span class ="kw-2 "> &mut </ span > T {
226- < span class ="kw-2 "> &mut </ span > < span class ="self "> self</ span > .< span class ="number "> 0
227- </ span > }
228- }
278+ < span class ="kw "> use </ span > std::sync::mpsc;
229279
230280< span class ="doccomment "> /// Efficiently performs many buffer writes by sharing and reusing temporary buffers.
231281///
232282/// Internally it uses a ring-buffer of staging buffers that are sub-allocated.
233- /// It has an advantage over [`Queue::write_buffer()`] in a way that it returns a mutable slice,
234- /// which you can fill to avoid an extra data copy.
283+ /// Its advantage over [`Queue::write_buffer_with()`] is that the individual allocations
284+ /// are cheaper; `StagingBelt` is most useful when you are writing very many small pieces
285+ /// of data. It can be understood as a sort of arena allocator.
235286///
236287/// Using a staging belt is slightly complicated, and generally goes as follows:
237- /// 1. Write to buffers that need writing to using [`StagingBelt::write_buffer()`].
288+ /// 1. Use [`StagingBelt::write_buffer()`] or [`StagingBelt::allocate()`] to allocate
289+ /// buffer slices, then write your data to them.
238290/// 2. Call [`StagingBelt::finish()`].
239291/// 3. Submit all command encoders that were used in step 1.
240292/// 4. Call [`StagingBelt::recall()`].
241293///
242- /// [`Queue::write_buffer ()`]: crate::Queue::write_buffer
294+ /// [`Queue::write_buffer_with ()`]: crate::Queue::write_buffer_with
243295</ span > < span class ="kw "> pub struct </ span > StagingBelt {
244296 chunk_size: BufferAddress,
245297 < span class ="doccomment "> /// Chunks into which we are accumulating data to be transferred.
246298 </ span > active_chunks: Vec<Chunk>,
247299 < span class ="doccomment "> /// Chunks that have scheduled transfers already; they are unmapped and some
248- /// command encoder has one or more `copy_buffer_to_buffer` commands with them
249- /// as source.
300+ /// command encoder has one or more commands with them as source.
250301 </ span > closed_chunks: Vec<Chunk>,
251302 < span class ="doccomment "> /// Chunks that are back from the GPU and ready to be mapped for write and put
252303 /// into `active_chunks`.
269320 /// (per [`StagingBelt::finish()`]); and
270321 /// * bigger is better, within these bounds.
271322 </ span > < span class ="kw "> pub fn </ span > new(chunk_size: BufferAddress) -> < span class ="self "> Self </ span > {
272- < span class ="kw "> let </ span > (sender, receiver) = std::sync:: mpsc::channel();
323+ < span class ="kw "> let </ span > (sender, receiver) = mpsc::channel();
273324 StagingBelt {
274325 chunk_size,
275326 active_chunks: Vec::new(),
280331 }
281332 }
282333
283- < span class ="doccomment "> /// Allocate the staging belt slice of `size` to be uploaded into the `target` buffer
334+ < span class ="doccomment "> /// Allocate a staging belt slice of `size` to be copied into the `target` buffer
284335 /// at the specified offset.
285336 ///
286337 /// The upload will be placed into the provided command encoder. This encoder
298349 size: BufferSize,
299350 device: < span class ="kw-2 "> &</ span > Device,
300351 ) -> BufferViewMut<< span class ="lifetime "> '_</ span > > {
352+ < span class ="kw "> let </ span > (mapped, belt_buffer, offset_in_belt_buffer) = < span class ="self "> self</ span > .allocate(
353+ size,
354+ < span class ="kw "> const </ span > { BufferSize::new(< span class ="kw "> crate</ span > ::COPY_BUFFER_ALIGNMENT).unwrap() },
355+ device,
356+ );
357+ encoder.copy_buffer_to_buffer(
358+ belt_buffer,
359+ offset_in_belt_buffer,
360+ target,
361+ offset,
362+ size.get(),
363+ );
364+ mapped
365+ }
366+
367+ < span class ="doccomment "> /// Allocate a staging belt slice with the given `size` and `alignment` and return it.
368+ ///
369+ /// This allows you to do whatever you want with the slice after, such as
370+ /// copying it to a texture or executing a compute shader that reads it, whereas
371+ /// [`StagingBelt::write_buffer()`] can only write to other buffers.
372+ ///
373+ /// If the `size` is greater than the space available in any free internal buffer, a new buffer
374+ /// will be allocated for it. Therefore, the `chunk_size` passed to [`StagingBelt::new()`]
375+ /// should ideally be larger than every such size.
376+ ///
377+ /// The chosen slice will be positioned within the buffer at a multiple of `alignment`,
378+ /// which may be used to meet alignment requirements for the operation you wish to perform
379+ /// with the slice. This does not necessarily affect the alignment of the mapping.
380+ ///
381+ /// Three values are returned:
382+ ///
383+ /// * The mapped buffer view which you should write into from the CPU side (Rust code).
384+ /// * The buffer containing the slice, for you to use in GPU commands.
385+ /// All commands involving this slice must be submitted after
386+ /// [`StagingBelt::finish()`] is called and before [`StagingBelt::recall()`] is called.
387+ /// * The offset within the buffer at which the slice starts.
388+ /// This offset should be used for all GPU commands, and should not be used with
389+ /// the mapped buffer view.
390+ </ span > < span class ="kw "> pub fn </ span > allocate(
391+ < span class ="kw-2 "> &mut </ span > < span class ="self "> self</ span > ,
392+ size: BufferSize,
393+ alignment: BufferSize,
394+ device: < span class ="kw-2 "> &</ span > Device,
395+ ) -> (BufferViewMut<< span class ="lifetime "> '_</ span > >, < span class ="kw-2 "> &</ span > Buffer, BufferAddress) {
396+ < span class ="macro "> assert!</ span > (
397+ alignment.get().is_power_of_two(),
398+ < span class ="string "> "alignment must be a power of two, not {alignment}"
399+ </ span > );
400+ < span class ="comment "> // At minimum, we must have alignment sufficient to map the buffer.
401+ </ span > < span class ="kw "> let </ span > alignment = alignment.get().max(< span class ="kw "> crate</ span > ::MAP_ALIGNMENT);
402+
301403 < span class ="kw "> let </ span > < span class ="kw-2 "> mut </ span > chunk = < span class ="kw "> if let </ span > < span class ="prelude-val "> Some</ span > (index) = < span class ="self "> self
302404 </ span > .active_chunks
303405 .iter()
304- .position(|chunk| chunk.offset + size.get() <= chunk. size)
406+ .position(|chunk| chunk.can_allocate( size, alignment) )
305407 {
306408 < span class ="self "> self</ span > .active_chunks.swap_remove(index)
307409 } < span class ="kw "> else </ span > {
310412 </ span > < span class ="kw "> if let </ span > < span class ="prelude-val "> Some</ span > (index) = < span class ="self "> self
311413 </ span > .free_chunks
312414 .iter()
313- .position(|chunk| size.get() <= chunk.size)
415+ .position(|chunk| chunk.can_allocate( size, alignment) )
314416 {
315417 < span class ="self "> self</ span > .free_chunks.swap_remove(index)
316418 } < span class ="kw "> else </ span > {
317- < span class ="kw "> let </ span > size = < span class ="self "> self</ span > .chunk_size.max(size.get());
318419 Chunk {
319- buffer: Arc::new( device.create_buffer(< span class ="kw-2 "> &</ span > BufferDescriptor {
420+ buffer: device.create_buffer(< span class ="kw-2 "> &</ span > BufferDescriptor {
320421 label: < span class ="prelude-val "> Some</ span > (< span class ="string "> "(wgpu internal) StagingBelt staging buffer"</ span > ),
321- size,
422+ size: < span class =" self " > self </ span > .chunk_size.max(size.get()) ,
322423 usage: BufferUsages::MAP_WRITE | BufferUsages::COPY_SRC,
323424 mapped_at_creation: < span class ="bool-val "> true</ span > ,
324- })),
325- size,
425+ }),
326426 offset: < span class ="number "> 0</ span > ,
327427 }
328428 }
329429 };
330430
331- encoder.copy_buffer_to_buffer(< span class ="kw-2 "> &</ span > chunk.buffer, chunk.offset, target, offset, size.get());
332- < span class ="kw "> let </ span > old_offset = chunk.offset;
333- chunk.offset = align_to(chunk.offset + size.get(), < span class ="kw "> crate</ span > ::MAP_ALIGNMENT);
431+ < span class ="kw "> let </ span > allocation_offset = chunk.allocate(size, alignment);
334432
335433 < span class ="self "> self</ span > .active_chunks.push(chunk);
336- < span class ="self "> self</ span > .active_chunks
337- .last()
338- .unwrap()
339- .buffer
340- .slice(old_offset..old_offset + size.get())
341- .get_mapped_range_mut()
434+ < span class ="kw "> let </ span > chunk = < span class ="self "> self</ span > .active_chunks.last().unwrap();
435+
436+ (
437+ chunk
438+ .buffer
439+ .slice(allocation_offset..allocation_offset + size.get())
440+ .get_mapped_range_mut(),
441+ < span class ="kw-2 "> &</ span > chunk.buffer,
442+ allocation_offset,
443+ )
342444 }
343445
344446 < span class ="doccomment "> /// Prepare currently mapped buffers for use in a submission.
396498 .finish_non_exhaustive()
397499 }
398500}
501+
502+ < span class ="kw "> struct </ span > Chunk {
503+ buffer: Buffer,
504+ offset: BufferAddress,
505+ }
506+
507+ < span class ="kw "> impl </ span > Chunk {
508+ < span class ="kw "> fn </ span > can_allocate(< span class ="kw-2 "> &</ span > < span class ="self "> self</ span > , size: BufferSize, alignment: BufferAddress) -> bool {
509+ < span class ="kw "> let </ span > alloc_start = align_to(< span class ="self "> self</ span > .offset, alignment);
510+ < span class ="kw "> let </ span > alloc_end = alloc_start + size.get();
511+
512+ alloc_end <= < span class ="self "> self</ span > .buffer.size()
513+ }
514+
515+ < span class ="kw "> fn </ span > allocate(< span class ="kw-2 "> &mut </ span > < span class ="self "> self</ span > , size: BufferSize, alignment: BufferAddress) -> BufferAddress {
516+ < span class ="kw "> let </ span > alloc_start = align_to(< span class ="self "> self</ span > .offset, alignment);
517+ < span class ="kw "> let </ span > alloc_end = alloc_start + size.get();
518+
519+ < span class ="macro "> assert!</ span > (alloc_end <= < span class ="self "> self</ span > .buffer.size());
520+ < span class ="self "> self</ span > .offset = alloc_end;
521+ alloc_start
522+ }
523+ }
524+
525+ < span class ="kw "> use </ span > exclusive::Exclusive;
526+ < span class ="kw "> mod </ span > exclusive {
527+ < span class ="doccomment "> /// `Sync` wrapper that works by providing only exclusive access.
528+ ///
529+ /// See <https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html>
530+ </ span > < span class ="kw "> pub</ span > (< span class ="kw "> super</ span > ) < span class ="kw "> struct </ span > Exclusive<T>(T);
531+
532+ < span class ="doccomment "> /// Safety: `&Exclusive` has no operations.
533+ </ span > < span class ="kw "> unsafe impl</ span > <T> Sync < span class ="kw "> for </ span > Exclusive<T> {}
534+
535+ < span class ="kw "> impl</ span > <T> Exclusive<T> {
536+ < span class ="kw "> pub fn </ span > new(value: T) -> < span class ="self "> Self </ span > {
537+ < span class ="self "> Self</ span > (value)
538+ }
539+
540+ < span class ="kw "> pub fn </ span > get_mut(< span class ="kw-2 "> &mut </ span > < span class ="self "> self</ span > ) -> < span class ="kw-2 "> &mut </ span > T {
541+ < span class ="kw-2 "> &mut </ span > < span class ="self "> self</ span > .< span class ="number "> 0
542+ </ span > }
543+ }
544+ }
399545</ code > </ pre > </ div > </ section > </ main > </ body > </ html >
0 commit comments