diff --git a/crates/bevy_core_pipeline/src/skybox/mod.rs b/crates/bevy_core_pipeline/src/skybox/mod.rs index 6dfe1af4dcd9f..c4a7803134ed3 100644 --- a/crates/bevy_core_pipeline/src/skybox/mod.rs +++ b/crates/bevy_core_pipeline/src/skybox/mod.rs @@ -18,7 +18,7 @@ use bevy_render::{ *, }, renderer::RenderDevice, - texture::{BevyDefault, Image}, + texture::{BevyDefault, GpuImage, Image}, view::{ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniforms}, Render, RenderApp, RenderSet, }; @@ -236,7 +236,7 @@ fn prepare_skybox_bind_groups( pipeline: Res, view_uniforms: Res, skybox_uniforms: Res>, - images: Res>, + images: Res>, render_device: Res, views: Query<(Entity, &Skybox, &DynamicUniformIndex)>, ) { diff --git a/crates/bevy_core_pipeline/src/tonemapping/mod.rs b/crates/bevy_core_pipeline/src/tonemapping/mod.rs index 2a61f5c60cfb3..b00aabcadb747 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/mod.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/mod.rs @@ -10,7 +10,7 @@ use bevy_render::render_resource::binding_types::{ sampler, texture_2d, texture_3d, uniform_buffer, }; use bevy_render::renderer::RenderDevice; -use bevy_render::texture::{CompressedImageFormats, Image, ImageSampler, ImageType}; +use bevy_render::texture::{CompressedImageFormats, GpuImage, Image, ImageSampler, ImageType}; use bevy_render::view::{ViewTarget, ViewUniform}; use bevy_render::{camera::Camera, texture::FallbackImage}; use bevy_render::{render_resource::*, Render, RenderApp, RenderSet}; @@ -319,7 +319,7 @@ pub enum DebandDither { } pub fn get_lut_bindings<'a>( - images: &'a RenderAssets, + images: &'a RenderAssets, tonemapping_luts: &'a TonemappingLuts, tonemapping: &Tonemapping, fallback_image: &'a FallbackImage, diff --git a/crates/bevy_core_pipeline/src/tonemapping/node.rs b/crates/bevy_core_pipeline/src/tonemapping/node.rs index cf8526b7ca68e..a7a3a4732a3f0 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/node.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/node.rs @@ -11,7 +11,7 @@ use bevy_render::{ RenderPassColorAttachment, RenderPassDescriptor, StoreOp, TextureViewId, }, renderer::RenderContext, - texture::{FallbackImage, Image}, + texture::{FallbackImage, GpuImage}, view::{ViewTarget, ViewUniformOffset, ViewUniforms}, }; @@ -42,7 +42,7 @@ impl ViewNode for TonemappingNode { ) -> Result<(), NodeRunError> { let pipeline_cache = world.resource::(); let tonemapping_pipeline = world.resource::(); - let gpu_images = world.get_resource::>().unwrap(); + let gpu_images = world.get_resource::>().unwrap(); let fallback_image = world.resource::(); let view_uniforms_resource = world.resource::(); let view_uniforms = &view_uniforms_resource.uniforms; diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 5bc45ead6bd35..0dc10d745f3af 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -79,9 +79,7 @@ use bevy_math::Vec3; use bevy_reflect::TypePath; use bevy_render::{ extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin}, - render_asset::{ - PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssetUsages, RenderAssets, - }, + render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets}, render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass}, render_resource::{ binding_types::uniform_buffer, BindGroup, BindGroupEntries, BindGroupLayout, @@ -129,7 +127,7 @@ impl Plugin for GizmoPlugin { .register_type::() .add_plugins(UniformComponentPlugin::::default()) .init_asset::() - .add_plugins(RenderAssetPlugin::::default()) + .add_plugins(RenderAssetPlugin::::default()) .init_resource::() // We insert the Resource GizmoConfigStore into the world implicitly here if it does not exist. .init_gizmo_group::() @@ -377,26 +375,22 @@ struct GpuLineGizmo { joints: GizmoLineJoint, } -impl RenderAsset for LineGizmo { - type PreparedAsset = GpuLineGizmo; +impl RenderAsset for GpuLineGizmo { + type SourceAsset = LineGizmo; type Param = SRes; - fn asset_usage(&self) -> RenderAssetUsages { - RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD - } - fn prepare_asset( - self, + gizmo: Self::SourceAsset, render_device: &mut SystemParamItem, - ) -> Result> { - let position_buffer_data = cast_slice(&self.positions); + ) -> Result> { + let position_buffer_data = cast_slice(&gizmo.positions); let position_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { usage: BufferUsages::VERTEX, label: Some("LineGizmo Position Buffer"), contents: position_buffer_data, }); - let color_buffer_data = cast_slice(&self.colors); + let color_buffer_data = cast_slice(&gizmo.colors); let color_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { usage: BufferUsages::VERTEX, label: Some("LineGizmo Color Buffer"), @@ -406,9 +400,9 @@ impl RenderAsset for LineGizmo { Ok(GpuLineGizmo { position_buffer, color_buffer, - vertex_count: self.positions.len() as u32, - strip: self.strip, - joints: self.joints, + vertex_count: gizmo.positions.len() as u32, + strip: gizmo.strip, + joints: gizmo.joints, }) } } @@ -468,7 +462,7 @@ impl RenderCommand

for SetLineGizmoBindGroup struct DrawLineGizmo; impl RenderCommand

for DrawLineGizmo { - type Param = SRes>; + type Param = SRes>; type ViewQuery = (); type ItemQuery = Read>; @@ -514,7 +508,7 @@ impl RenderCommand

for DrawLineGizmo { struct DrawLineJointGizmo; impl RenderCommand

for DrawLineJointGizmo { - type Param = SRes>; + type Param = SRes>; type ViewQuery = (); type ItemQuery = Read>; diff --git a/crates/bevy_gizmos/src/pipeline_2d.rs b/crates/bevy_gizmos/src/pipeline_2d.rs index 5110779078cbf..4fbf9544e22b5 100644 --- a/crates/bevy_gizmos/src/pipeline_2d.rs +++ b/crates/bevy_gizmos/src/pipeline_2d.rs @@ -1,8 +1,9 @@ use crate::{ config::{GizmoLineJoint, GizmoLineStyle, GizmoMeshConfig}, line_gizmo_vertex_buffer_layouts, line_joint_gizmo_vertex_buffer_layouts, DrawLineGizmo, - DrawLineJointGizmo, GizmoRenderSystem, LineGizmo, LineGizmoUniformBindgroupLayout, - SetLineGizmoBindGroup, LINE_JOINT_SHADER_HANDLE, LINE_SHADER_HANDLE, + DrawLineJointGizmo, GizmoRenderSystem, GpuLineGizmo, LineGizmo, + LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_JOINT_SHADER_HANDLE, + LINE_SHADER_HANDLE, }; use bevy_app::{App, Plugin}; use bevy_asset::Handle; @@ -52,7 +53,7 @@ impl Plugin for LineGizmo2dPlugin { Render, (queue_line_gizmos_2d, queue_line_joint_gizmos_2d) .in_set(GizmoRenderSystem::QueueLineGizmos2d) - .after(prepare_assets::), + .after(prepare_assets::), ); } @@ -253,7 +254,7 @@ fn queue_line_gizmos_2d( pipeline_cache: Res, msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, - line_gizmo_assets: Res>, + line_gizmo_assets: Res>, mut views: Query<( &ExtractedView, &mut SortedRenderPhase, @@ -306,7 +307,7 @@ fn queue_line_joint_gizmos_2d( pipeline_cache: Res, msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, - line_gizmo_assets: Res>, + line_gizmo_assets: Res>, mut views: Query<( &ExtractedView, &mut SortedRenderPhase, diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index ca53a1cdf2d54..ec9800330d1b7 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -1,8 +1,9 @@ use crate::{ config::{GizmoLineJoint, GizmoLineStyle, GizmoMeshConfig}, line_gizmo_vertex_buffer_layouts, line_joint_gizmo_vertex_buffer_layouts, DrawLineGizmo, - DrawLineJointGizmo, GizmoRenderSystem, LineGizmo, LineGizmoUniformBindgroupLayout, - SetLineGizmoBindGroup, LINE_JOINT_SHADER_HANDLE, LINE_SHADER_HANDLE, + DrawLineJointGizmo, GizmoRenderSystem, GpuLineGizmo, LineGizmo, + LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_JOINT_SHADER_HANDLE, + LINE_SHADER_HANDLE, }; use bevy_app::{App, Plugin}; use bevy_asset::Handle; @@ -51,7 +52,7 @@ impl Plugin for LineGizmo3dPlugin { Render, (queue_line_gizmos_3d, queue_line_joint_gizmos_3d) .in_set(GizmoRenderSystem::QueueLineGizmos3d) - .after(prepare_assets::), + .after(prepare_assets::), ); } @@ -278,7 +279,7 @@ fn queue_line_gizmos_3d( pipeline_cache: Res, msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, - line_gizmo_assets: Res>, + line_gizmo_assets: Res>, mut views: Query<( &ExtractedView, &mut SortedRenderPhase, @@ -361,7 +362,7 @@ fn queue_line_joint_gizmos_3d( pipeline_cache: Res, msaa: Res, line_gizmos: Query<(Entity, &Handle, &GizmoMeshConfig)>, - line_gizmo_assets: Res>, + line_gizmo_assets: Res>, mut views: Query<( &ExtractedView, &mut SortedRenderPhase, diff --git a/crates/bevy_pbr/src/extended_material.rs b/crates/bevy_pbr/src/extended_material.rs index a5c46ea6ffa8d..70f9ec34cc903 100644 --- a/crates/bevy_pbr/src/extended_material.rs +++ b/crates/bevy_pbr/src/extended_material.rs @@ -8,7 +8,7 @@ use bevy_render::{ ShaderRef, SpecializedMeshPipelineError, UnpreparedBindGroup, }, renderer::RenderDevice, - texture::{FallbackImage, Image}, + texture::{FallbackImage, GpuImage}, }; use crate::{Material, MaterialPipeline, MaterialPipelineKey, MeshPipeline, MeshPipelineKey}; @@ -139,7 +139,7 @@ impl AsBindGroup for ExtendedMaterial { &self, layout: &BindGroupLayout, render_device: &RenderDevice, - images: &RenderAssets, + images: &RenderAssets, fallback_image: &FallbackImage, ) -> Result, AsBindGroupError> { // add together the bindings of the base material and the user material diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index c87f14c6afe05..6603df730696f 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -95,7 +95,7 @@ use bevy_render::{ render_asset::prepare_assets, render_graph::RenderGraph, render_resource::Shader, - texture::Image, + texture::{GpuImage, Image}, view::VisibilitySystems, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -375,7 +375,7 @@ impl Plugin for PbrPlugin { ( prepare_lights .in_set(RenderSet::ManageViews) - .after(prepare_assets::), + .after(prepare_assets::), prepare_clusters.in_set(RenderSet::PrepareResources), ), ) diff --git a/crates/bevy_pbr/src/light_probe/environment_map.rs b/crates/bevy_pbr/src/light_probe/environment_map.rs index 268cbb3644ab6..e7340173a3568 100644 --- a/crates/bevy_pbr/src/light_probe/environment_map.rs +++ b/crates/bevy_pbr/src/light_probe/environment_map.rs @@ -60,7 +60,7 @@ use bevy_render::{ TextureSampleType, TextureView, }, renderer::RenderDevice, - texture::{FallbackImage, Image}, + texture::{FallbackImage, GpuImage, Image}, }; use std::num::NonZeroU32; @@ -213,7 +213,7 @@ impl<'a> RenderViewEnvironmentMapBindGroupEntries<'a> { /// specular binding arrays respectively, as well as the sampler. pub(crate) fn get( render_view_environment_maps: Option<&RenderViewLightProbes>, - images: &'a RenderAssets, + images: &'a RenderAssets, fallback_image: &'a FallbackImage, render_device: &RenderDevice, ) -> RenderViewEnvironmentMapBindGroupEntries<'a> { @@ -283,7 +283,7 @@ impl LightProbeComponent for EnvironmentMapLight { // view. type ViewLightProbeInfo = EnvironmentMapViewLightProbeInfo; - fn id(&self, image_assets: &RenderAssets) -> Option { + fn id(&self, image_assets: &RenderAssets) -> Option { if image_assets.get(&self.diffuse_map).is_none() || image_assets.get(&self.specular_map).is_none() { @@ -302,7 +302,7 @@ impl LightProbeComponent for EnvironmentMapLight { fn create_render_view_light_probes( view_component: Option<&EnvironmentMapLight>, - image_assets: &RenderAssets, + image_assets: &RenderAssets, ) -> RenderViewLightProbes { let mut render_view_light_probes = RenderViewLightProbes::new(); diff --git a/crates/bevy_pbr/src/light_probe/irradiance_volume.rs b/crates/bevy_pbr/src/light_probe/irradiance_volume.rs index c4efaf54d499f..978d34ee2b6f7 100644 --- a/crates/bevy_pbr/src/light_probe/irradiance_volume.rs +++ b/crates/bevy_pbr/src/light_probe/irradiance_volume.rs @@ -140,7 +140,7 @@ use bevy_render::{ TextureSampleType, TextureView, }, renderer::RenderDevice, - texture::{FallbackImage, Image}, + texture::{FallbackImage, GpuImage, Image}, }; use std::{num::NonZeroU32, ops::Deref}; @@ -212,7 +212,7 @@ impl<'a> RenderViewIrradianceVolumeBindGroupEntries<'a> { /// the view, as well as the sampler. pub(crate) fn get( render_view_irradiance_volumes: Option<&RenderViewLightProbes>, - images: &'a RenderAssets, + images: &'a RenderAssets, fallback_image: &'a FallbackImage, render_device: &RenderDevice, ) -> RenderViewIrradianceVolumeBindGroupEntries<'a> { @@ -236,7 +236,7 @@ impl<'a> RenderViewIrradianceVolumeBindGroupEntries<'a> { /// arrays are available on the current platform. fn get_multiple( render_view_irradiance_volumes: Option<&RenderViewLightProbes>, - images: &'a RenderAssets, + images: &'a RenderAssets, fallback_image: &'a FallbackImage, ) -> RenderViewIrradianceVolumeBindGroupEntries<'a> { let mut texture_views = vec![]; @@ -269,7 +269,7 @@ impl<'a> RenderViewIrradianceVolumeBindGroupEntries<'a> { /// arrays aren't available on the current platform. fn get_single( render_view_irradiance_volumes: Option<&RenderViewLightProbes>, - images: &'a RenderAssets, + images: &'a RenderAssets, fallback_image: &'a FallbackImage, ) -> RenderViewIrradianceVolumeBindGroupEntries<'a> { if let Some(irradiance_volumes) = render_view_irradiance_volumes { @@ -322,7 +322,7 @@ impl LightProbeComponent for IrradianceVolume { // here. type ViewLightProbeInfo = (); - fn id(&self, image_assets: &RenderAssets) -> Option { + fn id(&self, image_assets: &RenderAssets) -> Option { if image_assets.get(&self.voxels).is_none() { None } else { @@ -336,7 +336,7 @@ impl LightProbeComponent for IrradianceVolume { fn create_render_view_light_probes( _: Option<&Self>, - _: &RenderAssets, + _: &RenderAssets, ) -> RenderViewLightProbes { RenderViewLightProbes::new() } diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index 1a5df1b2caff0..964ffbc7c2a46 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -21,7 +21,7 @@ use bevy_render::{ render_resource::{DynamicUniformBuffer, Sampler, Shader, ShaderType, TextureView}, renderer::{RenderDevice, RenderQueue}, settings::WgpuFeatures, - texture::{FallbackImage, Image}, + texture::{FallbackImage, GpuImage, Image}, view::ExtractedView, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -270,7 +270,7 @@ pub trait LightProbeComponent: Send + Sync + Component + Sized { /// Returns the asset ID or asset IDs of the texture or textures referenced /// by this light probe. - fn id(&self, image_assets: &RenderAssets) -> Option; + fn id(&self, image_assets: &RenderAssets) -> Option; /// Returns the intensity of this light probe. /// @@ -284,7 +284,7 @@ pub trait LightProbeComponent: Send + Sync + Component + Sized { /// This is called for every light probe in view every frame. fn create_render_view_light_probes( view_component: Option<&Self>, - image_assets: &RenderAssets, + image_assets: &RenderAssets, ) -> RenderViewLightProbes; } @@ -342,7 +342,7 @@ impl Plugin for LightProbePlugin { /// Gathers up all light probes of a single type in the scene and assigns them /// to views, performing frustum culling and distance sorting in the process. fn gather_light_probes( - image_assets: Res>, + image_assets: Res>, light_probe_query: Extract>>, view_query: Extract), With>>, mut reflection_probes: Local>>, @@ -505,7 +505,7 @@ where /// every frame. fn new( (light_probe_transform, environment_map): (&GlobalTransform, &C), - image_assets: &RenderAssets, + image_assets: &RenderAssets, ) -> Option> { environment_map.id(image_assets).map(|id| LightProbeInfo { affine_transform: light_probe_transform.affine(), @@ -634,7 +634,7 @@ pub(crate) fn add_cubemap_texture_view<'a>( texture_views: &mut Vec<&'a ::Target>, sampler: &mut Option<&'a Sampler>, image_id: AssetId, - images: &'a RenderAssets, + images: &'a RenderAssets, fallback_image: &'a FallbackImage, ) { match images.get(image_id) { diff --git a/crates/bevy_pbr/src/lightmap/mod.rs b/crates/bevy_pbr/src/lightmap/mod.rs index 7299e9e946ec2..a57c2b8e4618e 100644 --- a/crates/bevy_pbr/src/lightmap/mod.rs +++ b/crates/bevy_pbr/src/lightmap/mod.rs @@ -40,6 +40,8 @@ use bevy_ecs::{ }; use bevy_math::{uvec2, vec4, Rect, UVec2}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; +use bevy_render::mesh::GpuMesh; +use bevy_render::texture::GpuImage; use bevy_render::{ mesh::Mesh, render_asset::RenderAssets, render_resource::Shader, texture::Image, view::ViewVisibility, Extract, ExtractSchedule, RenderApp, @@ -143,8 +145,8 @@ fn extract_lightmaps( mut render_lightmaps: ResMut, lightmaps: Extract>, render_mesh_instances: Res, - images: Res>, - meshes: Res>, + images: Res>, + meshes: Res>, ) { // Clear out the old frame's data. render_lightmaps.render_lightmaps.clear(); diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 4951d06eecf91..4785c4aed98db 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -4,7 +4,7 @@ use crate::meshlet::{ MeshletGpuScene, }; use crate::*; -use bevy_asset::{Asset, AssetEvent, AssetId, AssetServer}; +use bevy_asset::{Asset, AssetId, AssetServer}; use bevy_core_pipeline::{ core_3d::{ AlphaMask3d, Camera3d, Opaque3d, Opaque3dBinKey, ScreenSpaceTransmissionQuality, @@ -25,16 +25,15 @@ use bevy_render::{ camera::TemporalJitter, extract_instances::{ExtractInstancesPlugin, ExtractedInstances}, extract_resource::ExtractResource, - mesh::{Mesh, MeshVertexBufferLayoutRef}, - render_asset::RenderAssets, + mesh::{GpuMesh, MeshVertexBufferLayoutRef}, + render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets}, render_phase::*, render_resource::*, renderer::RenderDevice, texture::FallbackImage, view::{ExtractedView, Msaa, VisibleEntities}, - Extract, }; -use bevy_utils::{tracing::error, HashMap, HashSet}; +use bevy_utils::tracing::error; use std::marker::PhantomData; use std::sync::atomic::{AtomicU32, Ordering}; use std::{hash::Hash, num::NonZeroU32}; @@ -43,7 +42,7 @@ use self::{irradiance_volume::IrradianceVolume, prelude::EnvironmentMapLight}; /// Materials are used alongside [`MaterialPlugin`] and [`MaterialMeshBundle`] /// to spawn entities that are rendered with a specific [`Material`] type. They serve as an easy to use high level -/// way to render [`Mesh`] entities with custom shader logic. +/// way to render [`Mesh`](bevy_render::mesh::Mesh) entities with custom shader logic. /// /// Materials must implement [`AsBindGroup`] to define how data will be transferred to the GPU and bound in shaders. /// [`AsBindGroup`] can be derived, which makes generating bindings straightforward. See the [`AsBindGroup`] docs for details. @@ -250,8 +249,10 @@ where M::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { - app.init_asset::() - .add_plugins(ExtractInstancesPlugin::>::extract_visible()); + app.init_asset::().add_plugins(( + ExtractInstancesPlugin::>::extract_visible(), + RenderAssetPlugin::>::default(), + )); if let Some(render_app) = app.get_sub_app_mut(RenderApp) { render_app @@ -261,28 +262,20 @@ where .add_render_command::>() .add_render_command::>() .add_render_command::>() - .init_resource::>() - .init_resource::>() .init_resource::>>() - .add_systems(ExtractSchedule, extract_materials::) .add_systems( Render, - ( - prepare_materials:: - .in_set(RenderSet::PrepareAssets) - .after(prepare_assets::), - queue_material_meshes:: - .in_set(RenderSet::QueueMeshes) - .after(prepare_materials::), - ), + queue_material_meshes:: + .in_set(RenderSet::QueueMeshes) + .after(prepare_assets::>), ); if self.shadows_enabled { render_app.add_systems( Render, - (queue_shadows:: + queue_shadows:: .in_set(RenderSet::QueueMeshes) - .after(prepare_materials::),), + .after(prepare_assets::>), ); } @@ -438,7 +431,10 @@ type DrawMaterial = ( /// Sets the bind group for a given [`Material`] at the configured `I` index. pub struct SetMaterialBindGroup(PhantomData); impl RenderCommand

for SetMaterialBindGroup { - type Param = (SRes>, SRes>); + type Param = ( + SRes>>, + SRes>, + ); type ViewQuery = (); type ItemQuery = (); @@ -456,7 +452,7 @@ impl RenderCommand

for SetMaterial let Some(material_asset_id) = material_instances.get(&item.entity()) else { return RenderCommandResult::Failure; }; - let Some(material) = materials.get(material_asset_id) else { + let Some(material) = materials.get(*material_asset_id) else { return RenderCommandResult::Failure; }; pass.set_bind_group(I, &material.bind_group, &[]); @@ -522,8 +518,8 @@ pub fn queue_material_meshes( mut pipelines: ResMut>>, pipeline_cache: Res, msaa: Res, - render_meshes: Res>, - render_materials: Res>, + render_meshes: Res>, + render_materials: Res>>, render_mesh_instances: Res, render_material_instances: Res>, render_lightmaps: Res, @@ -657,7 +653,7 @@ pub fn queue_material_meshes( let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else { continue; }; - let Some(material) = render_materials.get(material_asset_id) else { + let Some(material) = render_materials.get(*material_asset_id) else { continue; }; @@ -846,6 +842,61 @@ pub struct PreparedMaterial { pub properties: MaterialProperties, } +impl RenderAsset for PreparedMaterial { + type SourceAsset = M; + + type Param = ( + SRes, + SRes>, + SRes, + SRes>, + SRes, + ); + + fn prepare_asset( + material: Self::SourceAsset, + (render_device, images, fallback_image, pipeline, default_opaque_render_method): &mut SystemParamItem, + ) -> Result> { + match material.as_bind_group( + &pipeline.material_layout, + render_device, + images, + fallback_image, + ) { + Ok(prepared) => { + let method = match material.opaque_render_method() { + OpaqueRendererMethod::Forward => OpaqueRendererMethod::Forward, + OpaqueRendererMethod::Deferred => OpaqueRendererMethod::Deferred, + OpaqueRendererMethod::Auto => default_opaque_render_method.0, + }; + let mut mesh_pipeline_key_bits = MeshPipelineKey::empty(); + mesh_pipeline_key_bits.set( + MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE, + material.reads_view_transmission_texture(), + ); + mesh_pipeline_key_bits.insert(alpha_mode_pipeline_key(material.alpha_mode())); + + Ok(PreparedMaterial { + bindings: prepared.bindings, + bind_group: prepared.bind_group, + key: prepared.data, + properties: MaterialProperties { + alpha_mode: material.alpha_mode(), + depth_bias: material.depth_bias(), + reads_view_transmission_texture: mesh_pipeline_key_bits + .contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE), + render_method: method, + mesh_pipeline_key_bits, + }, + }) + } + Err(AsBindGroupError::RetryNextUpdate) => { + Err(PrepareAssetError::RetryNextUpdate(material)) + } + } + } +} + #[derive(Component, Clone, Copy, Default, PartialEq, Eq, Deref, DerefMut)] pub struct MaterialBindGroupId(pub Option); @@ -894,181 +945,3 @@ impl PreparedMaterial { MaterialBindGroupId(Some(self.bind_group.id())) } } - -#[derive(Resource)] -pub struct ExtractedMaterials { - extracted: Vec<(AssetId, M)>, - removed: Vec>, -} - -impl Default for ExtractedMaterials { - fn default() -> Self { - Self { - extracted: Default::default(), - removed: Default::default(), - } - } -} - -/// Stores all prepared representations of [`Material`] assets for as long as they exist. -#[derive(Resource, Deref, DerefMut)] -pub struct RenderMaterials(pub HashMap, PreparedMaterial>); - -impl Default for RenderMaterials { - fn default() -> Self { - Self(Default::default()) - } -} - -/// This system extracts all created or modified assets of the corresponding [`Material`] type -/// into the "render world". -pub fn extract_materials( - mut commands: Commands, - mut events: Extract>>, - assets: Extract>>, -) { - let mut changed_assets = HashSet::default(); - let mut removed = Vec::new(); - for event in events.read() { - #[allow(clippy::match_same_arms)] - match event { - AssetEvent::Added { id } | AssetEvent::Modified { id } => { - changed_assets.insert(*id); - } - AssetEvent::Removed { id } => { - changed_assets.remove(id); - removed.push(*id); - } - AssetEvent::Unused { .. } => {} - AssetEvent::LoadedWithDependencies { .. } => { - // TODO: handle this - } - } - } - - let mut extracted_assets = Vec::new(); - for id in changed_assets.drain() { - if let Some(asset) = assets.get(id) { - extracted_assets.push((id, asset.clone())); - } - } - - commands.insert_resource(ExtractedMaterials { - extracted: extracted_assets, - removed, - }); -} - -/// All [`Material`] values of a given type that should be prepared next frame. -pub struct PrepareNextFrameMaterials { - assets: Vec<(AssetId, M)>, -} - -impl Default for PrepareNextFrameMaterials { - fn default() -> Self { - Self { - assets: Default::default(), - } - } -} - -/// This system prepares all assets of the corresponding [`Material`] type -/// which where extracted this frame for the GPU. -#[allow(clippy::too_many_arguments)] -pub fn prepare_materials( - mut prepare_next_frame: Local>, - mut extracted_assets: ResMut>, - mut render_materials: ResMut>, - render_device: Res, - images: Res>, - fallback_image: Res, - pipeline: Res>, - default_opaque_render_method: Res, -) { - let queued_assets = std::mem::take(&mut prepare_next_frame.assets); - for (id, material) in queued_assets.into_iter() { - if extracted_assets.removed.contains(&id) { - continue; - } - - match prepare_material( - &material, - &render_device, - &images, - &fallback_image, - &pipeline, - default_opaque_render_method.0, - ) { - Ok(prepared_asset) => { - render_materials.insert(id, prepared_asset); - } - Err(AsBindGroupError::RetryNextUpdate) => { - prepare_next_frame.assets.push((id, material)); - } - } - } - - for removed in std::mem::take(&mut extracted_assets.removed) { - render_materials.remove(&removed); - } - - for (id, material) in std::mem::take(&mut extracted_assets.extracted) { - match prepare_material( - &material, - &render_device, - &images, - &fallback_image, - &pipeline, - default_opaque_render_method.0, - ) { - Ok(prepared_asset) => { - render_materials.insert(id, prepared_asset); - } - Err(AsBindGroupError::RetryNextUpdate) => { - prepare_next_frame.assets.push((id, material)); - } - } - } -} - -fn prepare_material( - material: &M, - render_device: &RenderDevice, - images: &RenderAssets, - fallback_image: &FallbackImage, - pipeline: &MaterialPipeline, - default_opaque_render_method: OpaqueRendererMethod, -) -> Result, AsBindGroupError> { - let prepared = material.as_bind_group( - &pipeline.material_layout, - render_device, - images, - fallback_image, - )?; - let method = match material.opaque_render_method() { - OpaqueRendererMethod::Forward => OpaqueRendererMethod::Forward, - OpaqueRendererMethod::Deferred => OpaqueRendererMethod::Deferred, - OpaqueRendererMethod::Auto => default_opaque_render_method, - }; - - let mut mesh_pipeline_key_bits = MeshPipelineKey::empty(); - mesh_pipeline_key_bits.set( - MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE, - material.reads_view_transmission_texture(), - ); - mesh_pipeline_key_bits.insert(alpha_mode_pipeline_key(material.alpha_mode())); - - Ok(PreparedMaterial { - bindings: prepared.bindings, - bind_group: prepared.bind_group, - key: prepared.data, - properties: MaterialProperties { - alpha_mode: material.alpha_mode(), - depth_bias: material.depth_bias(), - reads_view_transmission_texture: mesh_pipeline_key_bits - .contains(MeshPipelineKey::READS_VIEW_TRANSMISSION_TEXTURE), - render_method: method, - mesh_pipeline_key_bits, - }, - }) -} diff --git a/crates/bevy_pbr/src/meshlet/material_draw_prepare.rs b/crates/bevy_pbr/src/meshlet/material_draw_prepare.rs index 937651834c10c..4790efc75b24d 100644 --- a/crates/bevy_pbr/src/meshlet/material_draw_prepare.rs +++ b/crates/bevy_pbr/src/meshlet/material_draw_prepare.rs @@ -10,6 +10,7 @@ use bevy_derive::{Deref, DerefMut}; use bevy_render::{ camera::TemporalJitter, mesh::{Mesh, MeshVertexBufferLayout, MeshVertexBufferLayoutRef, MeshVertexBufferLayouts}, + render_asset::RenderAssets, render_resource::*, view::ExtractedView, }; @@ -29,7 +30,7 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass( pipeline_cache: Res, material_pipeline: Res>, mesh_pipeline: Res, - render_materials: Res>, + render_materials: Res>>, render_material_instances: Res>, asset_server: Res, mut mesh_vertex_buffer_layouts: ResMut, @@ -139,7 +140,7 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass( view_key |= MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList); for material_id in render_material_instances.values() { - let Some(material) = render_materials.get(material_id) else { + let Some(material) = render_materials.get(*material_id) else { continue; }; @@ -226,7 +227,7 @@ pub fn prepare_material_meshlet_meshes_prepass( mut cache: Local>, pipeline_cache: Res, prepass_pipeline: Res>, - render_materials: Res>, + render_materials: Res>>, render_material_instances: Res>, mut mesh_vertex_buffer_layouts: ResMut, asset_server: Res, @@ -264,7 +265,7 @@ pub fn prepare_material_meshlet_meshes_prepass( view_key |= MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList); for material_id in render_material_instances.values() { - let Some(material) = render_materials.get(material_id) else { + let Some(material) = render_materials.get(*material_id) else { continue; }; diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 27c44a43dc7e9..0196a8956f5b2 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -651,7 +651,10 @@ pub struct StandardMaterialUniform { } impl AsBindGroupShaderType for StandardMaterial { - fn as_bind_group_shader_type(&self, images: &RenderAssets) -> StandardMaterialUniform { + fn as_bind_group_shader_type( + &self, + images: &RenderAssets, + ) -> StandardMaterialUniform { let mut flags = StandardMaterialFlags::NONE; if self.base_color_texture.is_some() { flags |= StandardMaterialFlags::BASE_COLOR_TEXTURE; diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index e43ab46b05e86..ad954cbc26f43 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,7 +1,7 @@ mod prepass_bindings; use bevy_render::batching::{batch_and_prepare_binned_render_phase, sort_binned_render_phase}; -use bevy_render::mesh::MeshVertexBufferLayoutRef; +use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef}; use bevy_render::render_resource::binding_types::uniform_buffer; pub use prepass_bindings::*; @@ -181,7 +181,7 @@ where Render, queue_prepass_material_meshes:: .in_set(RenderSet::QueueMeshes) - .after(prepare_materials::) + .after(prepare_assets::>) // queue_material_meshes only writes to `material_bind_group_id`, which `queue_prepass_material_meshes` doesn't read .ambiguous_with(queue_material_meshes::), ); @@ -714,9 +714,9 @@ pub fn queue_prepass_material_meshes( mut pipelines: ResMut>>, pipeline_cache: Res, msaa: Res, - render_meshes: Res>, + render_meshes: Res>, render_mesh_instances: Res, - render_materials: Res>, + render_materials: Res>>, render_material_instances: Res>, render_lightmaps: Res, mut views: Query< @@ -789,7 +789,7 @@ pub fn queue_prepass_material_meshes( let Some(mesh_instance) = render_mesh_instances.get(visible_entity) else { continue; }; - let Some(material) = render_materials.get(material_asset_id) else { + let Some(material) = render_materials.get(*material_asset_id) else { continue; }; let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else { diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index bb0c7853ddc50..dfc338f2fb3e1 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -3,10 +3,11 @@ use bevy_core_pipeline::core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT}; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_render::mesh::Mesh; use bevy_render::{ camera::Camera, diagnostic::RecordDiagnostics, - mesh::Mesh, + mesh::GpuMesh, primitives::{CascadesFrusta, CubemapFrusta, Frustum, HalfSpace}, render_asset::RenderAssets, render_graph::{Node, NodeRunError, RenderGraphContext}, @@ -1599,9 +1600,9 @@ pub fn prepare_clusters( pub fn queue_shadows( shadow_draw_functions: Res>, prepass_pipeline: Res>, - render_meshes: Res>, + render_meshes: Res>, render_mesh_instances: Res, - render_materials: Res>, + render_materials: Res>>, render_material_instances: Res>, mut pipelines: ResMut>>, pipeline_cache: Res, @@ -1659,7 +1660,7 @@ pub fn queue_shadows( let Some(material_asset_id) = render_material_instances.get(&entity) else { continue; }; - let Some(material) = render_materials.get(material_asset_id) else { + let Some(material) = render_materials.get(*material_asset_id) else { continue; }; let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else { diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 8319b30b68a96..f64fa2b2b5f12 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -22,7 +22,7 @@ use bevy_render::{ render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass}, render_resource::*, renderer::{RenderDevice, RenderQueue}, - texture::{BevyDefault, DefaultImageSampler, GpuImage, ImageSampler, TextureFormatPixelInfo}, + texture::{BevyDefault, DefaultImageSampler, ImageSampler, TextureFormatPixelInfo}, view::{ViewTarget, ViewUniformOffset, ViewVisibility}, Extract, }; @@ -427,7 +427,7 @@ impl FromWorld for MeshPipeline { impl MeshPipeline { pub fn get_image_texture<'a>( &'a self, - gpu_images: &'a RenderAssets, + gpu_images: &'a RenderAssets, handle_option: &Option>, ) -> Option<(&'a TextureView, &'a Sampler)> { if let Some(handle) = handle_option { @@ -1026,8 +1026,8 @@ impl MeshBindGroups { #[allow(clippy::too_many_arguments)] pub fn prepare_mesh_bind_group( - meshes: Res>, - images: Res>, + meshes: Res>, + images: Res>, mut groups: ResMut, mesh_pipeline: Res, render_device: Res, @@ -1187,7 +1187,7 @@ impl RenderCommand

for SetMeshBindGroup { pub struct DrawMesh; impl RenderCommand

for DrawMesh { - type Param = (SRes>, SRes); + type Param = (SRes>, SRes); type ViewQuery = (); type ItemQuery = (); #[inline] diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 7239ad01cbc60..90f1c802842cf 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -17,7 +17,7 @@ use bevy_render::{ render_asset::RenderAssets, render_resource::{binding_types::*, *}, renderer::RenderDevice, - texture::{BevyDefault, FallbackImage, FallbackImageMsaa, FallbackImageZero, Image}, + texture::{BevyDefault, FallbackImage, FallbackImageMsaa, FallbackImageZero, GpuImage}, view::{Msaa, ViewUniform, ViewUniforms}, }; @@ -370,7 +370,7 @@ pub fn prepare_mesh_view_bind_groups( Option<&RenderViewLightProbes>, )>, (images, mut fallback_images, fallback_image, fallback_image_zero): ( - Res>, + Res>, FallbackImageMsaa, Res, Res, diff --git a/crates/bevy_render/macros/src/as_bind_group.rs b/crates/bevy_render/macros/src/as_bind_group.rs index 06ce6f7982810..25887495f41bf 100644 --- a/crates/bevy_render/macros/src/as_bind_group.rs +++ b/crates/bevy_render/macros/src/as_bind_group.rs @@ -498,7 +498,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { &self, layout: &#render_path::render_resource::BindGroupLayout, render_device: &#render_path::renderer::RenderDevice, - images: &#render_path::render_asset::RenderAssets<#render_path::texture::Image>, + images: &#render_path::render_asset::RenderAssets<#render_path::texture::GpuImage>, fallback_image: &#render_path::texture::FallbackImage, ) -> Result<#render_path::render_resource::UnpreparedBindGroup, #render_path::render_resource::AsBindGroupError> { let bindings = vec![#(#binding_impls,)*]; diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 691d27d6d7685..4d25ada7859f3 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -1,11 +1,11 @@ use crate::{ - camera::CameraProjection, - camera::{ManualTextureViewHandle, ManualTextureViews}, + camera::{CameraProjection, ManualTextureViewHandle, ManualTextureViews}, prelude::Image, primitives::Frustum, render_asset::RenderAssets, render_graph::{InternedRenderSubGraph, RenderSubGraph}, render_resource::TextureView, + texture::GpuImage, view::{ColorGrading, ExtractedView, ExtractedWindows, RenderLayers, VisibleEntities}, Extract, }; @@ -581,7 +581,7 @@ impl NormalizedRenderTarget { pub fn get_texture_view<'a>( &self, windows: &'a ExtractedWindows, - images: &'a RenderAssets, + images: &'a RenderAssets, manual_texture_views: &'a ManualTextureViews, ) -> Option<&'a TextureView> { match self { @@ -601,7 +601,7 @@ impl NormalizedRenderTarget { pub fn get_texture_format<'a>( &self, windows: &'a ExtractedWindows, - images: &'a RenderAssets, + images: &'a RenderAssets, manual_texture_views: &'a ManualTextureViews, ) -> Option { match self { diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 78b8638571cca..cfbba600f0c05 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -61,10 +61,11 @@ use bevy_window::{PrimaryWindow, RawHandleWrapper}; use globals::GlobalsPlugin; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; +use crate::mesh::GpuMesh; use crate::renderer::WgpuWrapper; use crate::{ camera::CameraPlugin, - mesh::{morph::MorphPlugin, Mesh, MeshPlugin}, + mesh::{morph::MorphPlugin, MeshPlugin}, render_asset::prepare_assets, render_resource::{PipelineCache, Shader, ShaderLoader}, renderer::{render_system, RenderInstance}, @@ -111,7 +112,7 @@ pub enum RenderSet { /// Queue drawable entities as phase items in render phases ready for /// sorting (if necessary) Queue, - /// A sub-set within [`Queue`](RenderSet::Queue) where mesh entity queue systems are executed. Ensures `prepare_assets::` is completed. + /// A sub-set within [`Queue`](RenderSet::Queue) where mesh entity queue systems are executed. Ensures `prepare_assets::` is completed. QueueMeshes, // TODO: This could probably be moved in favor of a system ordering // abstraction in `Render` or `Queue` @@ -161,7 +162,7 @@ impl Render { ); schedule.configure_sets((ExtractCommands, PrepareAssets, Prepare).chain()); - schedule.configure_sets(QueueMeshes.in_set(Queue).after(prepare_assets::)); + schedule.configure_sets(QueueMeshes.in_set(Queue).after(prepare_assets::)); schedule.configure_sets( (PrepareResources, PrepareResourcesFlush, PrepareBindGroups) .chain() diff --git a/crates/bevy_render/src/mesh/mesh/mod.rs b/crates/bevy_render/src/mesh/mesh/mod.rs index 2cf32763d79c6..358b5a7119d13 100644 --- a/crates/bevy_render/src/mesh/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mesh/mod.rs @@ -10,6 +10,7 @@ use crate::{ render_asset::{PrepareAssetError, RenderAsset, RenderAssetUsages, RenderAssets}, render_resource::{Buffer, TextureView, VertexBufferLayout}, renderer::RenderDevice, + texture::GpuImage, }; use bevy_asset::{Asset, Handle}; use bevy_derive::EnumVariantMeta; @@ -1463,68 +1464,69 @@ pub enum GpuBufferInfo { NonIndexed, } -impl RenderAsset for Mesh { - type PreparedAsset = GpuMesh; +impl RenderAsset for GpuMesh { + type SourceAsset = Mesh; type Param = ( SRes, - SRes>, + SRes>, SResMut, ); - fn asset_usage(&self) -> RenderAssetUsages { - self.asset_usage + #[inline] + fn asset_usage(mesh: &Self::SourceAsset) -> RenderAssetUsages { + mesh.asset_usage } /// Converts the extracted mesh a into [`GpuMesh`]. fn prepare_asset( - self, + mesh: Self::SourceAsset, (render_device, images, ref mut mesh_vertex_buffer_layouts): &mut SystemParamItem< Self::Param, >, - ) -> Result> { - let morph_targets = match self.morph_targets.as_ref() { + ) -> Result> { + let morph_targets = match mesh.morph_targets.as_ref() { Some(mt) => { let Some(target_image) = images.get(mt) else { - return Err(PrepareAssetError::RetryNextUpdate(self)); + return Err(PrepareAssetError::RetryNextUpdate(mesh)); }; Some(target_image.texture_view.clone()) } None => None, }; - let vertex_buffer_data = self.get_vertex_buffer_data(); + let vertex_buffer_data = mesh.get_vertex_buffer_data(); let vertex_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { usage: BufferUsages::VERTEX, label: Some("Mesh Vertex Buffer"), contents: &vertex_buffer_data, }); - let buffer_info = if let Some(data) = self.get_index_buffer_bytes() { + let buffer_info = if let Some(data) = mesh.get_index_buffer_bytes() { GpuBufferInfo::Indexed { buffer: render_device.create_buffer_with_data(&BufferInitDescriptor { usage: BufferUsages::INDEX, contents: data, label: Some("Mesh Index Buffer"), }), - count: self.indices().unwrap().len() as u32, - index_format: self.indices().unwrap().into(), + count: mesh.indices().unwrap().len() as u32, + index_format: mesh.indices().unwrap().into(), } } else { GpuBufferInfo::NonIndexed }; let mesh_vertex_buffer_layout = - self.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts); + mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts); - let mut key_bits = BaseMeshPipelineKey::from_primitive_topology(self.primitive_topology()); + let mut key_bits = BaseMeshPipelineKey::from_primitive_topology(mesh.primitive_topology()); key_bits.set( BaseMeshPipelineKey::MORPH_TARGETS, - self.morph_targets.is_some(), + mesh.morph_targets.is_some(), ); Ok(GpuMesh { vertex_buffer, - vertex_count: self.count_vertices() as u32, + vertex_count: mesh.count_vertices() as u32, buffer_info, key_bits, layout: mesh_vertex_buffer_layout, diff --git a/crates/bevy_render/src/mesh/mod.rs b/crates/bevy_render/src/mesh/mod.rs index ab7b383f56176..cbac3705ddcd5 100644 --- a/crates/bevy_render/src/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mod.rs @@ -11,7 +11,7 @@ use std::{ sync::Arc, }; -use crate::{prelude::Image, render_asset::RenderAssetPlugin, RenderApp}; +use crate::{render_asset::RenderAssetPlugin, texture::GpuImage, RenderApp}; use bevy_app::{App, Plugin}; use bevy_asset::AssetApp; use bevy_ecs::{entity::Entity, system::Resource}; @@ -27,7 +27,7 @@ impl Plugin for MeshPlugin { .register_type::() .register_type::>() // 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready - .add_plugins(RenderAssetPlugin::::default()); + .add_plugins(RenderAssetPlugin::::default()); let Some(render_app) = app.get_sub_app_mut(RenderApp) else { return; diff --git a/crates/bevy_render/src/render_asset.rs b/crates/bevy_render/src/render_asset.rs index 213e79262a177..a7140bdc475a7 100644 --- a/crates/bevy_render/src/render_asset.rs +++ b/crates/bevy_render/src/render_asset.rs @@ -21,14 +21,14 @@ pub enum PrepareAssetError { /// Describes how an asset gets extracted and prepared for rendering. /// -/// In the [`ExtractSchedule`] step the asset is transferred +/// In the [`ExtractSchedule`] step the [`RenderAsset::SourceAsset`] is transferred /// from the "main world" into the "render world". /// /// After that in the [`RenderSet::PrepareAssets`] step the extracted asset -/// is transformed into its GPU-representation of type [`RenderAsset::PreparedAsset`]. -pub trait RenderAsset: Asset + Clone { - /// The GPU-representation of the asset. - type PreparedAsset: Send + Sync + 'static; +/// is transformed into its GPU-representation of type [`RenderAsset`]. +pub trait RenderAsset: Send + Sync + 'static + Sized { + /// The representation of the asset in the "main world". + type SourceAsset: Asset + Clone; /// Specifies all ECS data required by [`RenderAsset::prepare_asset`]. /// @@ -36,15 +36,18 @@ pub trait RenderAsset: Asset + Clone { type Param: SystemParam; /// Whether or not to unload the asset after extracting it to the render world. - fn asset_usage(&self) -> RenderAssetUsages; + #[inline] + fn asset_usage(_source_asset: &Self::SourceAsset) -> RenderAssetUsages { + RenderAssetUsages::default() + } - /// Prepares the asset for the GPU by transforming it into a [`RenderAsset::PreparedAsset`]. + /// Prepares the [`RenderAsset::SourceAsset`] for the GPU by transforming it into a [`RenderAsset`]. /// /// ECS data may be accessed via `param`. fn prepare_asset( - self, + source_asset: Self::SourceAsset, param: &mut SystemParamItem, - ) -> Result>; + ) -> Result>; } bitflags::bitflags! { @@ -101,8 +104,8 @@ impl Default for RenderAssetUsages { /// /// The `AFTER` generic parameter can be used to specify that `A::prepare_asset` should not be run until /// `prepare_assets::` has completed. This allows the `prepare_asset` function to depend on another -/// prepared [`RenderAsset`], for example `Mesh::prepare_asset` relies on `RenderAssets::` for morph -/// targets, so the plugin is created as `RenderAssetPlugin::::default()`. +/// prepared [`RenderAsset`], for example `Mesh::prepare_asset` relies on `RenderAssets::` for morph +/// targets, so the plugin is created as `RenderAssetPlugin::::default()`. pub struct RenderAssetPlugin { phantom: PhantomData (A, AFTER)>, } @@ -156,8 +159,8 @@ impl RenderAssetDependency for A { /// Temporarily stores the extracted and removed assets of the current frame. #[derive(Resource)] pub struct ExtractedAssets { - extracted: Vec<(AssetId, A)>, - removed: Vec>, + extracted: Vec<(AssetId, A::SourceAsset)>, + removed: Vec>, } impl Default for ExtractedAssets { @@ -169,10 +172,10 @@ impl Default for ExtractedAssets { } } -/// Stores all GPU representations ([`RenderAsset::PreparedAssets`](RenderAsset::PreparedAsset)) -/// of [`RenderAssets`](RenderAsset) as long as they exist. +/// Stores all GPU representations ([`RenderAsset`]) +/// of [`RenderAsset::SourceAsset`] as long as they exist. #[derive(Resource)] -pub struct RenderAssets(HashMap, A::PreparedAsset>); +pub struct RenderAssets(HashMap, A>); impl Default for RenderAssets { fn default() -> Self { @@ -181,31 +184,27 @@ impl Default for RenderAssets { } impl RenderAssets { - pub fn get(&self, id: impl Into>) -> Option<&A::PreparedAsset> { + pub fn get(&self, id: impl Into>) -> Option<&A> { self.0.get(&id.into()) } - pub fn get_mut(&mut self, id: impl Into>) -> Option<&mut A::PreparedAsset> { + pub fn get_mut(&mut self, id: impl Into>) -> Option<&mut A> { self.0.get_mut(&id.into()) } - pub fn insert( - &mut self, - id: impl Into>, - value: A::PreparedAsset, - ) -> Option { + pub fn insert(&mut self, id: impl Into>, value: A) -> Option { self.0.insert(id.into(), value) } - pub fn remove(&mut self, id: impl Into>) -> Option { + pub fn remove(&mut self, id: impl Into>) -> Option { self.0.remove(&id.into()) } - pub fn iter(&self) -> impl Iterator, &A::PreparedAsset)> { + pub fn iter(&self) -> impl Iterator, &A)> { self.0.iter().map(|(k, v)| (*k, v)) } - pub fn iter_mut(&mut self) -> impl Iterator, &mut A::PreparedAsset)> { + pub fn iter_mut(&mut self) -> impl Iterator, &mut A)> { self.0.iter_mut().map(|(k, v)| (*k, v)) } } @@ -213,8 +212,8 @@ impl RenderAssets { #[derive(Resource)] struct CachedExtractRenderAssetSystemState { state: SystemState<( - EventReader<'static, 'static, AssetEvent>, - ResMut<'static, Assets>, + EventReader<'static, 'static, AssetEvent>, + ResMut<'static, Assets>, )>, } @@ -226,7 +225,7 @@ impl FromWorld for CachedExtractRenderAssetSystemState { } } -/// This system extracts all created or modified assets of the corresponding [`RenderAsset`] type +/// This system extracts all created or modified assets of the corresponding [`RenderAsset::SourceAsset`] type /// into the "render world". fn extract_render_asset(mut commands: Commands, mut main_world: ResMut) { main_world.resource_scope( @@ -256,7 +255,7 @@ fn extract_render_asset(mut commands: Commands, mut main_world: let mut extracted_assets = Vec::new(); for id in changed_assets.drain() { if let Some(asset) = assets.get(id) { - let asset_usage = asset.asset_usage(); + let asset_usage = A::asset_usage(asset); if asset_usage.contains(RenderAssetUsages::RENDER_WORLD) { if asset_usage == RenderAssetUsages::RENDER_WORLD { if let Some(asset) = assets.remove(id) { @@ -269,7 +268,7 @@ fn extract_render_asset(mut commands: Commands, mut main_world: } } - commands.insert_resource(ExtractedAssets { + commands.insert_resource(ExtractedAssets:: { extracted: extracted_assets, removed, }); @@ -282,7 +281,7 @@ fn extract_render_asset(mut commands: Commands, mut main_world: /// All assets that should be prepared next frame. #[derive(Resource)] pub struct PrepareNextFrameAssets { - assets: Vec<(AssetId, A)>, + assets: Vec<(AssetId, A::SourceAsset)>, } impl Default for PrepareNextFrameAssets { @@ -293,7 +292,7 @@ impl Default for PrepareNextFrameAssets { } } -/// This system prepares all assets of the corresponding [`RenderAsset`] type +/// This system prepares all assets of the corresponding [`RenderAsset::SourceAsset`] type /// which where extracted this frame for the GPU. pub fn prepare_assets( mut extracted_assets: ResMut>, @@ -308,7 +307,7 @@ pub fn prepare_assets( continue; } - match extracted_asset.prepare_asset(&mut param) { + match A::prepare_asset(extracted_asset, &mut param) { Ok(prepared_asset) => { render_assets.insert(id, prepared_asset); } @@ -323,7 +322,7 @@ pub fn prepare_assets( } for (id, extracted_asset) in extracted_assets.extracted.drain(..) { - match extracted_asset.prepare_asset(&mut param) { + match A::prepare_asset(extracted_asset, &mut param) { Ok(prepared_asset) => { render_assets.insert(id, prepared_asset); } diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index 96f885f8e9c1d..ff61060ce796d 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -1,10 +1,9 @@ use crate::{ define_atomic_id, - prelude::Image, render_asset::RenderAssets, render_resource::{resource_macros::*, BindGroupLayout, Buffer, Sampler, TextureView}, renderer::RenderDevice, - texture::FallbackImage, + texture::{FallbackImage, GpuImage}, }; pub use bevy_render_macros::AsBindGroup; use encase::ShaderType; @@ -58,14 +57,14 @@ impl Deref for BindGroup { /// /// This is an opinionated trait that is intended to make it easy to generically /// convert a type into a [`BindGroup`]. It provides access to specific render resources, -/// such as [`RenderAssets`] and [`FallbackImage`]. If a type has a [`Handle`](bevy_asset::Handle), +/// such as [`RenderAssets`] and [`FallbackImage`]. If a type has a [`Handle`](bevy_asset::Handle), /// these can be used to retrieve the corresponding [`Texture`](crate::render_resource::Texture) resource. /// /// [`AsBindGroup::as_bind_group`] is intended to be called once, then the result cached somewhere. It is generally /// ok to do "expensive" work here, such as creating a [`Buffer`] for a uniform. /// /// If for some reason a [`BindGroup`] cannot be created yet (for example, the [`Texture`](crate::render_resource::Texture) -/// for an [`Image`] hasn't loaded yet), just return [`AsBindGroupError::RetryNextUpdate`], which signals that the caller +/// for an [`Image`](crate::texture::Image) hasn't loaded yet), just return [`AsBindGroupError::RetryNextUpdate`], which signals that the caller /// should retry again later. /// /// # Deriving @@ -117,7 +116,7 @@ impl Deref for BindGroup { /// GPU resource, which will be bound as a texture in shaders. The field will be assumed to implement [`Into>>`]. In practice, /// most fields should be a [`Handle`](bevy_asset::Handle) or [`Option>`]. If the value of an [`Option>`] is /// [`None`], the [`FallbackImage`] resource will be used instead. This attribute can be used in conjunction with a `sampler` binding attribute -/// (with a different binding index) if a binding of the sampler for the [`Image`] is also required. +/// (with a different binding index) if a binding of the sampler for the [`Image`](crate::texture::Image) is also required. /// /// | Arguments | Values | Default | /// |-----------------------|-------------------------------------------------------------------------|----------------------| @@ -145,7 +144,7 @@ impl Deref for BindGroup { /// resource, which will be bound as a sampler in shaders. The field will be assumed to implement [`Into>>`]. In practice, /// most fields should be a [`Handle`](bevy_asset::Handle) or [`Option>`]. If the value of an [`Option>`] is /// [`None`], the [`FallbackImage`] resource will be used instead. This attribute can be used in conjunction with a `texture` binding attribute -/// (with a different binding index) if a binding of the texture for the [`Image`] is also required. +/// (with a different binding index) if a binding of the texture for the [`Image`](crate::texture::Image) is also required. /// /// | Arguments | Values | Default | /// |------------------------|-------------------------------------------------------------------------|------------------------| @@ -220,7 +219,7 @@ impl Deref for BindGroup { /// much like the field-level `uniform` attribute. The difference is that the entire [`AsBindGroup`] value is converted to `ConvertedShaderType`, /// which must implement [`ShaderType`], instead of a specific field implementing [`ShaderType`]. This is useful if more complicated conversion /// logic is required. The conversion is done using the [`AsBindGroupShaderType`] trait, which is automatically implemented -/// if `&Self` implements [`Into`]. Only use [`AsBindGroupShaderType`] if access to resources like [`RenderAssets`] is +/// if `&Self` implements [`Into`]. Only use [`AsBindGroupShaderType`] if access to resources like [`RenderAssets`] is /// required. /// * `bind_group_data(DataType)` /// * The [`AsBindGroup`] type will be converted to some `DataType` using [`Into`] and stored @@ -295,7 +294,7 @@ pub trait AsBindGroup { &self, layout: &BindGroupLayout, render_device: &RenderDevice, - images: &RenderAssets, + images: &RenderAssets, fallback_image: &FallbackImage, ) -> Result, AsBindGroupError> { let UnpreparedBindGroup { bindings, data } = @@ -326,7 +325,7 @@ pub trait AsBindGroup { &self, layout: &BindGroupLayout, render_device: &RenderDevice, - images: &RenderAssets, + images: &RenderAssets, fallback_image: &FallbackImage, ) -> Result, AsBindGroupError>; @@ -396,7 +395,7 @@ impl OwnedBindingResource { pub trait AsBindGroupShaderType { /// Return the `T` [`ShaderType`] for `self`. When used in [`AsBindGroup`] /// derives, it is safe to assume that all images in `self` exist. - fn as_bind_group_shader_type(&self, images: &RenderAssets) -> T; + fn as_bind_group_shader_type(&self, images: &RenderAssets) -> T; } impl AsBindGroupShaderType for T @@ -404,7 +403,7 @@ where for<'a> &'a T: Into, { #[inline] - fn as_bind_group_shader_type(&self, _images: &RenderAssets) -> U { + fn as_bind_group_shader_type(&self, _images: &RenderAssets) -> U { self.into() } } @@ -412,7 +411,7 @@ where #[cfg(test)] mod test { use super::*; - use crate as bevy_render; + use crate::{self as bevy_render, prelude::Image}; use bevy_asset::Handle; #[test] diff --git a/crates/bevy_render/src/texture/image.rs b/crates/bevy_render/src/texture/image.rs index 4b8a5d71ceb25..720c2282d7351 100644 --- a/crates/bevy_render/src/texture/image.rs +++ b/crates/bevy_render/src/texture/image.rs @@ -826,39 +826,41 @@ pub struct GpuImage { pub mip_level_count: u32, } -impl RenderAsset for Image { - type PreparedAsset = GpuImage; +impl RenderAsset for GpuImage { + type SourceAsset = Image; type Param = ( SRes, SRes, SRes, ); - fn asset_usage(&self) -> RenderAssetUsages { - self.asset_usage + #[inline] + fn asset_usage(image: &Self::SourceAsset) -> RenderAssetUsages { + image.asset_usage } /// Converts the extracted image into a [`GpuImage`]. fn prepare_asset( - self, + image: Self::SourceAsset, (render_device, render_queue, default_sampler): &mut SystemParamItem, - ) -> Result> { + ) -> Result> { let texture = render_device.create_texture_with_data( render_queue, - &self.texture_descriptor, + &image.texture_descriptor, // TODO: Is this correct? Do we need to use `MipMajor` if it's a ktx2 file? wgpu::util::TextureDataOrder::default(), - &self.data, + &image.data, ); - let size = self.size(); + let size = image.size(); let texture_view = texture.create_view( - self.texture_view_descriptor + image + .texture_view_descriptor .or_else(|| Some(TextureViewDescriptor::default())) .as_ref() .unwrap(), ); - let sampler = match self.sampler { + let sampler = match image.sampler { ImageSampler::Default => (***default_sampler).clone(), ImageSampler::Descriptor(descriptor) => { render_device.create_sampler(&descriptor.as_wgpu()) @@ -868,10 +870,10 @@ impl RenderAsset for Image { Ok(GpuImage { texture, texture_view, - texture_format: self.texture_descriptor.format, + texture_format: image.texture_descriptor.format, sampler, size, - mip_level_count: self.texture_descriptor.mip_level_count, + mip_level_count: image.texture_descriptor.mip_level_count, }) } } diff --git a/crates/bevy_render/src/texture/mod.rs b/crates/bevy_render/src/texture/mod.rs index 880a988449e28..ac5d74cdc73b8 100644 --- a/crates/bevy_render/src/texture/mod.rs +++ b/crates/bevy_render/src/texture/mod.rs @@ -84,7 +84,7 @@ impl Plugin for ImagePlugin { app.init_asset_loader::(); } - app.add_plugins(RenderAssetPlugin::::default()) + app.add_plugins(RenderAssetPlugin::::default()) .register_type::() .init_asset::() .register_asset_reflect::(); diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index 0d1958bf7d4de..1fef36c5844a0 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -11,13 +11,15 @@ use crate::{ ManualTextureViews, MipBias, TemporalJitter, }, extract_resource::{ExtractResource, ExtractResourcePlugin}, - prelude::{Image, Shader}, + prelude::Shader, primitives::Frustum, render_asset::RenderAssets, render_phase::ViewRangefinder3d, render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView}, renderer::{RenderDevice, RenderQueue}, - texture::{BevyDefault, CachedTexture, ColorAttachment, DepthAttachment, TextureCache}, + texture::{ + BevyDefault, CachedTexture, ColorAttachment, DepthAttachment, GpuImage, TextureCache, + }, Render, RenderApp, RenderSet, }; use bevy_app::{App, Plugin}; @@ -62,7 +64,7 @@ impl Plugin for ViewPlugin { prepare_view_targets .in_set(RenderSet::ManageViews) .after(prepare_windows) - .after(crate::render_asset::prepare_assets::) + .after(crate::render_asset::prepare_assets::) .ambiguous_with(crate::camera::sort_cameras), // doesn't use `sorted_camera_index_for_target` prepare_view_uniforms.in_set(RenderSet::PrepareResources), ), @@ -460,7 +462,7 @@ struct MainTargetTextures { pub fn prepare_view_targets( mut commands: Commands, windows: Res, - images: Res>, + images: Res>, msaa: Res, clear_color_global: Res, render_device: Res, diff --git a/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs b/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs index 3b0d7e5bab933..078816ecdeeb7 100644 --- a/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs +++ b/crates/bevy_sprite/src/dynamic_texture_atlas_builder.rs @@ -3,7 +3,7 @@ use bevy_asset::{Assets, Handle}; use bevy_math::{URect, UVec2}; use bevy_render::{ render_asset::{RenderAsset, RenderAssetUsages}, - texture::{Image, TextureFormatPixelInfo}, + texture::{GpuImage, Image, TextureFormatPixelInfo}, }; use guillotiere::{size2, Allocation, AtlasAllocator}; @@ -56,8 +56,7 @@ impl DynamicTextureAtlasBuilder { if let Some(allocation) = allocation { let atlas_texture = textures.get_mut(atlas_texture_handle).unwrap(); assert!( - atlas_texture - .asset_usage() + ::asset_usage(atlas_texture) .contains(RenderAssetUsages::MAIN_WORLD), "The asset at atlas_texture_handle must have the RenderAssetUsages::MAIN_WORLD usage flag set" ); diff --git a/crates/bevy_sprite/src/mesh2d/color_material.rs b/crates/bevy_sprite/src/mesh2d/color_material.rs index 4e5f9ae64aef2..9bf6581b8848f 100644 --- a/crates/bevy_sprite/src/mesh2d/color_material.rs +++ b/crates/bevy_sprite/src/mesh2d/color_material.rs @@ -4,7 +4,11 @@ use bevy_asset::{load_internal_asset, Asset, AssetApp, Assets, Handle}; use bevy_color::{Color, LinearRgba}; use bevy_math::Vec4; use bevy_reflect::prelude::*; -use bevy_render::{render_asset::RenderAssets, render_resource::*, texture::Image}; +use bevy_render::{ + render_asset::RenderAssets, + render_resource::*, + texture::{GpuImage, Image}, +}; pub const COLOR_MATERIAL_SHADER_HANDLE: Handle = Handle::weak_from_u128(3253086872234592509); @@ -92,7 +96,7 @@ pub struct ColorMaterialUniform { } impl AsBindGroupShaderType for ColorMaterial { - fn as_bind_group_shader_type(&self, _images: &RenderAssets) -> ColorMaterialUniform { + fn as_bind_group_shader_type(&self, _images: &RenderAssets) -> ColorMaterialUniform { let mut flags = ColorMaterialFlags::NONE; if self.texture.is_some() { flags |= ColorMaterialFlags::TEXTURE; diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index ad05b7fe61737..9322b5f4b25a1 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -1,5 +1,5 @@ use bevy_app::{App, Plugin}; -use bevy_asset::{Asset, AssetApp, AssetEvent, AssetId, AssetServer, Assets, Handle}; +use bevy_asset::{Asset, AssetApp, AssetId, AssetServer, Handle}; use bevy_core_pipeline::{ core_2d::Transparent2d, tonemapping::{DebandDither, Tonemapping}, @@ -12,9 +12,10 @@ use bevy_ecs::{ }; use bevy_math::FloatOrd; use bevy_render::{ - mesh::{Mesh, MeshVertexBufferLayoutRef}, - prelude::Image, - render_asset::{prepare_assets, RenderAssets}, + mesh::{GpuMesh, MeshVertexBufferLayoutRef}, + render_asset::{ + prepare_assets, PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets, + }, render_phase::{ AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, SetItemPipeline, SortedRenderPhase, TrackedRenderPass, @@ -25,13 +26,12 @@ use bevy_render::{ SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines, }, renderer::RenderDevice, - texture::FallbackImage, + texture::{FallbackImage, GpuImage}, view::{ExtractedView, InheritedVisibility, Msaa, ViewVisibility, Visibility, VisibleEntities}, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::components::{GlobalTransform, Transform}; use bevy_utils::tracing::error; -use bevy_utils::{HashMap, HashSet}; use std::hash::Hash; use std::marker::PhantomData; @@ -148,29 +148,20 @@ where M::Data: PartialEq + Eq + Hash + Clone, { fn build(&self, app: &mut App) { - app.init_asset::(); + app.init_asset::() + .add_plugins(RenderAssetPlugin::>::default()); if let Some(render_app) = app.get_sub_app_mut(RenderApp) { render_app .add_render_command::>() - .init_resource::>() - .init_resource::>() .init_resource::>() .init_resource::>>() - .add_systems( - ExtractSchedule, - (extract_materials_2d::, extract_material_meshes_2d::), - ) + .add_systems(ExtractSchedule, extract_material_meshes_2d::) .add_systems( Render, - ( - prepare_materials_2d:: - .in_set(RenderSet::PrepareAssets) - .after(prepare_assets::), - queue_material2d_meshes:: - .in_set(RenderSet::QueueMeshes) - .after(prepare_materials_2d::), - ), + queue_material2d_meshes:: + .in_set(RenderSet::QueueMeshes) + .after(prepare_assets::>), ); } } @@ -330,7 +321,7 @@ impl RenderCommand

for SetMaterial2dBindGroup { type Param = ( - SRes>, + SRes>>, SRes>, ); type ViewQuery = (); @@ -349,7 +340,7 @@ impl RenderCommand

let Some(material_instance) = material_instances.get(&item.entity()) else { return RenderCommandResult::Failure; }; - let Some(material2d) = materials.get(material_instance) else { + let Some(material2d) = materials.get(*material_instance) else { return RenderCommandResult::Failure; }; pass.set_bind_group(I, &material2d.bind_group, &[]); @@ -379,8 +370,8 @@ pub fn queue_material2d_meshes( mut pipelines: ResMut>>, pipeline_cache: Res, msaa: Res, - render_meshes: Res>, - render_materials: Res>, + render_meshes: Res>, + render_materials: Res>>, mut render_mesh_instances: ResMut, render_material_instances: Res>, mut views: Query<( @@ -419,7 +410,7 @@ pub fn queue_material2d_meshes( let Some(mesh_instance) = render_mesh_instances.get_mut(visible_entity) else { continue; }; - let Some(material2d) = render_materials.get(material_asset_id) else { + let Some(material2d) = render_materials.get(*material_asset_id) else { continue; }; let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else { @@ -483,159 +474,39 @@ impl PreparedMaterial2d { } } -#[derive(Resource)] -pub struct ExtractedMaterials2d { - extracted: Vec<(AssetId, M)>, - removed: Vec>, -} - -impl Default for ExtractedMaterials2d { - fn default() -> Self { - Self { - extracted: Default::default(), - removed: Default::default(), - } - } -} - -/// Stores all prepared representations of [`Material2d`] assets for as long as they exist. -#[derive(Resource, Deref, DerefMut)] -pub struct RenderMaterials2d(HashMap, PreparedMaterial2d>); - -impl Default for RenderMaterials2d { - fn default() -> Self { - Self(Default::default()) - } -} - -/// This system extracts all created or modified assets of the corresponding [`Material2d`] type -/// into the "render world". -pub fn extract_materials_2d( - mut commands: Commands, - mut events: Extract>>, - assets: Extract>>, -) { - let mut changed_assets = HashSet::default(); - let mut removed = Vec::new(); - for event in events.read() { - #[allow(clippy::match_same_arms)] - match event { - AssetEvent::Added { id } | AssetEvent::Modified { id } => { - changed_assets.insert(*id); - } - AssetEvent::Removed { id } => { - changed_assets.remove(id); - removed.push(*id); - } - AssetEvent::Unused { .. } => {} - AssetEvent::LoadedWithDependencies { .. } => { - // TODO: handle this - } - } - } - - let mut extracted_assets = Vec::new(); - for id in changed_assets.drain() { - if let Some(asset) = assets.get(id) { - extracted_assets.push((id, asset.clone())); - } - } +impl RenderAsset for PreparedMaterial2d { + type SourceAsset = M; - commands.insert_resource(ExtractedMaterials2d { - extracted: extracted_assets, - removed, - }); -} - -/// All [`Material2d`] values of a given type that should be prepared next frame. -pub struct PrepareNextFrameMaterials { - assets: Vec<(AssetId, M)>, -} - -impl Default for PrepareNextFrameMaterials { - fn default() -> Self { - Self { - assets: Default::default(), - } - } -} - -/// This system prepares all assets of the corresponding [`Material2d`] type -/// which where extracted this frame for the GPU. -pub fn prepare_materials_2d( - mut prepare_next_frame: Local>, - mut extracted_assets: ResMut>, - mut render_materials: ResMut>, - render_device: Res, - images: Res>, - fallback_image: Res, - pipeline: Res>, -) { - let queued_assets = std::mem::take(&mut prepare_next_frame.assets); - for (id, material) in queued_assets { - if extracted_assets.removed.contains(&id) { - continue; - } - - match prepare_material2d( - &material, - &render_device, - &images, - &fallback_image, - &pipeline, - ) { - Ok(prepared_asset) => { - render_materials.insert(id, prepared_asset); - } - Err(AsBindGroupError::RetryNextUpdate) => { - prepare_next_frame.assets.push((id, material)); - } - } - } - - for removed in std::mem::take(&mut extracted_assets.removed) { - render_materials.remove(&removed); - } + type Param = ( + SRes, + SRes>, + SRes, + SRes>, + ); - for (asset_id, material) in std::mem::take(&mut extracted_assets.extracted) { - match prepare_material2d( - &material, - &render_device, - &images, - &fallback_image, - &pipeline, + fn prepare_asset( + material: Self::SourceAsset, + (render_device, images, fallback_image, pipeline): &mut SystemParamItem, + ) -> Result> { + match material.as_bind_group( + &pipeline.material2d_layout, + render_device, + images, + fallback_image, ) { - Ok(prepared_asset) => { - render_materials.insert(asset_id, prepared_asset); - } + Ok(prepared) => Ok(PreparedMaterial2d { + bindings: prepared.bindings, + bind_group: prepared.bind_group, + key: prepared.data, + depth_bias: material.depth_bias(), + }), Err(AsBindGroupError::RetryNextUpdate) => { - prepare_next_frame.assets.push((asset_id, material)); + Err(PrepareAssetError::RetryNextUpdate(material)) } } } } -fn prepare_material2d( - material: &M, - render_device: &RenderDevice, - images: &RenderAssets, - fallback_image: &FallbackImage, - pipeline: &Material2dPipeline, -) -> Result, AsBindGroupError> { - let prepared = material.as_bind_group( - &pipeline.material2d_layout, - render_device, - images, - fallback_image, - )?; - Ok(PreparedMaterial2d { - bindings: prepared.bindings, - bind_group: prepared.bind_group, - key: prepared.data, - depth_bias: material.depth_bias(), - }) -} - /// A component bundle for entities with a [`Mesh2dHandle`] and a [`Material2d`]. #[derive(Bundle, Clone)] pub struct MaterialMesh2dBundle { diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index d62255263c591..edf8dd4fabf4a 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -11,7 +11,7 @@ use bevy_ecs::{ }; use bevy_math::{Affine3, Vec4}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; -use bevy_render::mesh::MeshVertexBufferLayoutRef; +use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef}; use bevy_render::{ batching::{ batch_and_prepare_sorted_render_phase, write_batched_instance_buffer, GetBatchData, @@ -323,7 +323,7 @@ impl FromWorld for Mesh2dPipeline { impl Mesh2dPipeline { pub fn get_image_texture<'a>( &'a self, - gpu_images: &'a RenderAssets, + gpu_images: &'a RenderAssets, handle_option: &Option>, ) -> Option<(&'a TextureView, &'a Sampler)> { if let Some(handle) = handle_option { @@ -666,7 +666,7 @@ impl RenderCommand

for SetMesh2dBindGroup { pub struct DrawMesh2d; impl RenderCommand

for DrawMesh2d { - type Param = (SRes>, SRes); + type Param = (SRes>, SRes); type ViewQuery = (); type ItemQuery = (); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index a3160342bcf72..202a68dbe20da 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -528,7 +528,7 @@ pub fn prepare_sprites( view_uniforms: Res, sprite_pipeline: Res, mut image_bind_groups: ResMut, - gpu_images: Res>, + gpu_images: Res>, extracted_sprites: Res, mut phases: Query<&mut SortedRenderPhase>, events: Res, diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 9c4ce3ae18796..c03b90004b778 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -7,6 +7,7 @@ use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d}; use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; +use bevy_render::texture::GpuImage; use bevy_render::{render_phase::PhaseItem, view::ViewVisibility, ExtractSchedule, Render}; use bevy_sprite::{SpriteAssetEvents, TextureAtlas}; pub use pipeline::*; @@ -920,7 +921,7 @@ pub fn prepare_uinodes( view_uniforms: Res, ui_pipeline: Res, mut image_bind_groups: ResMut, - gpu_images: Res>, + gpu_images: Res>, mut phases: Query<&mut SortedRenderPhase>, events: Res, mut previous_len: Local, diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 33e293bab6096..b4d13ac65ac13 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -1,7 +1,6 @@ use std::{hash::Hash, marker::PhantomData, ops::Range}; use bevy_asset::*; -use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ prelude::Component, query::ROQueryItem, @@ -13,16 +12,15 @@ use bevy_math::{FloatOrd, Mat4, Rect, Vec2, Vec4Swizzles}; use bevy_render::{ extract_component::ExtractComponentPlugin, globals::{GlobalsBuffer, GlobalsUniform}, - render_asset::RenderAssets, + render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets}, render_phase::*, render_resource::{binding_types::uniform_buffer, *}, renderer::{RenderDevice, RenderQueue}, - texture::{BevyDefault, FallbackImage, Image}, + texture::{BevyDefault, FallbackImage, GpuImage}, view::*, Extract, ExtractSchedule, Render, RenderSet, }; use bevy_transform::prelude::GlobalTransform; -use bevy_utils::{HashMap, HashSet}; use bevy_window::{PrimaryWindow, Window}; use bytemuck::{Pod, Zeroable}; @@ -59,28 +57,24 @@ where "ui_material.wgsl", Shader::from_wgsl ); - app.init_asset::() - .add_plugins(ExtractComponentPlugin::>::extract_visible()); + app.init_asset::().add_plugins(( + ExtractComponentPlugin::>::extract_visible(), + RenderAssetPlugin::>::default(), + )); if let Some(render_app) = app.get_sub_app_mut(RenderApp) { render_app .add_render_command::>() - .init_resource::>() .init_resource::>() - .init_resource::>() .init_resource::>() .init_resource::>>() .add_systems( ExtractSchedule, - ( - extract_ui_materials::, - extract_ui_material_nodes::.in_set(RenderUiSystem::ExtractBackgrounds), - ), + extract_ui_material_nodes::.in_set(RenderUiSystem::ExtractBackgrounds), ) .add_systems( Render, ( - prepare_ui_materials::.in_set(RenderSet::PrepareAssets), queue_ui_material_nodes::.in_set(RenderSet::Queue), prepare_uimaterial_nodes::.in_set(RenderSet::PrepareBindGroups), ), @@ -286,7 +280,7 @@ pub struct SetUiMaterialBindGroup(PhantomData) impl RenderCommand

for SetUiMaterialBindGroup { - type Param = SRes>; + type Param = SRes>>; type ViewQuery = (); type ItemQuery = Read>; @@ -300,7 +294,7 @@ impl RenderCommand

let Some(material_handle) = material_handle else { return RenderCommandResult::Failure; }; - let Some(material) = materials.into_inner().get(&material_handle.material) else { + let Some(material) = materials.into_inner().get(material_handle.material) else { return RenderCommandResult::Failure; }; pass.set_bind_group(I, &material.bind_group, &[]); @@ -601,154 +595,39 @@ pub fn prepare_uimaterial_nodes( extracted_uinodes.uinodes.clear(); } -#[derive(Resource, Deref, DerefMut)] -pub struct RenderUiMaterials(HashMap, PreparedUiMaterial>); - -impl Default for RenderUiMaterials { - fn default() -> Self { - Self(Default::default()) - } -} - pub struct PreparedUiMaterial { pub bindings: Vec<(u32, OwnedBindingResource)>, pub bind_group: BindGroup, pub key: T::Data, } -#[derive(Resource)] -pub struct ExtractedUiMaterials { - extracted: Vec<(AssetId, M)>, - removed: Vec>, -} - -impl Default for ExtractedUiMaterials { - fn default() -> Self { - Self { - extracted: Default::default(), - removed: Default::default(), - } - } -} - -pub fn extract_ui_materials( - mut commands: Commands, - mut events: Extract>>, - assets: Extract>>, -) { - let mut changed_assets = HashSet::default(); - let mut removed = Vec::new(); - for event in events.read() { - #[allow(clippy::match_same_arms)] - match event { - AssetEvent::Added { id } | AssetEvent::Modified { id } => { - changed_assets.insert(*id); - } - AssetEvent::Removed { id } => { - changed_assets.remove(id); - removed.push(*id); - } - AssetEvent::Unused { .. } => {} - AssetEvent::LoadedWithDependencies { .. } => { - // TODO: handle this - } - } - } - - let mut extracted_assets = Vec::new(); - for id in changed_assets.drain() { - if let Some(asset) = assets.get(id) { - extracted_assets.push((id, asset.clone())); - } - } - - commands.insert_resource(ExtractedUiMaterials { - extracted: extracted_assets, - removed, - }); -} - -pub struct PrepareNextFrameMaterials { - assets: Vec<(AssetId, M)>, -} - -impl Default for PrepareNextFrameMaterials { - fn default() -> Self { - Self { - assets: Default::default(), - } - } -} - -pub fn prepare_ui_materials( - mut prepare_next_frame: Local>, - mut extracted_assets: ResMut>, - mut render_materials: ResMut>, - render_device: Res, - images: Res>, - fallback_image: Res, - pipeline: Res>, -) { - let queued_assets = std::mem::take(&mut prepare_next_frame.assets); - for (id, material) in queued_assets { - if extracted_assets.removed.contains(&id) { - continue; - } - - match prepare_ui_material( - &material, - &render_device, - &images, - &fallback_image, - &pipeline, - ) { - Ok(prepared_asset) => { - render_materials.insert(id, prepared_asset); - } - Err(AsBindGroupError::RetryNextUpdate) => { - prepare_next_frame.assets.push((id, material)); - } - } - } - - for removed in std::mem::take(&mut extracted_assets.removed) { - render_materials.remove(&removed); - } - - for (handle, material) in std::mem::take(&mut extracted_assets.extracted) { - match prepare_ui_material( - &material, - &render_device, - &images, - &fallback_image, - &pipeline, - ) { - Ok(prepared_asset) => { - render_materials.insert(handle, prepared_asset); - } +impl RenderAsset for PreparedUiMaterial { + type SourceAsset = M; + + type Param = ( + SRes, + SRes>, + SRes, + SRes>, + ); + + fn prepare_asset( + material: Self::SourceAsset, + (render_device, images, fallback_image, pipeline): &mut SystemParamItem, + ) -> Result> { + match material.as_bind_group(&pipeline.ui_layout, render_device, images, fallback_image) { + Ok(prepared) => Ok(PreparedUiMaterial { + bindings: prepared.bindings, + bind_group: prepared.bind_group, + key: prepared.data, + }), Err(AsBindGroupError::RetryNextUpdate) => { - prepare_next_frame.assets.push((handle, material)); + Err(PrepareAssetError::RetryNextUpdate(material)) } } } } -fn prepare_ui_material( - material: &M, - render_device: &RenderDevice, - images: &RenderAssets, - fallback_image: &Res, - pipeline: &UiMaterialPipeline, -) -> Result, AsBindGroupError> { - let prepared = - material.as_bind_group(&pipeline.ui_layout, render_device, images, fallback_image)?; - Ok(PreparedUiMaterial { - bindings: prepared.bindings, - bind_group: prepared.bind_group, - key: prepared.data, - }) -} - #[allow(clippy::too_many_arguments)] pub fn queue_ui_material_nodes( extracted_uinodes: Res>, @@ -756,7 +635,7 @@ pub fn queue_ui_material_nodes( ui_material_pipeline: Res>, mut pipelines: ResMut>>, pipeline_cache: Res, - render_materials: Res>, + render_materials: Res>>, mut views: Query<(&ExtractedView, &mut SortedRenderPhase)>, ) where M::Data: PartialEq + Eq + Hash + Clone, @@ -764,7 +643,7 @@ pub fn queue_ui_material_nodes( let draw_function = draw_functions.read().id::>(); for (entity, extracted_uinode) in extracted_uinodes.uinodes.iter() { - let Some(material) = render_materials.get(&extracted_uinode.material) else { + let Some(material) = render_materials.get(extracted_uinode.material) else { continue; }; let Ok((view, mut transparent_phase)) = views.get_mut(extracted_uinode.camera_entity) diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index d8a5524aa8938..462b0bbfd6c4d 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -11,7 +11,7 @@ use bevy::{ math::FloatOrd, prelude::*, render::{ - mesh::{Indices, MeshVertexAttribute}, + mesh::{GpuMesh, Indices, MeshVertexAttribute}, render_asset::{RenderAssetUsages, RenderAssets}, render_phase::{AddRenderCommand, DrawFunctions, SetItemPipeline, SortedRenderPhase}, render_resource::{ @@ -356,7 +356,7 @@ pub fn queue_colored_mesh2d( mut pipelines: ResMut>, pipeline_cache: Res, msaa: Res, - render_meshes: Res>, + render_meshes: Res>, render_mesh_instances: Res, mut views: Query<( &VisibleEntities, diff --git a/examples/shader/compute_shader_game_of_life.rs b/examples/shader/compute_shader_game_of_life.rs index a26bb6c308416..266cd50713b81 100644 --- a/examples/shader/compute_shader_game_of_life.rs +++ b/examples/shader/compute_shader_game_of_life.rs @@ -11,6 +11,7 @@ use bevy::{ render_graph::{self, RenderGraph, RenderLabel}, render_resource::{binding_types::texture_storage_2d, *}, renderer::{RenderContext, RenderDevice}, + texture::GpuImage, Render, RenderApp, RenderSet, }, }; @@ -129,7 +130,7 @@ struct GameOfLifeImageBindGroups([BindGroup; 2]); fn prepare_bind_group( mut commands: Commands, pipeline: Res, - gpu_images: Res>, + gpu_images: Res>, game_of_life_images: Res, render_device: Res, ) { diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index 44a01c75845d4..b44c96e1c3029 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -12,7 +12,7 @@ use bevy::{ prelude::*, render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, - mesh::{GpuBufferInfo, MeshVertexBufferLayoutRef}, + mesh::{GpuBufferInfo, GpuMesh, MeshVertexBufferLayoutRef}, render_asset::RenderAssets, render_phase::{ AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, @@ -114,7 +114,7 @@ fn queue_custom( msaa: Res, mut pipelines: ResMut>, pipeline_cache: Res, - meshes: Res>, + meshes: Res>, render_mesh_instances: Res, material_meshes: Query>, mut views: Query<(&ExtractedView, &mut SortedRenderPhase)>, @@ -234,7 +234,7 @@ type DrawCustom = ( struct DrawMeshInstanced; impl RenderCommand

for DrawMeshInstanced { - type Param = (SRes>, SRes); + type Param = (SRes>, SRes); type ViewQuery = (); type ItemQuery = Read; diff --git a/examples/shader/texture_binding_array.rs b/examples/shader/texture_binding_array.rs index 252172f5838ae..710bec904be79 100644 --- a/examples/shader/texture_binding_array.rs +++ b/examples/shader/texture_binding_array.rs @@ -5,8 +5,11 @@ use bevy::{ prelude::*, reflect::TypePath, render::{ - render_asset::RenderAssets, render_resource::*, renderer::RenderDevice, - texture::FallbackImage, RenderApp, + render_asset::RenderAssets, + render_resource::*, + renderer::RenderDevice, + texture::{FallbackImage, GpuImage}, + RenderApp, }, }; use std::{num::NonZeroU32, process::exit}; @@ -92,7 +95,7 @@ impl AsBindGroup for BindlessMaterial { &self, layout: &BindGroupLayout, render_device: &RenderDevice, - image_assets: &RenderAssets, + image_assets: &RenderAssets, fallback_image: &FallbackImage, ) -> Result, AsBindGroupError> { // retrieve the render resources from handles @@ -133,7 +136,7 @@ impl AsBindGroup for BindlessMaterial { &self, _: &BindGroupLayout, _: &RenderDevice, - _: &RenderAssets, + _: &RenderAssets, _: &FallbackImage, ) -> Result, AsBindGroupError> { // we implement as_bind_group directly because