@@ -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 {
@@ -366,6 +438,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
366
438
Ok ( super :: CommandBuffer { raw } )
367
439
}
368
440
unsafe fn reset_all < I : Iterator < Item = super :: CommandBuffer > > ( & mut self , command_buffers : I ) {
441
+ self . intermediate_copy_bufs . clear ( ) ;
369
442
for cmd_buf in command_buffers {
370
443
self . free_lists . push ( cmd_buf. raw ) ;
371
444
}
@@ -612,31 +685,61 @@ impl crate::CommandEncoder for super::CommandEncoder {
612
685
) where
613
686
T : Iterator < Item = crate :: BufferTextureCopy > ,
614
687
{
615
- for r in regions {
688
+ let offset_alignment = self . shared . private_caps . texture_data_placement_alignment ( ) ;
689
+
690
+ for naive_copy_region in regions {
691
+ let is_offset_aligned = naive_copy_region. buffer_layout . offset % offset_alignment == 0 ;
692
+ let ( final_copy_region, src) = if is_offset_aligned {
693
+ ( naive_copy_region, src)
694
+ } else {
695
+ let Some ( ( intermediate_to_dst_region, intermediate_buf) ) = ( unsafe {
696
+ let src_offset = naive_copy_region. buffer_layout . offset ;
697
+ self . buf_tex_intermediate (
698
+ naive_copy_region,
699
+ dst. format ,
700
+ |this, buf, size, intermediate_to_dst_region| {
701
+ let layout = crate :: BufferCopy {
702
+ src_offset,
703
+ dst_offset : 0 ,
704
+ size,
705
+ } ;
706
+ this. copy_buffer_to_buffer ( src, buf, [ layout] . into_iter ( ) ) ;
707
+ intermediate_to_dst_region
708
+ } ,
709
+ )
710
+ } ) else {
711
+ continue ;
712
+ } ;
713
+ self . intermediate_copy_bufs . push ( intermediate_buf) ;
714
+ let intermediate_buf = self . intermediate_copy_bufs . last ( ) . unwrap ( ) ;
715
+ ( intermediate_to_dst_region, intermediate_buf)
716
+ } ;
717
+
616
718
let list = self . list . as_ref ( ) . unwrap ( ) ;
617
719
618
720
let src_location = Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION {
619
721
pResource : unsafe { borrow_interface_temporarily ( & src. resource ) } ,
620
722
Type : Direct3D12 :: D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT ,
621
723
Anonymous : Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION_0 {
622
- PlacedFootprint : r . to_subresource_footprint ( dst. format ) ,
724
+ PlacedFootprint : final_copy_region . to_subresource_footprint ( dst. format ) ,
623
725
} ,
624
726
} ;
625
727
let dst_location = Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION {
626
728
pResource : unsafe { borrow_interface_temporarily ( & dst. resource ) } ,
627
729
Type : Direct3D12 :: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX ,
628
730
Anonymous : Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION_0 {
629
- SubresourceIndex : dst. calc_subresource_for_copy ( & r. texture_base ) ,
731
+ SubresourceIndex : dst
732
+ . calc_subresource_for_copy ( & final_copy_region. texture_base ) ,
630
733
} ,
631
734
} ;
632
735
633
- let src_box = make_box ( & wgt:: Origin3d :: ZERO , & r . size ) ;
736
+ let src_box = make_box ( & wgt:: Origin3d :: ZERO , & final_copy_region . size ) ;
634
737
unsafe {
635
738
list. CopyTextureRegion (
636
739
& dst_location,
637
- r . texture_base . origin . x ,
638
- r . texture_base . origin . y ,
639
- r . texture_base . origin . z ,
740
+ final_copy_region . texture_base . origin . x ,
741
+ final_copy_region . texture_base . origin . y ,
742
+ final_copy_region . texture_base . origin . z ,
640
743
& src_location,
641
744
Some ( & src_box) ,
642
745
)
@@ -680,8 +783,37 @@ impl crate::CommandEncoder for super::CommandEncoder {
680
783
} ;
681
784
} ;
682
785
786
+ let offset_alignment = self . shared . private_caps . texture_data_placement_alignment ( ) ;
787
+
683
788
for r in regions {
684
- copy_aligned ( this, src, dst, r) ;
789
+ let is_offset_aligned = r. buffer_layout . offset % offset_alignment == 0 ;
790
+ if is_offset_aligned {
791
+ copy_aligned ( self , src, dst, r)
792
+ } else {
793
+ let orig_offset = r. buffer_layout . offset ;
794
+ let Some ( ( intermediate_to_dst_region, src) ) = ( unsafe {
795
+ self . buf_tex_intermediate (
796
+ r,
797
+ src. format ,
798
+ |this, buf, size, intermediate_region| {
799
+ copy_aligned ( this, src, buf, intermediate_region) ;
800
+ crate :: BufferCopy {
801
+ src_offset : orig_offset,
802
+ dst_offset : 0 ,
803
+ size,
804
+ }
805
+ } ,
806
+ )
807
+ } ) else {
808
+ continue ;
809
+ } ;
810
+
811
+ unsafe {
812
+ self . copy_buffer_to_buffer ( & src, dst, [ intermediate_to_dst_region] . into_iter ( ) ) ;
813
+ }
814
+
815
+ self . intermediate_copy_bufs . push ( src) ;
816
+ } ;
685
817
}
686
818
}
687
819
0 commit comments