11use crate :: {
22 render_asset:: { AssetExtractionError , PrepareAssetError , RenderAsset , RenderAssetPlugin } ,
33 render_resource:: { Buffer , BufferUsages } ,
4- renderer:: RenderDevice ,
4+ renderer:: { RenderDevice , RenderQueue } ,
55} ;
66use bevy_app:: { App , Plugin } ;
77use bevy_asset:: { Asset , AssetApp , AssetId , RenderAssetUsages } ;
@@ -34,6 +34,8 @@ pub struct ShaderBuffer {
3434 pub buffer_description : wgpu:: BufferDescriptor < ' static > ,
3535 /// The asset usage of the storage buffer.
3636 pub asset_usage : RenderAssetUsages ,
37+ /// Whether this buffer should be copied on the GPU when resized.
38+ pub copy_on_resize : bool ,
3739}
3840
3941impl Default for ShaderBuffer {
@@ -43,10 +45,11 @@ impl Default for ShaderBuffer {
4345 buffer_description : wgpu:: BufferDescriptor {
4446 label : None ,
4547 size : 0 ,
46- usage : BufferUsages :: STORAGE ,
48+ usage : BufferUsages :: STORAGE | BufferUsages :: COPY_SRC | BufferUsages :: COPY_DST ,
4749 mapped_at_creation : false ,
4850 } ,
4951 asset_usage : RenderAssetUsages :: default ( ) ,
52+ copy_on_resize : false ,
5053 }
5154 }
5255}
@@ -84,6 +87,30 @@ impl ShaderBuffer {
8487 wrapper. write ( & value) . unwrap ( ) ;
8588 self . data = Some ( wrapper. into_inner ( ) ) ;
8689 }
90+
91+ /// Resizes the buffer to the new size.
92+ ///
93+ /// If CPU data is present, it will be truncated or zero-extended.
94+ /// Does not preserve GPU data when the descriptor changes.
95+ pub fn resize ( & mut self , size : u64 ) {
96+ self . buffer_description . size = size;
97+ if let Some ( ref mut data) = self . data {
98+ data. resize ( size as usize , 0 ) ;
99+ }
100+ }
101+
102+ /// Resizes the buffer to the new size, preserving existing data.
103+ ///
104+ /// If CPU data is present, it will be truncated or zero-extended.
105+ /// If no CPU data is present, sets `copy_on_resize` to preserve GPU data.
106+ pub fn resize_in_place ( & mut self , size : u64 ) {
107+ self . buffer_description . size = size;
108+ if let Some ( ref mut data) = self . data {
109+ data. resize ( size as usize , 0 ) ;
110+ } else {
111+ self . copy_on_resize = true ;
112+ }
113+ }
87114}
88115
89116impl < T > From < T > for ShaderBuffer
@@ -101,12 +128,13 @@ where
101128/// A storage buffer that is prepared as a [`RenderAsset`] and uploaded to the GPU.
102129pub struct GpuShaderBuffer {
103130 pub buffer : Buffer ,
131+ pub buffer_descriptor : wgpu:: BufferDescriptor < ' static > ,
104132 pub had_data : bool ,
105133}
106134
107135impl RenderAsset for GpuShaderBuffer {
108136 type SourceAsset = ShaderBuffer ;
109- type Param = SRes < RenderDevice > ;
137+ type Param = ( SRes < RenderDevice > , SRes < RenderQueue > ) ;
110138
111139 fn asset_usage ( source_asset : & Self :: SourceAsset ) -> RenderAssetUsages {
112140 source_asset. asset_usage
@@ -131,28 +159,59 @@ impl RenderAsset for GpuShaderBuffer {
131159 fn prepare_asset (
132160 source_asset : Self :: SourceAsset ,
133161 _: AssetId < Self :: SourceAsset > ,
134- render_device : & mut SystemParamItem < Self :: Param > ,
135- _ : Option < & Self > ,
162+ ( render_device, render_queue ) : & mut SystemParamItem < Self :: Param > ,
163+ previous_asset : Option < & Self > ,
136164 ) -> Result < Self , PrepareAssetError < Self :: SourceAsset > > {
137- match source_asset. data {
138- Some ( data ) => {
139- let buffer = render_device . create_buffer_with_data ( & BufferInitDescriptor {
140- label : source_asset. buffer_description . label ,
141- contents : & data ,
142- usage : source_asset . buffer_description . usage ,
143- } ) ;
144- Ok ( GpuShaderBuffer {
145- buffer ,
146- had_data : true ,
147- } )
165+ let had_data = source_asset. data . is_some ( ) ;
166+
167+ let buffer = if let Some ( prev ) = previous_asset
168+ && prev . buffer_descriptor == source_asset. buffer_description
169+ && source_asset
170+ . buffer_description
171+ . usage
172+ . contains ( BufferUsages :: COPY_DST )
173+ {
174+ if let Some ( ref data ) = source_asset . data {
175+ render_queue . write_buffer ( & prev . buffer , 0 , data ) ;
148176 }
149- None => {
150- let buffer = render_device. create_buffer ( & source_asset. buffer_description ) ;
151- Ok ( GpuShaderBuffer {
152- buffer,
153- had_data : false ,
154- } )
177+ prev. buffer . clone ( )
178+ } else if let Some ( ref data) = source_asset. data {
179+ render_device. create_buffer_with_data ( & BufferInitDescriptor {
180+ label : source_asset. buffer_description . label ,
181+ contents : data,
182+ usage : source_asset. buffer_description . usage ,
183+ } )
184+ } else {
185+ let new_buffer = render_device. create_buffer ( & source_asset. buffer_description ) ;
186+ if source_asset. copy_on_resize
187+ && let Some ( previous) = previous_asset
188+ && previous
189+ . buffer_descriptor
190+ . usage
191+ . contains ( BufferUsages :: COPY_SRC )
192+ && source_asset
193+ . buffer_description
194+ . usage
195+ . contains ( BufferUsages :: COPY_DST )
196+ {
197+ let copy_size = source_asset
198+ . buffer_description
199+ . size
200+ . min ( previous. buffer_descriptor . size ) ;
201+ let mut encoder =
202+ render_device. create_command_encoder ( & wgpu:: CommandEncoderDescriptor {
203+ label : Some ( "copy_buffer_on_resize" ) ,
204+ } ) ;
205+ encoder. copy_buffer_to_buffer ( & previous. buffer , 0 , & new_buffer, 0 , copy_size) ;
206+ render_queue. submit ( [ encoder. finish ( ) ] ) ;
155207 }
156- }
208+ new_buffer
209+ } ;
210+
211+ Ok ( GpuShaderBuffer {
212+ buffer,
213+ buffer_descriptor : source_asset. buffer_description ,
214+ had_data,
215+ } )
157216 }
158217}
0 commit comments