@@ -14,7 +14,7 @@ use crate::{
14
14
dxgi:: { name:: ObjectExt , result:: HResult as _} ,
15
15
} ,
16
16
dx12:: borrow_interface_temporarily,
17
- AccelerationStructureEntries ,
17
+ AccelerationStructureEntries , CommandEncoder as _ ,
18
18
} ;
19
19
20
20
fn make_box ( origin : & wgt:: Origin3d , size : & crate :: CopyExtent ) -> Direct3D12 :: D3D12_BOX {
@@ -312,6 +312,78 @@ impl super::CommandEncoder {
312
312
}
313
313
}
314
314
}
315
+
316
+ unsafe fn buf_tex_intermediate < T > (
317
+ & mut self ,
318
+ region : crate :: BufferTextureCopy ,
319
+ tex_fmt : wgt:: TextureFormat ,
320
+ copy_op : impl FnOnce ( & mut Self , & super :: Buffer , wgt:: BufferSize , crate :: BufferTextureCopy ) -> T ,
321
+ ) -> Option < ( T , super :: Buffer ) > {
322
+ let size = {
323
+ let copy_info = region. buffer_layout . get_buffer_texture_copy_info (
324
+ tex_fmt,
325
+ region. texture_base . aspect . map ( ) ,
326
+ & region. size . into ( ) ,
327
+ ) ;
328
+ copy_info. unwrap ( ) . bytes_in_copy
329
+ } ;
330
+
331
+ let size = wgt:: BufferSize :: new ( size) ?;
332
+
333
+ let buffer = {
334
+ let ( resource, allocation) =
335
+ super :: suballocation:: DeviceAllocationContext :: from ( & * self )
336
+ . create_buffer ( & crate :: BufferDescriptor {
337
+ label : None ,
338
+ size : size. get ( ) ,
339
+ usage : wgt:: BufferUses :: COPY_SRC | wgt:: BufferUses :: COPY_DST ,
340
+ memory_flags : crate :: MemoryFlags :: empty ( ) ,
341
+ } )
342
+ . expect ( concat ! (
343
+ "internal error: " ,
344
+ "failed to allocate intermediate buffer " ,
345
+ "for offset alignment"
346
+ ) ) ;
347
+ super :: Buffer {
348
+ resource,
349
+ size : size. get ( ) ,
350
+ allocation,
351
+ }
352
+ } ;
353
+
354
+ let mut region = region;
355
+ region. buffer_layout . offset = 0 ;
356
+
357
+ unsafe {
358
+ self . transition_buffers (
359
+ [ crate :: BufferBarrier {
360
+ buffer : & buffer,
361
+ usage : crate :: StateTransition {
362
+ from : wgt:: BufferUses :: empty ( ) ,
363
+ to : wgt:: BufferUses :: COPY_DST ,
364
+ } ,
365
+ } ]
366
+ . into_iter ( ) ,
367
+ )
368
+ } ;
369
+
370
+ let t = copy_op ( self , & buffer, size, region) ;
371
+
372
+ unsafe {
373
+ self . transition_buffers (
374
+ [ crate :: BufferBarrier {
375
+ buffer : & buffer,
376
+ usage : crate :: StateTransition {
377
+ from : wgt:: BufferUses :: COPY_DST ,
378
+ to : wgt:: BufferUses :: COPY_SRC ,
379
+ } ,
380
+ } ]
381
+ . into_iter ( ) ,
382
+ )
383
+ } ;
384
+
385
+ Some ( ( t, buffer) )
386
+ }
315
387
}
316
388
317
389
impl crate :: CommandEncoder for super :: CommandEncoder {
@@ -612,31 +684,61 @@ impl crate::CommandEncoder for super::CommandEncoder {
612
684
) where
613
685
T : Iterator < Item = crate :: BufferTextureCopy > ,
614
686
{
615
- for r in regions {
687
+ let offset_alignment = self . shared . private_caps . texture_data_placement_alignment ( ) ;
688
+
689
+ for naive_copy_region in regions {
690
+ let is_offset_aligned = naive_copy_region. buffer_layout . offset % offset_alignment == 0 ;
691
+ let ( final_copy_region, src) = if is_offset_aligned {
692
+ ( naive_copy_region, src)
693
+ } else {
694
+ let Some ( ( intermediate_to_dst_region, intermediate_buf) ) = ( unsafe {
695
+ let src_offset = naive_copy_region. buffer_layout . offset ;
696
+ self . buf_tex_intermediate (
697
+ naive_copy_region,
698
+ dst. format ,
699
+ |this, buf, size, intermediate_to_dst_region| {
700
+ let layout = crate :: BufferCopy {
701
+ src_offset,
702
+ dst_offset : 0 ,
703
+ size,
704
+ } ;
705
+ this. copy_buffer_to_buffer ( src, buf, [ layout] . into_iter ( ) ) ;
706
+ intermediate_to_dst_region
707
+ } ,
708
+ )
709
+ } ) else {
710
+ continue ;
711
+ } ;
712
+ self . intermediate_copy_bufs . push ( intermediate_buf) ;
713
+ let intermediate_buf = self . intermediate_copy_bufs . last ( ) . unwrap ( ) ;
714
+ ( intermediate_to_dst_region, intermediate_buf)
715
+ } ;
716
+
616
717
let list = self . list . as_ref ( ) . unwrap ( ) ;
617
718
618
719
let src_location = Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION {
619
720
pResource : unsafe { borrow_interface_temporarily ( & src. resource ) } ,
620
721
Type : Direct3D12 :: D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT ,
621
722
Anonymous : Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION_0 {
622
- PlacedFootprint : r . to_subresource_footprint ( dst. format ) ,
723
+ PlacedFootprint : final_copy_region . to_subresource_footprint ( dst. format ) ,
623
724
} ,
624
725
} ;
625
726
let dst_location = Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION {
626
727
pResource : unsafe { borrow_interface_temporarily ( & dst. resource ) } ,
627
728
Type : Direct3D12 :: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX ,
628
729
Anonymous : Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION_0 {
629
- SubresourceIndex : dst. calc_subresource_for_copy ( & r. texture_base ) ,
730
+ SubresourceIndex : dst
731
+ . calc_subresource_for_copy ( & final_copy_region. texture_base ) ,
630
732
} ,
631
733
} ;
632
734
633
- let src_box = make_box ( & wgt:: Origin3d :: ZERO , & r . size ) ;
735
+ let src_box = make_box ( & wgt:: Origin3d :: ZERO , & final_copy_region . size ) ;
634
736
unsafe {
635
737
list. CopyTextureRegion (
636
738
& dst_location,
637
- r . texture_base . origin . x ,
638
- r . texture_base . origin . y ,
639
- r . texture_base . origin . z ,
739
+ final_copy_region . texture_base . origin . x ,
740
+ final_copy_region . texture_base . origin . y ,
741
+ final_copy_region . texture_base . origin . z ,
640
742
& src_location,
641
743
Some ( & src_box) ,
642
744
)
@@ -680,8 +782,37 @@ impl crate::CommandEncoder for super::CommandEncoder {
680
782
} ;
681
783
} ;
682
784
785
+ let offset_alignment = self . shared . private_caps . texture_data_placement_alignment ( ) ;
786
+
683
787
for r in regions {
684
- copy_aligned ( this, src, dst, r) ;
788
+ let is_offset_aligned = r. buffer_layout . offset % offset_alignment == 0 ;
789
+ if is_offset_aligned {
790
+ copy_aligned ( self , src, dst, r)
791
+ } else {
792
+ let orig_offset = r. buffer_layout . offset ;
793
+ let Some ( ( intermediate_to_dst_region, src) ) = ( unsafe {
794
+ self . buf_tex_intermediate (
795
+ r,
796
+ src. format ,
797
+ |this, buf, size, intermediate_region| {
798
+ copy_aligned ( this, src, buf, intermediate_region) ;
799
+ crate :: BufferCopy {
800
+ src_offset : orig_offset,
801
+ dst_offset : 0 ,
802
+ size,
803
+ }
804
+ } ,
805
+ )
806
+ } ) else {
807
+ continue ;
808
+ } ;
809
+
810
+ unsafe {
811
+ self . copy_buffer_to_buffer ( & src, dst, [ intermediate_to_dst_region] . into_iter ( ) ) ;
812
+ }
813
+
814
+ self . intermediate_copy_bufs . push ( src) ;
815
+ } ;
685
816
}
686
817
}
687
818
0 commit comments