@@ -14,7 +14,7 @@ use crate::{
1414 dxgi:: { name:: ObjectExt , result:: HResult as _} ,
1515 } ,
1616 dx12:: borrow_interface_temporarily,
17- AccelerationStructureEntries ,
17+ AccelerationStructureEntries , CommandEncoder as _ ,
1818} ;
1919
2020fn make_box ( origin : & wgt:: Origin3d , size : & crate :: CopyExtent ) -> Direct3D12 :: D3D12_BOX {
@@ -312,6 +312,78 @@ impl super::CommandEncoder {
312312 }
313313 }
314314 }
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+ ) -> ( 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) . unwrap ( ) ;
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+ ( t, buffer)
386+ }
315387}
316388
317389impl crate :: CommandEncoder for super :: CommandEncoder {
@@ -366,6 +438,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
366438 Ok ( super :: CommandBuffer { raw } )
367439 }
368440 unsafe fn reset_all < I : Iterator < Item = super :: CommandBuffer > > ( & mut self , command_buffers : I ) {
441+ self . intermediate_copy_bufs . clear ( ) ;
369442 for cmd_buf in command_buffers {
370443 self . free_lists . push ( cmd_buf. raw ) ;
371444 }
@@ -612,31 +685,59 @@ impl crate::CommandEncoder for super::CommandEncoder {
612685 ) where
613686 T : Iterator < Item = crate :: BufferTextureCopy > ,
614687 {
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 ( 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+ } ;
711+ self . intermediate_copy_bufs . push ( intermediate_buf) ;
712+ let intermediate_buf = self . intermediate_copy_bufs . last ( ) . unwrap ( ) ;
713+ ( intermediate_to_dst_region, intermediate_buf)
714+ } ;
715+
616716 let list = self . list . as_ref ( ) . unwrap ( ) ;
617717
618718 let src_location = Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION {
619719 pResource : unsafe { borrow_interface_temporarily ( & src. resource ) } ,
620720 Type : Direct3D12 :: D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT ,
621721 Anonymous : Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION_0 {
622- PlacedFootprint : r . to_subresource_footprint ( dst. format ) ,
722+ PlacedFootprint : final_copy_region . to_subresource_footprint ( dst. format ) ,
623723 } ,
624724 } ;
625725 let dst_location = Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION {
626726 pResource : unsafe { borrow_interface_temporarily ( & dst. resource ) } ,
627727 Type : Direct3D12 :: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX ,
628728 Anonymous : Direct3D12 :: D3D12_TEXTURE_COPY_LOCATION_0 {
629- SubresourceIndex : dst. calc_subresource_for_copy ( & r. texture_base ) ,
729+ SubresourceIndex : dst
730+ . calc_subresource_for_copy ( & final_copy_region. texture_base ) ,
630731 } ,
631732 } ;
632733
633- let src_box = make_box ( & wgt:: Origin3d :: ZERO , & r . size ) ;
734+ let src_box = make_box ( & wgt:: Origin3d :: ZERO , & final_copy_region . size ) ;
634735 unsafe {
635736 list. CopyTextureRegion (
636737 & dst_location,
637- r . texture_base . origin . x ,
638- r . texture_base . origin . y ,
639- r . texture_base . origin . z ,
738+ final_copy_region . texture_base . origin . x ,
739+ final_copy_region . texture_base . origin . y ,
740+ final_copy_region . texture_base . origin . z ,
640741 & src_location,
641742 Some ( & src_box) ,
642743 )
@@ -680,8 +781,35 @@ impl crate::CommandEncoder for super::CommandEncoder {
680781 } ;
681782 } ;
682783
784+ let offset_alignment = self . shared . private_caps . texture_data_placement_alignment ( ) ;
785+
683786 for r in regions {
684- copy_aligned ( this, src, dst, r) ;
787+ let is_offset_aligned = r. buffer_layout . offset % offset_alignment == 0 ;
788+ if is_offset_aligned {
789+ copy_aligned ( self , src, dst, r)
790+ } else {
791+ let orig_offset = r. buffer_layout . offset ;
792+ let ( intermediate_to_dst_region, src) = unsafe {
793+ self . buf_tex_intermediate (
794+ r,
795+ src. format ,
796+ |this, buf, size, intermediate_region| {
797+ copy_aligned ( this, src, buf, intermediate_region) ;
798+ crate :: BufferCopy {
799+ src_offset : 0 ,
800+ dst_offset : orig_offset,
801+ size,
802+ }
803+ } ,
804+ )
805+ } ;
806+
807+ unsafe {
808+ self . copy_buffer_to_buffer ( & src, dst, [ intermediate_to_dst_region] . into_iter ( ) ) ;
809+ }
810+
811+ self . intermediate_copy_bufs . push ( src) ;
812+ } ;
685813 }
686814 }
687815
0 commit comments