1use super::*;
2
3pub type GpuBufferAddress = wgpu::BufferAddress;
4pub trait GpuBufferNew<T>
7{
8 fn new(value: &[T], desc: GpuBufferDesc) -> Self;
9 fn with_capacity(capacity: usize, desc: GpuBufferDesc) -> Self;
10}
11pub trait GpuBufferByte
12{
13 fn bytes_len(&self) -> usize { self.wgpu_bytes_len() as _ }
14 fn wgpu_bytes_len(&self) -> GpuBufferAddress;
15
16 fn bytes_capacity(&self) -> usize { self.wgpu_bytes_capacity() as _ }
17 fn wgpu_bytes_capacity(&self) -> GpuBufferAddress { self.wgpu_bytes_len() }
18}
19
20pub trait GpuBufferAsWgpuSlice
21{
22 fn as_wgpu_slice(&self) -> wgpu::BufferSlice<'_>;
23}
24
25pub trait GpuAsUntypedSlice
26{
27 fn untyped_slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuUntypedSlice<'_>;
28
29 fn untyped_update<T>(&mut self, values: &[T])
30 where
31 T: BitAllUsed,
32 {
33 self.try_untyped_update(values)
34 .expect("failed to update the gpu buffer")
35 }
36 fn try_untyped_update<T>(&mut self, values: &[T]) -> Result<(), ()>
37 where
38 T: BitAllUsed,
39 {
40 self.untyped_slice(..).update(values)
41 }
42}
43
44pub trait GpuBufferRead<T>: GpuBufferByte
45{
46 fn len(&self) -> usize { self.wgpu_len() as _ }
47 fn wgpu_len(&self) -> GpuBufferAddress
48 {
49 self.wgpu_bytes_len() / std::mem::size_of::<T>() as GpuBufferAddress
50 }
51
52 fn capacity(&self) -> usize { self.wgpu_capacity() as _ }
53 fn wgpu_capacity(&self) -> GpuBufferAddress
54 {
55 self.wgpu_bytes_capacity() / std::mem::size_of::<T>() as GpuBufferAddress
56 }
57
58 fn read(&self) -> GpuResult<Vec<T>>
59 where
60 T: BitZero + BitPattern,
61 {
62 let mut v = Vec::new();
63 self.read_in(&mut v)?;
64 Ok(v)
65 }
66 fn read_in(&self, vec: &mut Vec<T>) -> GpuResult
67 where
68 T: BitZero + BitPattern;
69
70 fn slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuSlice<'_, T>;
71
72 fn update(&mut self, values: &[T])
73 where
74 T: BitAllUsed,
75 {
76 self.try_update(values)
77 .expect("failed to update the gpu buffer")
78 }
79 fn try_update(&mut self, values: &[T]) -> Result<(), ()>
80 where
81 T: BitAllUsed,
82 {
83 self.slice(..).update(values)
84 }
85}
86
87impl<T> GpuBufferNew<T> for wgpu::Buffer
88where
89 T: BitAllUsed,
90{
91 fn new(value: &[T], desc: GpuBufferDesc) -> Self
92 {
93 Gpu.wgpu
94 .device
95 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
96 label: None,
97 contents: bit::transmute_slice(value),
98 usage: desc.usages.into(),
99 })
100 }
101
102 fn with_capacity(capacity: usize, desc: GpuBufferDesc) -> Self
103 {
104 Gpu.wgpu.device.create_buffer(&wgpu::BufferDescriptor {
105 label: None,
106 usage: desc.usages.into(),
107 size: (capacity * std::mem::size_of::<T>()) as _,
108 mapped_at_creation: false,
109 })
110 }
111}
112impl GpuBufferByte for wgpu::Buffer
113{
114 fn wgpu_bytes_len(&self) -> GpuBufferAddress { self.size() }
115}
116impl GpuAsUntypedSlice for wgpu::Buffer
117{
118 fn untyped_slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuUntypedSlice<'_>
119 {
120 let bytes_len = self.size();
121
122 let start = match bounds.start_bound()
123 {
124 Bound::Included(&v) => v as GpuBufferAddress,
125 Bound::Excluded(&v) => (v + 1) as GpuBufferAddress,
126 Bound::Unbounded => 0,
127 }
128 .min(bytes_len);
129
130 let end = match bounds.end_bound()
131 {
132 Bound::Included(&v) => (v + 1) as GpuBufferAddress,
133 Bound::Excluded(&v) => v as GpuBufferAddress,
134 Bound::Unbounded => bytes_len,
135 }
136 .min(bytes_len);
137
138 assert!(
139 start <= end,
140 "GpuUntypedSlice::untyped_slice: invalid range"
141 );
142
143 GpuUntypedSlice {
144 buffer: self,
145 offset: start,
146 size: end - start,
147 }
148 }
149}
150
151fn create_staging_and_copy_slice(slice: &wgpu::BufferSlice) -> wgpu::Buffer
152{
153 let size = slice.size().get();
154
155 let staging = Gpu.wgpu.device.create_buffer(&wgpu::BufferDescriptor {
156 label: Some("staging buffer"),
157 size,
158 usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
159 mapped_at_creation: false,
160 });
161
162 let mut encoder = Gpu
163 .wgpu
164 .device
165 .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
166
167 encoder.copy_buffer_to_buffer(slice.buffer(), slice.offset(), &staging, 0, size);
168
169 Gpu.wgpu.queue.submit(Some(encoder.finish()));
170 staging
171}
172
173impl<'a> GpuBufferByte for wgpu::BufferSlice<'a>
174{
175 fn wgpu_bytes_len(&self) -> GpuBufferAddress { self.size().get() }
176}
177
178impl<'a, T> GpuBufferRead<T> for wgpu::BufferSlice<'a>
179{
180 fn read_in(&self, vec: &mut Vec<T>) -> GpuResult
181 where
182 T: BitZero + BitPattern,
183 {
184 let byte_len = self.size().get() as GpuBufferAddress as usize;
185 let elem_count = byte_len / std::mem::size_of::<T>();
186
187 if vec.len() < elem_count
188 {
189 vec.resize(elem_count, T::zeroed());
190 }
191
192 let staging = create_staging_and_copy_slice(self);
193 let slice = staging.slice(..);
194
195 let status = std::sync::Arc::new(std::sync::Mutex::new(None));
196 let status_clone = status.clone();
197
198 slice.map_async(wgpu::MapMode::Read, move |res| {
199 *status_clone.lock().unwrap() = Some(res);
200 });
201
202 while status.lock().unwrap().is_none()
203 {
204 Gpu.wgpu.device.poll(wgpu::PollType::Wait);
205 }
206
207 match status.lock().unwrap().take().unwrap()
208 {
209 Ok(()) =>
210 {
211 let data = slice.get_mapped_range();
212 let typed = bit::transmute_slice(&data);
213 vec[..typed.len()].copy_from_slice(typed);
214 drop(data);
215 staging.unmap();
216 Ok(())
217 }
218 Err(e) => Err(e.into()),
219 }
220 }
221
222 fn slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuSlice<'_, T> { todo!() }
223}
224
225impl<T> GpuBufferRead<T> for wgpu::Buffer
250{
251 fn read_in(&self, mut vec: &mut Vec<T>) -> GpuResult
252 where
253 T: BitZero + BitPattern,
254 {
255 self.slice(..).read_in(vec)
256 }
257
258 fn slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuSlice<'_, T>
259 {
260 let untyped_slice = GpuUntypedSlice {
261 buffer: self,
262 offset: 0,
263 size: self.size(),
264 };
265 let slice: GpuSlice<'_, T> = untyped_slice.slice(bounds);
266 unsafe { GpuSlice::from_raw_parts(self, slice.offset, slice.size) }
267 }
268}
269
270#[derive(Copy, Clone, Debug, PartialEq)]
271pub struct GpuSlice<'a, T>
272{
273 buffer: &'a wgpu::Buffer,
274 offset: GpuBufferAddress,
275 size: GpuBufferAddress,
276 phantom: PhantomData<T>,
277}
278impl<'a, T> From<GpuSlice<'a, T>> for GpuUntypedSlice<'a>
279{
280 fn from(value: GpuSlice<'a, T>) -> Self
281 {
282 let size = std::mem::size_of::<T>() as GpuBufferAddress;
283 unsafe {
284 GpuUntypedSlice::from_raw_parts(value.buffer, value.offset * size, value.size * size)
285 }
286 }
287}
288impl<'a, T> GpuSlice<'a, T>
289{
290 pub unsafe fn from_raw_parts(
291 buffer: &'a wgpu::Buffer,
292 offset: GpuBufferAddress,
293 size: GpuBufferAddress,
294 ) -> Self
295 {
296 Self {
297 buffer,
298 offset,
299 size,
300 phantom: PhantomData,
301 }
302 }
303
304 pub unsafe fn from_untyped_slice_unchecked(slice: GpuUntypedSlice<'a>) -> Self
305 {
306 let size = std::mem::size_of::<T>().max(1) as GpuBufferAddress;
307 unsafe { Self::from_raw_parts(slice.buffer, slice.offset / size, slice.size / size) }
308 }
309
310 fn update(&self, values: &[T]) -> Result<(), ()>
311 where
312 T: BitAllUsed,
313 {
314 let untyped: GpuUntypedSlice<'_> = (*self).into();
315
316 let elem_size = std::mem::size_of::<T>();
317 if (values.len() as GpuBufferAddress) > self.size
318 {
319 return Err(()); }
321 untyped.update(values)
322 }
323}
324impl<'a, T> GpuBufferAsWgpuSlice for GpuSlice<'a, T>
325{
326 fn as_wgpu_slice(&self) -> wgpu::BufferSlice<'a>
327 {
328 let size = std::mem::size_of::<T>() as GpuBufferAddress;
329 self.buffer
330 .slice((self.offset * size)..((self.offset + self.size) * size))
331 }
332}
333
334impl<'a, T> From<&'a wgpu::Buffer> for GpuSlice<'a, T>
336where
337 T: BitAnyPattern,
338{
339 fn from(buffer: &'a wgpu::Buffer) -> Self
340 {
341 assert_eq!(
342 buffer.bytes_len() % std::mem::size_of::<T>(),
343 0,
344 "wrong size"
345 );
346 unsafe { Self::from_untyped_slice_unchecked(GpuUntypedSlice::from(buffer)) }
347 }
348}
349
350#[derive(Copy, Clone, Debug, PartialEq)]
351pub struct GpuUntypedSlice<'a>
352{
353 buffer: &'a wgpu::Buffer,
354 offset: GpuBufferAddress,
355 size: GpuBufferAddress,
356}
357impl<'a> GpuUntypedSlice<'a>
358{
359 pub unsafe fn from_raw_parts(
360 buffer: &'a wgpu::Buffer,
361 offset: GpuBufferAddress,
362 size: GpuBufferAddress,
363 ) -> Self
364 {
365 Self {
366 buffer,
367 offset,
368 size,
369 }
370 }
371
372 fn update<T>(&self, values: &[T]) -> Result<(), ()>
373 where
374 T: BitAllUsed,
375 {
376 let value_bytes = values.len() * size_of::<T>();
377 if value_bytes as GpuBufferAddress > self.size
378 {
379 return Err(()); }
381
382 let staging = Gpu
383 .wgpu
384 .device
385 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
386 label: Some("update_bytes staging"),
387 contents: bit::try_transmute_slice(values).map_err(|_| ())?,
388 usage: wgpu::BufferUsages::COPY_SRC,
389 });
390
391 let mut encoder = Gpu
392 .wgpu
393 .device
394 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
395 label: Some("update_bytes encoder"),
396 });
397
398 encoder.copy_buffer_to_buffer(
399 &staging,
400 0,
401 self.buffer,
402 self.offset,
403 value_bytes as GpuBufferAddress,
404 );
405
406 Gpu.wgpu.queue.submit(Some(encoder.finish()));
407
408 Ok(())
409 }
410}
411impl<'a> GpuBufferAsWgpuSlice for GpuUntypedSlice<'a>
412{
413 fn as_wgpu_slice(&self) -> wgpu::BufferSlice<'a>
414 {
415 self.buffer.slice(self.offset..self.offset + self.size)
416 }
417}
418
419impl<'a> From<&'a wgpu::Buffer> for GpuUntypedSlice<'a>
420{
421 fn from(buffer: &'a wgpu::Buffer) -> Self
422 {
423 Self {
424 buffer,
425 offset: 0,
426 size: buffer.size(),
427 }
428 }
429}
430impl<'a> GpuBufferByte for GpuUntypedSlice<'a>
431{
432 fn wgpu_bytes_len(&self) -> GpuBufferAddress { self.size }
433}
434impl<'a> GpuAsUntypedSlice for GpuUntypedSlice<'a>
435{
436 fn untyped_slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuUntypedSlice<'_>
437 {
438 let start = match bounds.start_bound()
439 {
440 Bound::Included(&v) => v as GpuBufferAddress,
441 Bound::Excluded(&v) => (v + 1) as GpuBufferAddress,
442 Bound::Unbounded => 0,
443 };
444
445 let end = match bounds.end_bound()
446 {
447 Bound::Included(&v) => (v + 1) as GpuBufferAddress,
448 Bound::Excluded(&v) => v as GpuBufferAddress,
449 Bound::Unbounded => self.size,
450 };
451
452 assert!(
453 start <= end && end <= self.size,
454 "GpuUntypedSlice::untyped_slice out of bounds"
455 );
456
457 GpuUntypedSlice {
458 buffer: self.buffer,
459 offset: self.offset + start,
460 size: end - start,
461 }
462 }
463}
464impl<'a, T> GpuBufferRead<T> for GpuUntypedSlice<'a>
465{
466 fn read_in(&self, vec: &mut Vec<T>) -> GpuResult
467 where
468 T: BitZero + BitPattern,
469 {
470 let elem_size = std::mem::size_of::<T>().max(1);
471 let elem_count = (self.size / elem_size as GpuBufferAddress) as usize;
472 if vec.len() < elem_count
473 {
474 vec.resize(elem_count, T::zeroed());
475 }
476
477 let staging = create_staging_and_copy_slice(&self.as_wgpu_slice());
478
479 let slice = staging.slice(..);
480 let status = std::sync::Arc::new(std::sync::Mutex::new(None));
481 let status_clone = status.clone();
482
483 slice.map_async(wgpu::MapMode::Read, move |res| {
484 *status_clone.lock().unwrap() = Some(res);
485 });
486
487 while status.lock().unwrap().is_none()
488 {
489 Gpu.wgpu.device.poll(wgpu::PollType::Wait);
490 }
491
492 match status.lock().unwrap().take().unwrap()
493 {
494 Ok(()) =>
495 {
496 let data = slice.get_mapped_range();
497 let typed = bit::transmute_slice(&data);
498 vec[..typed.len()].copy_from_slice(typed);
499 drop(data);
500 staging.unmap();
501 Ok(())
502 }
503 Err(e) => Err(e.into()),
504 }
505 }
506
507 fn slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuSlice<'_, T>
508 {
509 let elem_size = std::mem::size_of::<T>().max(1) as GpuBufferAddress;
510 let bytes_len = self.size;
511
512 let start = match bounds.start_bound()
513 {
514 std::ops::Bound::Included(&v) => (v as GpuBufferAddress) * elem_size,
515 std::ops::Bound::Excluded(&v) => ((v + 1) as GpuBufferAddress) * elem_size,
516 std::ops::Bound::Unbounded => 0,
517 }
518 .min(bytes_len);
519
520 let end = match bounds.end_bound()
521 {
522 std::ops::Bound::Included(&v) => ((v + 1) as GpuBufferAddress) * elem_size,
523 std::ops::Bound::Excluded(&v) => (v as GpuBufferAddress) * elem_size,
524 std::ops::Bound::Unbounded => bytes_len,
525 }
526 .min(bytes_len);
527
528 let size = end - start;
529
530 assert!(
531 start <= end && size % elem_size == 0,
532 "GpuSlice<T>::slice: requested range not aligned with element size"
533 );
534
535 let untyped = GpuUntypedSlice {
536 buffer: self.buffer,
537 offset: self.offset + start,
538 size,
539 };
540
541 unsafe { GpuSlice::from_untyped_slice_unchecked(untyped) }
542 }
543}
544
545#[repr(transparent)]
546#[derive(Clone, Debug, PartialEq, Hash)]
547pub struct GpuUntypedBuffer
548{
549 pub(crate) wgpu: wgpu::Buffer,
550 private_constructor: (),
551}
552impl Handle for GpuUntypedBuffer {}
553
554impl<T> GpuBufferNew<T> for GpuUntypedBuffer
555where
556 T: BitAllUsed,
557{
558 fn new(value: &[T], desc: GpuBufferDesc) -> Self
559 {
560 Self {
561 wgpu: wgpu::Buffer::new(value, desc),
562 private_constructor: (),
563 }
564 }
565
566 fn with_capacity(capacity: usize, desc: GpuBufferDesc) -> Self
567 {
568 Self {
569 wgpu: <wgpu::Buffer as GpuBufferNew<T>>::with_capacity(capacity, desc),
570 private_constructor: (),
571 }
572 }
573}
574
575impl From<wgpu::Buffer> for GpuUntypedBuffer
576{
577 fn from(buffer: wgpu::Buffer) -> Self
578 {
579 Self {
580 wgpu: buffer,
581 private_constructor: (),
582 }
583 }
584}
585impl From<GpuUntypedBuffer> for wgpu::Buffer
586{
587 fn from(value: GpuUntypedBuffer) -> Self { value.wgpu }
588}
589impl GpuBufferByte for GpuUntypedBuffer
590{
591 fn wgpu_bytes_len(&self) -> GpuBufferAddress { self.wgpu.wgpu_bytes_len() }
592}
593impl GpuAsUntypedSlice for GpuUntypedBuffer
594{
595 fn untyped_slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuUntypedSlice<'_>
596 {
597 self.wgpu.untyped_slice(bounds)
598 }
599}
600impl<T> GpuBufferRead<T> for GpuUntypedBuffer
601where
602 wgpu::Buffer: GpuBufferRead<T>,
603{
604 fn read_in(&self, vec: &mut Vec<T>) -> GpuResult
605 where
606 T: BitZero + BitPattern,
607 {
608 self.wgpu.read_in(vec)
609 }
610 fn slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuSlice<'_, T>
611 {
612 GpuBufferRead::<T>::slice(&self.wgpu, bounds)
613 }
614}
615
616#[repr(transparent)]
617#[derive(Clone, Debug, PartialEq, Hash)]
618pub struct GpuBuffer<T>
619{
620 pub(crate) wgpu: wgpu::Buffer,
621 phantom: PhantomData<T>,
622}
623impl<T> Handle for GpuBuffer<T> where T: BitAllUsed {}
624
625impl<T> GpuBufferNew<T> for GpuBuffer<T>
626where
627 T: BitAllUsed,
628{
629 fn new(value: &[T], desc: GpuBufferDesc) -> Self
630 {
631 Self {
632 wgpu: wgpu::Buffer::new(value, desc),
633 phantom: PhantomData,
634 }
635 }
636
637 fn with_capacity(capacity: usize, desc: GpuBufferDesc) -> Self
638 {
639 Self {
640 wgpu: <wgpu::Buffer as GpuBufferNew<T>>::with_capacity(capacity, desc),
641 phantom: PhantomData,
642 }
643 }
644}
645
646impl<T> From<wgpu::Buffer> for GpuBuffer<T>
647where
648 T: BitAnyPattern,
649{
650 fn from(buffer: wgpu::Buffer) -> Self
651 {
652 assert_eq!(
653 buffer.bytes_len() % std::mem::size_of::<T>(),
654 0,
655 "wrong gpu buffer size"
656 );
657 Self {
658 wgpu: buffer,
659 phantom: PhantomData,
660 }
661 }
662}
663impl<T> From<GpuUntypedBuffer> for GpuBuffer<T>
664where
665 T: BitAnyPattern,
666{
667 fn from(buffer: GpuUntypedBuffer) -> Self { Self::from(buffer.wgpu) }
668}
669impl<T> From<GpuBuffer<T>> for wgpu::Buffer
670{
671 fn from(value: GpuBuffer<T>) -> Self { value.wgpu }
672}
673impl<T> From<GpuBuffer<T>> for GpuUntypedBuffer
674{
675 fn from(value: GpuBuffer<T>) -> Self { GpuUntypedBuffer::from(value.wgpu) }
676}
677
678impl<T> GpuBufferByte for GpuBuffer<T>
679{
680 fn wgpu_bytes_len(&self) -> GpuBufferAddress { self.wgpu.wgpu_bytes_len() }
681}
682impl<T> GpuAsUntypedSlice for GpuBuffer<T>
683{
684 fn untyped_slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuUntypedSlice<'_>
685 {
686 self.wgpu.untyped_slice(bounds)
687 }
688 fn try_untyped_update<T2>(&mut self, values: &[T2]) -> Result<(), ()>
689 where
690 T2: BitAllUsed,
691 {
692 if std::mem::size_of::<T>() != std::mem::size_of::<T2>()
693 {
694 return Err(());
695 }
696 self.untyped_slice(..).update(values)
697 }
698}
699impl<T> GpuBufferRead<T> for GpuBuffer<T>
700where
701 wgpu::Buffer: GpuBufferRead<T>,
702{
703 fn read_in(&self, vec: &mut Vec<T>) -> GpuResult
704 where
705 T: BitZero + BitPattern,
706 {
707 self.wgpu.read_in(vec)
708 }
709 fn slice<S: RangeBounds<usize>>(&self, bounds: S) -> GpuSlice<'_, T>
710 {
711 GpuBufferRead::<T>::slice(&self.wgpu, bounds)
712 }
713}
714
715#[bit_index]
723#[repr(u32)]
724pub enum BufferUsage
725{
726 MapReap = 0,
732 MapWrite = 1,
738 CopySrc = 2,
741 CopyDst = 3,
744 Index = 4,
746 Vertex = 5,
748 Uniform = 6,
750 Storage = 7,
752 Indirect = 8,
754 QueryResolve = 9,
756 BlasInput = 10,
758 TlasInput = 11,
760}
761impl BufferUsageFlags
762{
763 pub const fn from_wgpu(value: wgpu::BufferUsages) -> Self
764 {
765 unsafe { Self::from_bits_unchecked(value.bits()) }
766 }
767}
768impl From<wgpu::BufferUsages> for BufferUsageFlags
769{
770 #[inline(always)]
771 fn from(value: wgpu::BufferUsages) -> Self { Self::from_wgpu(value) }
772}
773impl From<BufferUsageFlags> for wgpu::BufferUsages
774{
775 fn from(value: BufferUsageFlags) -> Self { Self::from_bits(value.bits()).expect("") }
776}
777
778#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
779pub struct GpuBufferDesc
780{
781 pub usages: BufferUsageFlags,
782 pub name: Option<&'static str>,
783}
784impl Default for GpuBufferDesc
785{
786 fn default() -> Self { Self::new() }
787}
788impl GpuBufferDesc
789{
790 pub const fn new() -> Self
791 {
792 Self {
793 usages: BufferUsageFlags::CopyDst.union(BufferUsageFlags::CopySrc),
794 name: None,
795 }
796 }
797
798 pub const fn add_usage(mut self, usage: BufferUsageFlags) -> Self
799 {
800 self.usages = self.usages.union(usage);
801 self
802 }
803 pub const fn with_usages(mut self, usages: BufferUsageFlags) -> Self
804 {
805 self.usages = usages;
806 self
807 }
808 pub const fn with_label(mut self, label: Option<&'static str>) -> Self
809 {
810 self.name = label;
811 self
812 }
813
814 pub const VERTEX: Self = Self::new().add_usage(BufferUsageFlags::Vertex);
815 pub const INDEX: Self = Self::new().add_usage(BufferUsageFlags::Index);
816}
817
818pub trait ToGpuBuffer<T>
819where
820 T: BitAllUsed,
821{
822 fn to_gpu_buffer(self, desc: GpuBufferDesc) -> GpuBuffer<T>;
823}
824impl<T> ToGpuBuffer<T> for &[T]
825where
826 T: BitAllUsed,
827{
828 fn to_gpu_buffer(self, desc: GpuBufferDesc) -> GpuBuffer<T> { GpuBuffer::new(self, desc) }
829}