RenderAssetPlugin
This commit is contained in:
		
							parent
							
								
									09043b66ce
								
							
						
					
					
						commit
						3ef951dcbc
					
				| @ -2,6 +2,7 @@ pub mod camera; | |||||||
| pub mod color; | pub mod color; | ||||||
| pub mod core_pipeline; | pub mod core_pipeline; | ||||||
| pub mod mesh; | pub mod mesh; | ||||||
|  | pub mod render_asset; | ||||||
| pub mod render_graph; | pub mod render_graph; | ||||||
| pub mod render_phase; | pub mod render_phase; | ||||||
| pub mod render_resource; | pub mod render_resource; | ||||||
| @ -22,7 +23,7 @@ use crate::{ | |||||||
|     texture::ImagePlugin, |     texture::ImagePlugin, | ||||||
|     view::{ViewPlugin, WindowRenderPlugin}, |     view::{ViewPlugin, WindowRenderPlugin}, | ||||||
| }; | }; | ||||||
| use bevy_app::{App, Plugin, StartupStage}; | use bevy_app::{App, Plugin}; | ||||||
| use bevy_ecs::prelude::*; | use bevy_ecs::prelude::*; | ||||||
| 
 | 
 | ||||||
| #[derive(Default)] | #[derive(Default)] | ||||||
|  | |||||||
							
								
								
									
										104
									
								
								pipelined/bevy_render2/src/render_asset.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								pipelined/bevy_render2/src/render_asset.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | use std::marker::PhantomData; | ||||||
|  | 
 | ||||||
|  | use crate::{ | ||||||
|  |     renderer::{RenderDevice, RenderQueue}, | ||||||
|  |     RenderStage, | ||||||
|  | }; | ||||||
|  | use bevy_app::{App, Plugin}; | ||||||
|  | use bevy_asset::{Asset, AssetEvent, Assets, Handle}; | ||||||
|  | use bevy_ecs::prelude::*; | ||||||
|  | use bevy_utils::{HashMap, HashSet}; | ||||||
|  | 
 | ||||||
|  | pub trait RenderAsset: Asset { | ||||||
|  |     type ExtractedAsset: Send + Sync + 'static; | ||||||
|  |     type PreparedAsset: Send + Sync + 'static; | ||||||
|  |     fn extract_asset(&self) -> Self::ExtractedAsset; | ||||||
|  |     fn prepare_asset( | ||||||
|  |         extracted_asset: Self::ExtractedAsset, | ||||||
|  |         render_device: &RenderDevice, | ||||||
|  |         render_queue: &RenderQueue, | ||||||
|  |     ) -> Self::PreparedAsset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Extracts assets into gpu-usable data
 | ||||||
|  | #[derive(Default)] | ||||||
|  | pub struct RenderAssetPlugin<A: RenderAsset>(PhantomData<fn() -> A>); | ||||||
|  | 
 | ||||||
|  | impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> { | ||||||
|  |     fn build(&self, app: &mut App) { | ||||||
|  |         let render_app = app.sub_app_mut(0); | ||||||
|  |         render_app | ||||||
|  |             .init_resource::<ExtractedAssets<A>>() | ||||||
|  |             .init_resource::<RenderAssets<A>>() | ||||||
|  |             .add_system_to_stage(RenderStage::Extract, extract_render_asset::<A>.system()) | ||||||
|  |             .add_system_to_stage(RenderStage::Prepare, prepare_render_asset::<A>.system()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct ExtractedAssets<A: RenderAsset> { | ||||||
|  |     extracted: Vec<(Handle<A>, A::ExtractedAsset)>, | ||||||
|  |     removed: Vec<Handle<A>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<A: RenderAsset> Default for ExtractedAssets<A> { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             extracted: Default::default(), | ||||||
|  |             removed: Default::default(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub type RenderAssets<A: RenderAsset> = HashMap<Handle<A>, A::PreparedAsset>; | ||||||
|  | 
 | ||||||
|  | fn extract_render_asset<A: RenderAsset>( | ||||||
|  |     mut commands: Commands, | ||||||
|  |     mut events: EventReader<AssetEvent<A>>, | ||||||
|  |     assets: Res<Assets<A>>, | ||||||
|  | ) { | ||||||
|  |     let mut changed_assets = HashSet::default(); | ||||||
|  |     let mut removed = Vec::new(); | ||||||
|  |     for event in events.iter() { | ||||||
|  |         match event { | ||||||
|  |             AssetEvent::Created { handle } => { | ||||||
|  |                 changed_assets.insert(handle); | ||||||
|  |             } | ||||||
|  |             AssetEvent::Modified { handle } => { | ||||||
|  |                 changed_assets.insert(handle); | ||||||
|  |             } | ||||||
|  |             AssetEvent::Removed { handle } => { | ||||||
|  |                 if !changed_assets.remove(handle) { | ||||||
|  |                     removed.push(handle.clone_weak()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut extracted_assets = Vec::new(); | ||||||
|  |     for handle in changed_assets.drain() { | ||||||
|  |         if let Some(asset) = assets.get(handle) { | ||||||
|  |             extracted_assets.push((handle.clone_weak(), asset.extract_asset())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     commands.insert_resource(ExtractedAssets { | ||||||
|  |         extracted: extracted_assets, | ||||||
|  |         removed, | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn prepare_render_asset<R: RenderAsset>( | ||||||
|  |     mut extracted_assets: ResMut<ExtractedAssets<R>>, | ||||||
|  |     mut render_assets: ResMut<RenderAssets<R>>, | ||||||
|  |     render_device: Res<RenderDevice>, | ||||||
|  |     render_queue: Res<RenderQueue>, | ||||||
|  | ) { | ||||||
|  |     for removed in extracted_assets.removed.iter() { | ||||||
|  |         render_assets.remove(removed); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (handle, extracted_asset) in extracted_assets.extracted.drain(..) { | ||||||
|  |         let prepared_asset = R::prepare_asset(extracted_asset, &render_device, &render_queue); | ||||||
|  |         render_assets.insert(handle, prepared_asset); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,25 +1,23 @@ | |||||||
| use super::image_texture_conversion::image_to_texture; | use super::image_texture_conversion::image_to_texture; | ||||||
| use crate::render_resource::{Sampler, Texture, TextureView}; | use crate::{ | ||||||
|  |     render_asset::RenderAsset, | ||||||
|  |     render_resource::{Sampler, Texture, TextureView}, | ||||||
|  |     renderer::{RenderDevice, RenderQueue}, | ||||||
|  | }; | ||||||
| use bevy_reflect::TypeUuid; | use bevy_reflect::TypeUuid; | ||||||
| use thiserror::Error; | use thiserror::Error; | ||||||
| use wgpu::{Extent3d, TextureDimension, TextureFormat}; | use wgpu::{ | ||||||
|  |     Extent3d, ImageCopyTexture, ImageDataLayout, Origin3d, TextureDimension, TextureFormat, | ||||||
|  |     TextureViewDescriptor, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| pub const TEXTURE_ASSET_INDEX: u64 = 0; | pub const TEXTURE_ASSET_INDEX: u64 = 0; | ||||||
| pub const SAMPLER_ASSET_INDEX: u64 = 1; | pub const SAMPLER_ASSET_INDEX: u64 = 1; | ||||||
| 
 | 
 | ||||||
| // TODO: this shouldn't live in the Texture type
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct ImageGpuData { |  | ||||||
|     pub texture: Texture, |  | ||||||
|     pub texture_view: TextureView, |  | ||||||
|     pub sampler: Sampler, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, TypeUuid)] | #[derive(Debug, Clone, TypeUuid)] | ||||||
| #[uuid = "6ea26da6-6cf8-4ea2-9986-1d7bf6c17d6f"] | #[uuid = "6ea26da6-6cf8-4ea2-9986-1d7bf6c17d6f"] | ||||||
| pub struct Image { | pub struct Image { | ||||||
|     pub data: Vec<u8>, |     pub data: Vec<u8>, | ||||||
|     pub gpu_data: Option<ImageGpuData>, |  | ||||||
|     // TODO: this nesting makes accessing Image metadata verbose. Either flatten out descriptor or add accessors
 |     // TODO: this nesting makes accessing Image metadata verbose. Either flatten out descriptor or add accessors
 | ||||||
|     pub texture_descriptor: wgpu::TextureDescriptor<'static>, |     pub texture_descriptor: wgpu::TextureDescriptor<'static>, | ||||||
|     pub sampler_descriptor: wgpu::SamplerDescriptor<'static>, |     pub sampler_descriptor: wgpu::SamplerDescriptor<'static>, | ||||||
| @ -29,7 +27,6 @@ impl Default for Image { | |||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
|         Image { |         Image { | ||||||
|             data: Default::default(), |             data: Default::default(), | ||||||
|             gpu_data: None, |  | ||||||
|             texture_descriptor: wgpu::TextureDescriptor { |             texture_descriptor: wgpu::TextureDescriptor { | ||||||
|                 size: wgpu::Extent3d { |                 size: wgpu::Extent3d { | ||||||
|                     width: 1, |                     width: 1, | ||||||
| @ -336,3 +333,57 @@ impl TextureFormatPixelInfo for TextureFormat { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct GpuImage { | ||||||
|  |     pub texture: Texture, | ||||||
|  |     pub texture_view: TextureView, | ||||||
|  |     pub sampler: Sampler, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl RenderAsset for Image { | ||||||
|  |     type ExtractedAsset = Image; | ||||||
|  |     type PreparedAsset = GpuImage; | ||||||
|  | 
 | ||||||
|  |     fn extract_asset(&self) -> Self::ExtractedAsset { | ||||||
|  |         self.clone() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn prepare_asset( | ||||||
|  |         image: Self::ExtractedAsset, | ||||||
|  |         render_device: &RenderDevice, | ||||||
|  |         render_queue: &RenderQueue, | ||||||
|  |     ) -> Self::PreparedAsset { | ||||||
|  |         let texture = render_device.create_texture(&image.texture_descriptor); | ||||||
|  |         let sampler = render_device.create_sampler(&image.sampler_descriptor); | ||||||
|  | 
 | ||||||
|  |         let width = image.texture_descriptor.size.width as usize; | ||||||
|  |         let format_size = image.texture_descriptor.format.pixel_size(); | ||||||
|  |         render_queue.write_texture( | ||||||
|  |             ImageCopyTexture { | ||||||
|  |                 texture: &texture, | ||||||
|  |                 mip_level: 0, | ||||||
|  |                 origin: Origin3d::ZERO, | ||||||
|  |             }, | ||||||
|  |             &image.data, | ||||||
|  |             ImageDataLayout { | ||||||
|  |                 offset: 0, | ||||||
|  |                 bytes_per_row: Some( | ||||||
|  |                     std::num::NonZeroU32::new( | ||||||
|  |                         image.texture_descriptor.size.width * format_size as u32, | ||||||
|  |                     ) | ||||||
|  |                     .unwrap(), | ||||||
|  |                 ), | ||||||
|  |                 rows_per_image: None, | ||||||
|  |             }, | ||||||
|  |             image.texture_descriptor.size, | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         let texture_view = texture.create_view(&TextureViewDescriptor::default()); | ||||||
|  |         GpuImage { | ||||||
|  |             texture, | ||||||
|  |             texture_view, | ||||||
|  |             sampler, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,27 +1,25 @@ | |||||||
| #[cfg(feature = "hdr")] | #[cfg(feature = "hdr")] | ||||||
| mod hdr_texture_loader; | mod hdr_texture_loader; | ||||||
| mod image_texture_loader; |  | ||||||
| #[allow(clippy::module_inception)] | #[allow(clippy::module_inception)] | ||||||
| mod texture; | mod image; | ||||||
|  | mod image_texture_loader; | ||||||
| mod texture_cache; | mod texture_cache; | ||||||
| 
 | 
 | ||||||
| pub(crate) mod image_texture_conversion; | pub(crate) mod image_texture_conversion; | ||||||
| 
 | 
 | ||||||
| #[cfg(feature = "hdr")] | #[cfg(feature = "hdr")] | ||||||
| pub use hdr_texture_loader::*; | pub use hdr_texture_loader::*; | ||||||
|  | pub use self::image::*; | ||||||
| pub use image_texture_loader::*; | pub use image_texture_loader::*; | ||||||
| pub use texture::*; |  | ||||||
| pub use texture_cache::*; | pub use texture_cache::*; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     renderer::{RenderDevice, RenderQueue}, |     render_asset::RenderAssetPlugin, | ||||||
|     RenderStage, |     RenderStage, | ||||||
| }; | }; | ||||||
| use bevy_app::{App, CoreStage, Plugin}; | use bevy_app::{App, Plugin}; | ||||||
| use bevy_asset::{AddAsset, AssetEvent, Assets}; | use bevy_asset::{AddAsset}; | ||||||
| use bevy_ecs::prelude::*; | use bevy_ecs::prelude::*; | ||||||
| use bevy_utils::HashSet; |  | ||||||
| use wgpu::{ImageCopyTexture, ImageDataLayout, Origin3d, TextureViewDescriptor}; |  | ||||||
| 
 | 
 | ||||||
| // TODO: replace Texture names with Image names?
 | // TODO: replace Texture names with Image names?
 | ||||||
| pub struct ImagePlugin; | pub struct ImagePlugin; | ||||||
| @ -33,7 +31,7 @@ impl Plugin for ImagePlugin { | |||||||
|             app.init_asset_loader::<ImageTextureLoader>(); |             app.init_asset_loader::<ImageTextureLoader>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         app.add_system_to_stage(CoreStage::PostUpdate, image_resource_system.system()) |         app.add_plugin(RenderAssetPlugin::<Image>::default()) | ||||||
|             .add_asset::<Image>(); |             .add_asset::<Image>(); | ||||||
| 
 | 
 | ||||||
|         let render_app = app.sub_app_mut(0); |         let render_app = app.sub_app_mut(0); | ||||||
| @ -43,93 +41,6 @@ impl Plugin for ImagePlugin { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn image_resource_system( |  | ||||||
|     render_device: Res<RenderDevice>, |  | ||||||
|     render_queue: Res<RenderQueue>, |  | ||||||
|     mut images: ResMut<Assets<Image>>, |  | ||||||
|     mut image_events: EventReader<AssetEvent<Image>>, |  | ||||||
| ) { |  | ||||||
|     let mut changed_images = HashSet::default(); |  | ||||||
|     for event in image_events.iter() { |  | ||||||
|         match event { |  | ||||||
|             AssetEvent::Created { handle } => { |  | ||||||
|                 changed_images.insert(handle); |  | ||||||
|             } |  | ||||||
|             AssetEvent::Modified { handle } => { |  | ||||||
|                 changed_images.insert(handle); |  | ||||||
|                 // TODO: uncomment this to support mutated textures
 |  | ||||||
|                 // remove_current_texture_resources(render_resource_context, handle, &mut textures);
 |  | ||||||
|             } |  | ||||||
|             AssetEvent::Removed { handle } => { |  | ||||||
|                 // if texture was modified and removed in the same update, ignore the
 |  | ||||||
|                 // modification events are ordered so future modification
 |  | ||||||
|                 // events are ok
 |  | ||||||
|                 changed_images.remove(handle); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for image_handle in changed_images.iter() { |  | ||||||
|         if let Some(image) = images.get_mut(*image_handle) { |  | ||||||
|             // TODO: this avoids creating new textures each frame because storing gpu data in the texture flags it as
 |  | ||||||
|             // modified. this prevents hot reloading and therefore can't be used in an actual impl.
 |  | ||||||
|             if image.gpu_data.is_some() { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             let texture = render_device.create_texture(&image.texture_descriptor); |  | ||||||
|             let sampler = render_device.create_sampler(&image.sampler_descriptor); |  | ||||||
| 
 |  | ||||||
|             let width = image.texture_descriptor.size.width as usize; |  | ||||||
|             let format_size = image.texture_descriptor.format.pixel_size(); |  | ||||||
|             // let mut aligned_data = vec![
 |  | ||||||
|             //     0;
 |  | ||||||
|             //     format_size
 |  | ||||||
|             //         * aligned_width
 |  | ||||||
|             //         * image.texture_descriptor.size.height as usize
 |  | ||||||
|             //         * image.texture_descriptor.size.depth_or_array_layers
 |  | ||||||
|             //             as usize
 |  | ||||||
|             // ];
 |  | ||||||
|             // image
 |  | ||||||
|             //     .data
 |  | ||||||
|             //     .chunks_exact(format_size * width)
 |  | ||||||
|             //     .enumerate()
 |  | ||||||
|             //     .for_each(|(index, row)| {
 |  | ||||||
|             //         let offset = index * aligned_width * format_size;
 |  | ||||||
|             //         aligned_data[offset..(offset + width * format_size)].copy_from_slice(row);
 |  | ||||||
|             //     });
 |  | ||||||
| 
 |  | ||||||
|             // TODO: this might require different alignment. docs seem to say that we don't need it though
 |  | ||||||
|             render_queue.write_texture( |  | ||||||
|                 ImageCopyTexture { |  | ||||||
|                     texture: &texture, |  | ||||||
|                     mip_level: 0, |  | ||||||
|                     origin: Origin3d::ZERO, |  | ||||||
|                 }, |  | ||||||
|                 &image.data, |  | ||||||
|                 ImageDataLayout { |  | ||||||
|                     offset: 0, |  | ||||||
|                     bytes_per_row: Some( |  | ||||||
|                         std::num::NonZeroU32::new( |  | ||||||
|                             image.texture_descriptor.size.width * format_size as u32, |  | ||||||
|                         ) |  | ||||||
|                         .unwrap(), |  | ||||||
|                     ), |  | ||||||
|                     rows_per_image: None, |  | ||||||
|                 }, |  | ||||||
|                 image.texture_descriptor.size, |  | ||||||
|             ); |  | ||||||
| 
 |  | ||||||
|             let texture_view = texture.create_view(&TextureViewDescriptor::default()); |  | ||||||
|             image.gpu_data = Some(ImageGpuData { |  | ||||||
|                 texture, |  | ||||||
|                 texture_view, |  | ||||||
|                 sampler, |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub trait BevyDefault { | pub trait BevyDefault { | ||||||
|     fn bevy_default() -> Self; |     fn bevy_default() -> Self; | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,13 +5,14 @@ use bevy_math::{Mat4, Vec2, Vec3, Vec4Swizzles}; | |||||||
| use bevy_render2::{ | use bevy_render2::{ | ||||||
|     core_pipeline::Transparent2dPhase, |     core_pipeline::Transparent2dPhase, | ||||||
|     mesh::{shape::Quad, Indices, Mesh, VertexAttributeValues}, |     mesh::{shape::Quad, Indices, Mesh, VertexAttributeValues}, | ||||||
|  |     render_asset::RenderAssets, | ||||||
|     render_graph::{Node, NodeRunError, RenderGraphContext}, |     render_graph::{Node, NodeRunError, RenderGraphContext}, | ||||||
|     render_phase::{Draw, DrawFunctions, Drawable, RenderPhase, TrackedRenderPass}, |     render_phase::{Draw, DrawFunctions, Drawable, RenderPhase, TrackedRenderPass}, | ||||||
|     render_resource::*, |     render_resource::*, | ||||||
|     renderer::{RenderContext, RenderDevice}, |     renderer::{RenderContext, RenderDevice}, | ||||||
|     shader::Shader, |     shader::Shader, | ||||||
|     texture::{BevyDefault, Image}, |     texture::{BevyDefault, Image}, | ||||||
|     view::{ViewMeta, ViewUniformOffset, ViewUniform}, |     view::{ViewMeta, ViewUniform, ViewUniformOffset}, | ||||||
| }; | }; | ||||||
| use bevy_transform::components::GlobalTransform; | use bevy_transform::components::GlobalTransform; | ||||||
| use bevy_utils::HashMap; | use bevy_utils::HashMap; | ||||||
| @ -48,8 +49,7 @@ impl FromWorld for SpriteShaders { | |||||||
|             source: ShaderSource::SpirV(Cow::Borrowed(&fragment_spirv)), |             source: ShaderSource::SpirV(Cow::Borrowed(&fragment_spirv)), | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         let view_layout = |         let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { | ||||||
|             render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { |  | ||||||
|             entries: &[BindGroupLayoutEntry { |             entries: &[BindGroupLayoutEntry { | ||||||
|                 binding: 0, |                 binding: 0, | ||||||
|                 visibility: ShaderStage::VERTEX | ShaderStage::FRAGMENT, |                 visibility: ShaderStage::VERTEX | ShaderStage::FRAGMENT, | ||||||
| @ -57,9 +57,7 @@ impl FromWorld for SpriteShaders { | |||||||
|                     ty: BufferBindingType::Uniform, |                     ty: BufferBindingType::Uniform, | ||||||
|                     has_dynamic_offset: true, |                     has_dynamic_offset: true, | ||||||
|                     // TODO: verify this is correct
 |                     // TODO: verify this is correct
 | ||||||
|                         min_binding_size: BufferSize::new( |                     min_binding_size: BufferSize::new(std::mem::size_of::<ViewUniform>() as u64), | ||||||
|                             std::mem::size_of::<ViewUniform>() as u64 |  | ||||||
|                         ), |  | ||||||
|                 }, |                 }, | ||||||
|                 count: None, |                 count: None, | ||||||
|             }], |             }], | ||||||
| @ -164,9 +162,7 @@ impl FromWorld for SpriteShaders { | |||||||
| struct ExtractedSprite { | struct ExtractedSprite { | ||||||
|     transform: Mat4, |     transform: Mat4, | ||||||
|     size: Vec2, |     size: Vec2, | ||||||
|     // TODO: use asset handle here instead of owned renderer handles (lots of arc cloning)
 |     handle: Handle<Image>, | ||||||
|     texture_view: TextureView, |  | ||||||
|     sampler: Sampler, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct ExtractedSprites { | pub struct ExtractedSprites { | ||||||
| @ -175,22 +171,21 @@ pub struct ExtractedSprites { | |||||||
| 
 | 
 | ||||||
| pub fn extract_sprites( | pub fn extract_sprites( | ||||||
|     mut commands: Commands, |     mut commands: Commands, | ||||||
|     textures: Res<Assets<Image>>, |     images: Res<Assets<Image>>, | ||||||
|     query: Query<(&Sprite, &GlobalTransform, &Handle<Image>)>, |     query: Query<(&Sprite, &GlobalTransform, &Handle<Image>)>, | ||||||
| ) { | ) { | ||||||
|     let mut extracted_sprites = Vec::new(); |     let mut extracted_sprites = Vec::new(); | ||||||
|     for (sprite, transform, handle) in query.iter() { |     for (sprite, transform, handle) in query.iter() { | ||||||
|         if let Some(texture) = textures.get(handle) { |         if !images.contains(handle) { | ||||||
|             if let Some(gpu_data) = &texture.gpu_data { |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         extracted_sprites.push(ExtractedSprite { |         extracted_sprites.push(ExtractedSprite { | ||||||
|             transform: transform.compute_matrix(), |             transform: transform.compute_matrix(), | ||||||
|             size: sprite.size, |             size: sprite.size, | ||||||
|                     texture_view: gpu_data.texture_view.clone(), |             handle: handle.clone_weak(), | ||||||
|                     sampler: gpu_data.sampler.clone(), |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     commands.insert_resource(ExtractedSprites { |     commands.insert_resource(ExtractedSprites { | ||||||
|         sprites: extracted_sprites, |         sprites: extracted_sprites, | ||||||
| @ -211,7 +206,7 @@ pub struct SpriteMeta { | |||||||
|     view_bind_group: Option<BindGroup>, |     view_bind_group: Option<BindGroup>, | ||||||
|     // TODO: these should be garbage collected if unused across X frames
 |     // TODO: these should be garbage collected if unused across X frames
 | ||||||
|     texture_bind_groups: Vec<BindGroup>, |     texture_bind_groups: Vec<BindGroup>, | ||||||
|     texture_bind_group_indices: HashMap<TextureViewId, usize>, |     texture_bind_group_indices: HashMap<Handle<Image>, usize>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for SpriteMeta { | impl Default for SpriteMeta { | ||||||
| @ -309,6 +304,7 @@ pub fn queue_sprites( | |||||||
|     view_meta: Res<ViewMeta>, |     view_meta: Res<ViewMeta>, | ||||||
|     sprite_shaders: Res<SpriteShaders>, |     sprite_shaders: Res<SpriteShaders>, | ||||||
|     extracted_sprites: Res<ExtractedSprites>, |     extracted_sprites: Res<ExtractedSprites>, | ||||||
|  |     gpu_images: Res<RenderAssets<Image>>, | ||||||
|     mut views: Query<&mut RenderPhase<Transparent2dPhase>>, |     mut views: Query<&mut RenderPhase<Transparent2dPhase>>, | ||||||
| ) { | ) { | ||||||
|     // TODO: define this without needing to check every frame
 |     // TODO: define this without needing to check every frame
 | ||||||
| @ -323,27 +319,25 @@ pub fn queue_sprites( | |||||||
|         }) |         }) | ||||||
|     }); |     }); | ||||||
|     let sprite_meta = &mut *sprite_meta; |     let sprite_meta = &mut *sprite_meta; | ||||||
|     for mut transparent_phase in views.iter_mut() { |  | ||||||
|         // TODO: free old bind groups? clear_unused_bind_groups() currently does this for us? Moving to RAII would also do this for us?
 |  | ||||||
|     let draw_sprite_function = draw_functions.read().get_id::<DrawSprite>().unwrap(); |     let draw_sprite_function = draw_functions.read().get_id::<DrawSprite>().unwrap(); | ||||||
| 
 |     for mut transparent_phase in views.iter_mut() { | ||||||
|         let texture_bind_groups = &mut sprite_meta.texture_bind_groups; |         let texture_bind_groups = &mut sprite_meta.texture_bind_groups; | ||||||
|         // let material_layout = ;
 |  | ||||||
|         for (i, sprite) in extracted_sprites.sprites.iter().enumerate() { |         for (i, sprite) in extracted_sprites.sprites.iter().enumerate() { | ||||||
|             let bind_group_index = *sprite_meta |             let bind_group_index = *sprite_meta | ||||||
|                 .texture_bind_group_indices |                 .texture_bind_group_indices | ||||||
|                 .entry(sprite.texture_view.id()) |                 .entry(sprite.handle.clone_weak()) | ||||||
|                 .or_insert_with(|| { |                 .or_insert_with(|| { | ||||||
|  |                     let gpu_image = gpu_images.get(&sprite.handle).unwrap(); | ||||||
|                     let index = texture_bind_groups.len(); |                     let index = texture_bind_groups.len(); | ||||||
|                     let bind_group = render_device.create_bind_group(&BindGroupDescriptor { |                     let bind_group = render_device.create_bind_group(&BindGroupDescriptor { | ||||||
|                         entries: &[ |                         entries: &[ | ||||||
|                             BindGroupEntry { |                             BindGroupEntry { | ||||||
|                                 binding: 0, |                                 binding: 0, | ||||||
|                                 resource: BindingResource::TextureView(&sprite.texture_view), |                                 resource: BindingResource::TextureView(&gpu_image.texture_view), | ||||||
|                             }, |                             }, | ||||||
|                             BindGroupEntry { |                             BindGroupEntry { | ||||||
|                                 binding: 1, |                                 binding: 1, | ||||||
|                                 resource: BindingResource::Sampler(&sprite.sampler), |                                 resource: BindingResource::Sampler(&gpu_image.sampler), | ||||||
|                             }, |                             }, | ||||||
|                         ], |                         ], | ||||||
|                         label: None, |                         label: None, | ||||||
| @ -410,10 +404,9 @@ impl Draw for DrawSprite { | |||||||
|     ) { |     ) { | ||||||
|         const INDICES: usize = 6; |         const INDICES: usize = 6; | ||||||
|         let (sprite_shaders, sprite_meta, views) = self.params.get(world); |         let (sprite_shaders, sprite_meta, views) = self.params.get(world); | ||||||
|         let (sprite_shaders, sprite_meta, views) = |  | ||||||
|             (sprite_shaders.into_inner(), sprite_meta.into_inner(), views); |  | ||||||
|         let view_uniform = views.get(view).unwrap(); |         let view_uniform = views.get(view).unwrap(); | ||||||
|         pass.set_render_pipeline(&sprite_shaders.pipeline); |         let sprite_meta = sprite_meta.into_inner(); | ||||||
|  |         pass.set_render_pipeline(&sprite_shaders.into_inner().pipeline); | ||||||
|         pass.set_vertex_buffer(0, sprite_meta.vertices.buffer().unwrap().slice(..)); |         pass.set_vertex_buffer(0, sprite_meta.vertices.buffer().unwrap().slice(..)); | ||||||
|         pass.set_index_buffer( |         pass.set_index_buffer( | ||||||
|             sprite_meta.indices.buffer().unwrap().slice(..), |             sprite_meta.indices.buffer().unwrap().slice(..), | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson