@@ -17,7 +17,7 @@ use crate::{
1717 TextureModes ,
1818 } ,
1919 bindgroup:: ManagedBindGroup ,
20- texture:: { CopiedTextureBuffer , Texture } ,
20+ texture:: { self , CopiedTextureBuffer , Texture } ,
2121} ;
2222
2323use super :: atlas_image:: { convert_pixels, AtlasImage } ;
@@ -41,6 +41,11 @@ pub enum AtlasError {
4141
4242 #[ snafu( display( "Missing bindgroup {layer}" ) ) ]
4343 MissingBindgroup { layer : u32 } ,
44+
45+ #[ snafu( display( "{source}" ) ) ]
46+ Texture {
47+ source : crate :: texture:: TextureError ,
48+ } ,
4449}
4550
4651/// A staged texture in the texture atlas.
@@ -200,6 +205,8 @@ pub struct Atlas {
200205 layers : Arc < RwLock < Vec < Layer > > > ,
201206 label : Option < String > ,
202207 descriptor : Hybrid < AtlasDescriptor > ,
208+ /// Used for user updates into the atlas by blit images into specific frames.
209+ blitter : AtlasBlitter ,
203210}
204211
205212impl Atlas {
@@ -286,13 +293,18 @@ impl Atlas {
286293 size : UVec3 :: new ( size. width , size. height , size. depth_or_array_layers ) ,
287294 } ) ;
288295 let label = label. map ( |s| s. to_owned ( ) ) ;
289-
296+ let blitter = AtlasBlitter :: new (
297+ slab. device ( ) ,
298+ texture. texture . format ( ) ,
299+ wgpu:: FilterMode :: Linear ,
300+ ) ;
290301 Atlas {
291302 slab : slab. clone ( ) ,
292303 layers : Arc :: new ( RwLock :: new ( layers) ) ,
293- texture_array : Arc :: new ( RwLock :: new ( texture) ) ,
294304 descriptor,
295305 label,
306+ blitter,
307+ texture_array : Arc :: new ( RwLock :: new ( texture) ) ,
296308 }
297309 }
298310
@@ -523,6 +535,107 @@ impl Atlas {
523535 }
524536 images
525537 }
538+
539+ /// Update the given [`AtlasTexture`] with a [`Texture`](crate::texture::Texture).
540+ ///
541+ /// This will blit the `Texture` into the frame of the [`Atlas`] pointed to by the
542+ /// `AtlasTexture`.
543+ ///
544+ /// Returns a submission index that can be polled with [`wgpu::Device::poll`].
545+ pub fn update_texture (
546+ & self ,
547+ atlas_texture : & AtlasTexture ,
548+ source_texture : & texture:: Texture ,
549+ ) -> Result < wgpu:: SubmissionIndex , AtlasError > {
550+ self . update_textures ( Some ( ( atlas_texture, source_texture) ) )
551+ }
552+
553+ /// Update the given [`AtlasTexture`]s with [`Texture`](crate::texture::Texture)s.
554+ ///
555+ /// This will blit the `Texture` into the frame of the [`Atlas`] pointed to by the
556+ /// `AtlasTexture`.
557+ ///
558+ /// Returns a submission index that can be polled with [`wgpu::Device::poll`].
559+ pub fn update_textures < ' a > (
560+ & self ,
561+ updates : impl IntoIterator < Item = ( & ' a AtlasTexture , & ' a texture:: Texture ) > ,
562+ ) -> Result < wgpu:: SubmissionIndex , AtlasError > {
563+ let updates = updates. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
564+ let op = AtlasBlittingOperation :: new ( & self . blitter , & self , updates. len ( ) ) ;
565+ let runtime = self . slab . runtime ( ) ;
566+ let mut encoder = runtime
567+ . device
568+ . create_command_encoder ( & wgpu:: CommandEncoderDescriptor {
569+ label : Some ( "Atlas::update_texture" ) ,
570+ } ) ;
571+ for ( i, ( atlas_texture, source_texture) ) in updates. into_iter ( ) . enumerate ( ) {
572+ op. run (
573+ & runtime,
574+ & mut encoder,
575+ source_texture,
576+ i as u32 ,
577+ & self ,
578+ atlas_texture,
579+ ) ?;
580+ }
581+ Ok ( runtime. queue . submit ( Some ( encoder. finish ( ) ) ) )
582+ }
583+
584+ /// Update the given [`AtlasTexture`]s with new data.
585+ ///
586+ /// This will blit the image data into the frame of the [`Atlas`] pointed to by the
587+ /// `AtlasTexture`.
588+ ///
589+ /// Returns a submission index that can be polled with [`wgpu::Device::poll`].
590+ pub fn update_images < ' a > (
591+ & self ,
592+ updates : impl IntoIterator < Item = ( & ' a AtlasTexture , impl Into < AtlasImage > ) > ,
593+ ) -> Result < wgpu:: SubmissionIndex , AtlasError > {
594+ let ( atlas_textures, images) : ( Vec < _ > , Vec < _ > ) = updates. into_iter ( ) . unzip ( ) ;
595+ let mut textures = vec ! [ ] ;
596+ for image in images. into_iter ( ) {
597+ let image: AtlasImage = image. into ( ) ;
598+ let atlas_format = self . get_texture ( ) . texture . format ( ) ;
599+ let bytes = super :: atlas_image:: convert_pixels (
600+ image. pixels ,
601+ image. format ,
602+ atlas_format,
603+ image. apply_linear_transfer ,
604+ ) ;
605+ let ( channels, subpixel_bytes) =
606+ texture:: wgpu_texture_format_channels_and_subpixel_bytes ( atlas_format)
607+ . context ( TextureSnafu ) ?;
608+ let texture = texture:: Texture :: new_with (
609+ self . slab . runtime ( ) ,
610+ Some ( "atlas-image-update" ) ,
611+ Some ( wgpu:: TextureUsages :: TEXTURE_BINDING | wgpu:: TextureUsages :: COPY_DST ) ,
612+ None ,
613+ atlas_format,
614+ channels,
615+ subpixel_bytes,
616+ image. size . x ,
617+ image. size . y ,
618+ 1 ,
619+ & bytes,
620+ ) ;
621+ textures. push ( texture) ;
622+ }
623+ self . update_textures ( atlas_textures. into_iter ( ) . zip ( textures. iter ( ) ) )
624+ }
625+
626+ /// Update the given [`AtlasTexture`]s with new data.
627+ ///
628+ /// This will blit the image data into the frame of the [`Atlas`] pointed to by the
629+ /// `AtlasTexture`.
630+ ///
631+ /// Returns a submission index that can be polled with [`wgpu::Device::poll`].
632+ pub fn update_image (
633+ & self ,
634+ atlas_texture : & AtlasTexture ,
635+ source_image : impl Into < AtlasImage > ,
636+ ) -> Result < wgpu:: SubmissionIndex , AtlasError > {
637+ self . update_images ( Some ( ( atlas_texture, source_image) ) )
638+ }
526639}
527640
528641fn pack_images < ' a > (
@@ -750,6 +863,30 @@ pub struct AtlasBlittingOperation {
750863}
751864
752865impl AtlasBlittingOperation {
866+ pub fn new (
867+ blitter : & AtlasBlitter ,
868+ into_atlas : & Atlas ,
869+ source_layers : usize ,
870+ ) -> AtlasBlittingOperation {
871+ AtlasBlittingOperation {
872+ desc : into_atlas
873+ . slab
874+ . new_value ( AtlasBlittingDescriptor :: default ( ) ) ,
875+ atlas_slab_buffer : Arc :: new ( Mutex :: new ( into_atlas. slab . commit ( ) ) ) ,
876+ bindgroups : {
877+ let mut bgs = vec ! [ ] ;
878+ for _ in 0 ..source_layers {
879+ bgs. push ( ManagedBindGroup :: default ( ) ) ;
880+ }
881+ Arc :: new ( bgs)
882+ } ,
883+ pipeline : blitter. pipeline . clone ( ) ,
884+ sampler : blitter. sampler . clone ( ) ,
885+ bindgroup_layout : blitter. bind_group_layout . clone ( ) ,
886+ from_texture_id : Default :: default ( ) ,
887+ }
888+ }
889+
753890 /// Copies the data from texture this [`AtlasBlittingOperation`] was created with
754891 /// into the atlas.
755892 ///
@@ -760,7 +897,7 @@ impl AtlasBlittingOperation {
760897 runtime : impl AsRef < WgpuRuntime > ,
761898 encoder : & mut wgpu:: CommandEncoder ,
762899 from_texture : & crate :: texture:: Texture ,
763- layer : u32 ,
900+ from_layer : u32 ,
764901 to_atlas : & Atlas ,
765902 atlas_texture : & AtlasTexture ,
766903 ) -> Result < ( ) , AtlasError > {
@@ -788,15 +925,15 @@ impl AtlasBlittingOperation {
788925 . texture
789926 . create_view ( & wgpu:: TextureViewDescriptor {
790927 label : Some ( "atlas-blitting" ) ,
791- base_array_layer : layer ,
928+ base_array_layer : from_layer ,
792929 array_layer_count : Some ( 1 ) ,
793930 dimension : Some ( wgpu:: TextureViewDimension :: D2 ) ,
794931 ..Default :: default ( )
795932 } ) ;
796933 let bindgroup = self
797934 . bindgroups
798- . get ( layer as usize )
799- . context ( MissingBindgroupSnafu { layer } ) ?
935+ . get ( from_layer as usize )
936+ . context ( MissingBindgroupSnafu { layer : from_layer } ) ?
800937 . get ( should_invalidate, || {
801938 runtime
802939 . device
@@ -874,19 +1011,20 @@ impl AtlasBlitter {
8741011 ///
8751012 /// # Arguments
8761013 /// - `device` - A [`wgpu::Device`]
877- /// - `format` - The [`wgpu::TextureFormat`] of the texture that will be copied to. This has to be renderable.
878- /// - `sample_type` - The [`wgpu::Sampler`] Filtering Mode
1014+ /// - `format` - The [`wgpu::TextureFormat`] of the atlas being updated.
1015+ /// - `mag_filter` - The filtering algorithm to use when magnifying.
1016+ /// This is used when the input source is smaller than the destination.
8791017 pub fn new (
8801018 device : & wgpu:: Device ,
8811019 format : wgpu:: TextureFormat ,
882- sample_type : wgpu:: FilterMode ,
1020+ mag_filter : wgpu:: FilterMode ,
8831021 ) -> Self {
8841022 let sampler = device. create_sampler ( & wgpu:: SamplerDescriptor {
8851023 label : Some ( "atlas-blitter" ) ,
8861024 address_mode_u : wgpu:: AddressMode :: ClampToEdge ,
8871025 address_mode_v : wgpu:: AddressMode :: ClampToEdge ,
8881026 address_mode_w : wgpu:: AddressMode :: ClampToEdge ,
889- mag_filter : sample_type ,
1027+ mag_filter,
8901028 ..Default :: default ( )
8911029 } ) ;
8921030
@@ -908,7 +1046,7 @@ impl AtlasBlitter {
9081046 visibility : wgpu:: ShaderStages :: FRAGMENT ,
9091047 ty : wgpu:: BindingType :: Texture {
9101048 sample_type : wgpu:: TextureSampleType :: Float {
911- filterable : sample_type == wgpu:: FilterMode :: Linear ,
1049+ filterable : mag_filter == wgpu:: FilterMode :: Linear ,
9121050 } ,
9131051 view_dimension : wgpu:: TextureViewDimension :: D2 ,
9141052 multisampled : false ,
@@ -918,7 +1056,7 @@ impl AtlasBlitter {
9181056 wgpu:: BindGroupLayoutEntry {
9191057 binding : 2 ,
9201058 visibility : wgpu:: ShaderStages :: FRAGMENT ,
921- ty : wgpu:: BindingType :: Sampler ( if sample_type == wgpu:: FilterMode :: Linear {
1059+ ty : wgpu:: BindingType :: Sampler ( if mag_filter == wgpu:: FilterMode :: Linear {
9221060 wgpu:: SamplerBindingType :: Filtering
9231061 } else {
9241062 wgpu:: SamplerBindingType :: NonFiltering
@@ -976,30 +1114,6 @@ impl AtlasBlitter {
9761114 sampler : sampler. into ( ) ,
9771115 }
9781116 }
979-
980- pub fn new_blitting_operation (
981- & self ,
982- into_atlas : & Atlas ,
983- layers : usize ,
984- ) -> AtlasBlittingOperation {
985- AtlasBlittingOperation {
986- desc : into_atlas
987- . slab
988- . new_value ( AtlasBlittingDescriptor :: default ( ) ) ,
989- atlas_slab_buffer : Arc :: new ( Mutex :: new ( into_atlas. slab . commit ( ) ) ) ,
990- bindgroups : {
991- let mut bgs = vec ! [ ] ;
992- for _ in 0 ..layers {
993- bgs. push ( ManagedBindGroup :: default ( ) ) ;
994- }
995- Arc :: new ( bgs)
996- } ,
997- pipeline : self . pipeline . clone ( ) ,
998- sampler : self . sampler . clone ( ) ,
999- bindgroup_layout : self . bind_group_layout . clone ( ) ,
1000- from_texture_id : Default :: default ( ) ,
1001- }
1002- }
10031117}
10041118
10051119#[ cfg( test) ]
0 commit comments