diff --git a/examples/shader/custom_shader_pipelined.rs b/examples/shader/custom_shader_pipelined.rs index dab60f7e6df961..622c9d69565aef 100644 --- a/examples/shader/custom_shader_pipelined.rs +++ b/examples/shader/custom_shader_pipelined.rs @@ -135,8 +135,12 @@ pub struct CustomPipeline { impl SpecializedPipeline for CustomPipeline { type Key = MeshPipelineKey; - fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let mut descriptor = self.mesh_pipeline.specialize(key); + fn specialize( + &self, + key: Self::Key, + vertex_layout: &VertexBufferLayout, + ) -> RenderPipelineDescriptor { + let mut descriptor = self.mesh_pipeline.specialize(key, vertex_layout); descriptor.fragment.as_mut().unwrap().shader = self.shader.clone(); descriptor.layout = Some(vec![ self.mesh_pipeline.view_layout.clone(), @@ -177,11 +181,12 @@ impl FromWorld for CustomPipeline { pub fn queue_custom( transparent_3d_draw_functions: Res>, materials: Res>, + render_meshes: Res>, custom_pipeline: Res, mut pipeline_cache: ResMut, mut specialized_pipelines: ResMut>, msaa: Res, - material_meshes: Query<(Entity, &Handle, &MeshUniform), With>>, + material_meshes: Query<(Entity, &Handle, &Handle, &MeshUniform)>, mut views: Query<(&ExtractedView, &mut RenderPhase)>, ) { let draw_custom = transparent_3d_draw_functions @@ -192,14 +197,16 @@ pub fn queue_custom( for (view, mut transparent_phase) in views.iter_mut() { let view_matrix = view.transform.compute_matrix(); let view_row_2 = view_matrix.row(2); - for (entity, material_handle, mesh_uniform) in material_meshes.iter() { + for (entity, material_handle, mesh_handle, mesh_uniform) in material_meshes.iter() { if materials.contains_key(material_handle) { + let mesh = render_meshes.get(mesh_handle).unwrap(); transparent_phase.add(Transparent3d { entity, pipeline: specialized_pipelines.specialize( &mut pipeline_cache, &custom_pipeline, key, + &mesh.vertex_layout, ), draw_function: draw_custom, distance: view_row_2.dot(mesh_uniform.transform.col(3)), diff --git a/examples/shader/shader_defs_pipelined.rs b/examples/shader/shader_defs_pipelined.rs index 8fde88640d1f87..2865f0f605484e 100644 --- a/examples/shader/shader_defs_pipelined.rs +++ b/examples/shader/shader_defs_pipelined.rs @@ -11,6 +11,7 @@ use bevy::{ render2::{ camera::PerspectiveCameraBundle, mesh::{shape, Mesh}, + render_asset::RenderAssets, render_component::{ExtractComponent, ExtractComponentPlugin}, render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline}, render_resource::*, @@ -105,12 +106,18 @@ impl FromWorld for IsRedPipeline { impl SpecializedPipeline for IsRedPipeline { type Key = (IsRed, MeshPipelineKey); - fn specialize(&self, (is_red, pbr_pipeline_key): Self::Key) -> RenderPipelineDescriptor { + fn specialize( + &self, + (is_red, pbr_pipeline_key): Self::Key, + vertex_layout: &VertexBufferLayout, + ) -> RenderPipelineDescriptor { let mut shader_defs = Vec::new(); if is_red.0 { shader_defs.push("IS_RED".to_string()); } - let mut descriptor = self.mesh_pipline.specialize(pbr_pipeline_key); + let mut descriptor = self + .mesh_pipline + .specialize(pbr_pipeline_key, vertex_layout); descriptor.vertex.shader = self.shader.clone(); descriptor.vertex.shader_defs = shader_defs.clone(); let fragment = descriptor.fragment.as_mut().unwrap(); @@ -131,13 +138,15 @@ type DrawIsRed = ( DrawMesh, ); +#[allow(clippy::too_many_arguments)] fn queue_custom( transparent_3d_draw_functions: Res>, custom_pipeline: Res, msaa: Res, + render_meshes: Res>, mut pipelines: ResMut>, mut pipeline_cache: ResMut, - material_meshes: Query<(Entity, &MeshUniform, &IsRed), With>>, + material_meshes: Query<(Entity, &Handle, &MeshUniform, &IsRed)>, mut views: Query<(&ExtractedView, &mut RenderPhase)>, ) { let draw_custom = transparent_3d_draw_functions @@ -148,9 +157,14 @@ fn queue_custom( for (view, mut transparent_phase) in views.iter_mut() { let view_matrix = view.transform.compute_matrix(); let view_row_2 = view_matrix.row(2); - for (entity, mesh_uniform, is_red) in material_meshes.iter() { - let pipeline = - pipelines.specialize(&mut pipeline_cache, &custom_pipeline, (*is_red, key)); + for (entity, mesh_handle, mesh_uniform, is_red) in material_meshes.iter() { + let mesh = render_meshes.get(mesh_handle).unwrap(); + let pipeline = pipelines.specialize( + &mut pipeline_cache, + &custom_pipeline, + (*is_red, key), + &mesh.vertex_layout, + ); transparent_phase.add(Transparent3d { entity, pipeline, diff --git a/pipelined/bevy_gltf2/src/loader.rs b/pipelined/bevy_gltf2/src/loader.rs index 560d221388a7e8..86e88f01afe682 100644 --- a/pipelined/bevy_gltf2/src/loader.rs +++ b/pipelined/bevy_gltf2/src/loader.rs @@ -14,6 +14,7 @@ use bevy_render2::{ color::Color, mesh::{Indices, Mesh, VertexAttributeValues}, primitives::Aabb, + render_resource::VertexFormat, texture::{Image, ImageType, TextureError}, }; use bevy_scene::Scene; @@ -134,6 +135,8 @@ async fn load_gltf<'a, 'b>( .read_tangents() .map(|v| VertexAttributeValues::Float32x4(v.collect())) { + mesh.vertex_layout_mut() + .push(Mesh::ATTRIBUTE_TANGENT, VertexFormat::Float32x4); mesh.set_attribute(Mesh::ATTRIBUTE_TANGENT, vertex_attribute); } diff --git a/pipelined/bevy_pbr2/src/render/light.rs b/pipelined/bevy_pbr2/src/render/light.rs index 211efb8df15f42..c3b1e7552bc230 100644 --- a/pipelined/bevy_pbr2/src/render/light.rs +++ b/pipelined/bevy_pbr2/src/render/light.rs @@ -181,73 +181,17 @@ bitflags::bitflags! { impl SpecializedPipeline for ShadowPipeline { type Key = ShadowPipelineKey; - fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let (vertex_array_stride, vertex_attributes) = - if key.contains(ShadowPipelineKey::VERTEX_TANGENTS) { - ( - 48, - vec![ - // Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 12, - shader_location: 0, - }, - // Normal - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 1, - }, - // Uv (GOTCHA! uv is no longer third in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x2, - offset: 40, - shader_location: 2, - }, - // Tangent - VertexAttribute { - format: VertexFormat::Float32x4, - offset: 24, - shader_location: 3, - }, - ], - ) - } else { - ( - 32, - vec![ - // Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 12, - shader_location: 0, - }, - // Normal - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 1, - }, - // Uv - VertexAttribute { - format: VertexFormat::Float32x2, - offset: 24, - shader_location: 2, - }, - ], - ) - }; + fn specialize( + &self, + _key: Self::Key, + vertex_layout: &VertexBufferLayout, + ) -> RenderPipelineDescriptor { RenderPipelineDescriptor { vertex: VertexState { shader: SHADOW_SHADER_HANDLE.typed::(), entry_point: "vertex".into(), shader_defs: vec![], - buffers: vec![VertexBufferLayout { - array_stride: vertex_array_stride, - step_mode: VertexStepMode::Vertex, - attributes: vertex_attributes, - }], + buffers: vec![vertex_layout.clone()], }, fragment: None, layout: Some(vec![self.view_layout.clone(), self.mesh_layout.clone()]), @@ -756,13 +700,16 @@ pub fn queue_shadows( for VisibleEntity { entity, .. } in visible_entities.iter() { let mut key = ShadowPipelineKey::empty(); if let Ok(mesh_handle) = casting_meshes.get(*entity) { - if let Some(mesh) = render_meshes.get(mesh_handle) { - if mesh.has_tangents { - key |= ShadowPipelineKey::VERTEX_TANGENTS; - } + let mesh = render_meshes.get(mesh_handle).unwrap(); + if mesh.has_tangents { + key |= ShadowPipelineKey::VERTEX_TANGENTS; } - let pipeline_id = - pipelines.specialize(&mut pipeline_cache, &shadow_pipeline, key); + let pipeline_id = pipelines.specialize( + &mut pipeline_cache, + &shadow_pipeline, + key, + &mesh.vertex_layout, + ); shadow_phase.add(Shadow { draw_function: draw_shadow_mesh, diff --git a/pipelined/bevy_pbr2/src/render/mesh.rs b/pipelined/bevy_pbr2/src/render/mesh.rs index 8ea39af793b8e5..1db396d0844873 100644 --- a/pipelined/bevy_pbr2/src/render/mesh.rs +++ b/pipelined/bevy_pbr2/src/render/mesh.rs @@ -353,63 +353,11 @@ impl MeshPipelineKey { impl SpecializedPipeline for MeshPipeline { type Key = MeshPipelineKey; - fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let (vertex_array_stride, vertex_attributes) = - if key.contains(MeshPipelineKey::VERTEX_TANGENTS) { - ( - 48, - vec![ - // Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 12, - shader_location: 0, - }, - // Normal - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 1, - }, - // Uv (GOTCHA! uv is no longer third in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x2, - offset: 40, - shader_location: 2, - }, - // Tangent - VertexAttribute { - format: VertexFormat::Float32x4, - offset: 24, - shader_location: 3, - }, - ], - ) - } else { - ( - 32, - vec![ - // Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 12, - shader_location: 0, - }, - // Normal - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 1, - }, - // Uv - VertexAttribute { - format: VertexFormat::Float32x2, - offset: 24, - shader_location: 2, - }, - ], - ) - }; + fn specialize( + &self, + key: Self::Key, + vertex_layout: &VertexBufferLayout, + ) -> RenderPipelineDescriptor { let mut shader_defs = Vec::new(); if key.contains(MeshPipelineKey::VERTEX_TANGENTS) { shader_defs.push(String::from("VERTEX_TANGENTS")); @@ -436,11 +384,7 @@ impl SpecializedPipeline for MeshPipeline { shader: MESH_SHADER_HANDLE.typed::(), entry_point: "vertex".into(), shader_defs: shader_defs.clone(), - buffers: vec![VertexBufferLayout { - array_stride: vertex_array_stride, - step_mode: VertexStepMode::Vertex, - attributes: vertex_attributes, - }], + buffers: vec![vertex_layout.clone()], }, fragment: Some(FragmentState { shader: MESH_SHADER_HANDLE.typed::(), diff --git a/pipelined/bevy_pbr2/src/render/mod.rs b/pipelined/bevy_pbr2/src/render/mod.rs index 348f7db9552803..34467697ffa3f7 100644 --- a/pipelined/bevy_pbr2/src/render/mod.rs +++ b/pipelined/bevy_pbr2/src/render/mod.rs @@ -191,8 +191,12 @@ pub struct PbrPipelineKey { impl SpecializedPipeline for PbrPipeline { type Key = PbrPipelineKey; - fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key); + fn specialize( + &self, + key: Self::Key, + vertex_layout: &VertexBufferLayout, + ) -> RenderPipelineDescriptor { + let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key, vertex_layout); descriptor.fragment.as_mut().unwrap().shader = PBR_SHADER_HANDLE.typed::(); descriptor.layout = Some(vec![ self.mesh_pipeline.view_layout.clone(), @@ -256,18 +260,21 @@ pub fn queue_meshes( mesh_key, normal_map: material.has_normal_map, }; - if let Some(mesh) = render_meshes.get(mesh_handle) { - if mesh.has_tangents { - pbr_key.mesh_key |= MeshPipelineKey::VERTEX_TANGENTS; - } + let mesh = render_meshes.get(mesh_handle).unwrap(); + if mesh.has_tangents { + pbr_key.mesh_key |= MeshPipelineKey::VERTEX_TANGENTS; } if let AlphaMode::Blend = material.alpha_mode { pbr_key.mesh_key |= MeshPipelineKey::TRANSPARENT_MAIN_PASS } - let pipeline_id = - pipelines.specialize(&mut pipeline_cache, &pbr_pipeline, pbr_key); + let pipeline_id = pipelines.specialize( + &mut pipeline_cache, + &pbr_pipeline, + pbr_key, + &mesh.vertex_layout, + ); // NOTE: row 2 of the inverse view matrix dotted with column 3 of the model matrix // gives the z component of translation of the mesh in view space diff --git a/pipelined/bevy_render2/src/mesh/mesh/mod.rs b/pipelined/bevy_render2/src/mesh/mesh/mod.rs index 57614f378e34a8..e9e40e2a91b92a 100644 --- a/pipelined/bevy_render2/src/mesh/mesh/mod.rs +++ b/pipelined/bevy_render2/src/mesh/mesh/mod.rs @@ -3,7 +3,7 @@ mod conversions; use crate::{ primitives::Aabb, render_asset::{PrepareAssetError, RenderAsset}, - render_resource::Buffer, + render_resource::{Buffer, VertexBufferLayout}, renderer::RenderDevice, }; use bevy_core::cast_slice; @@ -29,6 +29,7 @@ pub struct Mesh { /// Uses a BTreeMap because, unlike HashMap, it has a defined iteration order, /// which allows easy stable VertexBuffers (i.e. same buffer order) attributes: BTreeMap, VertexAttributeValues>, + vertex_layout: VertexBufferLayout, indices: Option, } @@ -75,6 +76,7 @@ impl Mesh { Mesh { primitive_topology, attributes: Default::default(), + vertex_layout: Self::default_vertex_layout(), indices: None, } } @@ -86,13 +88,34 @@ impl Mesh { /// Sets the data for a vertex attribute (position, normal etc.). The name will /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`]. + /// + /// # Panics + /// + /// This method panics when the attribute descriptor does not have the given name + /// or has the wrong format. pub fn set_attribute( &mut self, name: impl Into>, values: impl Into, ) { + let name = name.into(); let values: VertexAttributeValues = values.into(); - self.attributes.insert(name.into(), values); + + let vertex_layout = self + .vertex_layout + .attribute_layout(&name) + .unwrap_or_else(|| { + panic!("VertexBufferLayout is missing an attribute named {}", name); + }); + + let vertex_format = VertexFormat::from(&values); + assert_eq!( + vertex_format, vertex_layout.format, + "Attribute {} has a different format than the VertexBufferLayout: {:?} != {:?}", + name, vertex_format, vertex_layout.format + ); + + self.attributes.insert(name, values); } /// Retrieves the data currently set to the vertex attribute with the specified `name`. @@ -108,6 +131,33 @@ impl Mesh { self.attributes.get_mut(&name.into()) } + /// Get a shared reference to the vertex buffer layout. + pub fn vertex_layout(&self) -> &VertexBufferLayout { + &self.vertex_layout + } + + /// Get a unique reference to the vertex buffer layout for updating. + pub fn vertex_layout_mut(&mut self) -> &mut VertexBufferLayout { + &mut self.vertex_layout + } + + /// Replace the existing vertex buffer layout. + pub fn replace_vertex_layout(&mut self, vertex_layout: VertexBufferLayout) { + self.vertex_layout = vertex_layout; + } + + /// Create a default vertex buffer layout matching the simplest PBR shader + /// (without specialization). + pub fn default_vertex_layout() -> VertexBufferLayout { + let mut vertex_layout = VertexBufferLayout::default(); + + vertex_layout.push(Self::ATTRIBUTE_POSITION, VertexFormat::Float32x3); + vertex_layout.push(Self::ATTRIBUTE_NORMAL, VertexFormat::Float32x3); + vertex_layout.push(Self::ATTRIBUTE_UV_0, VertexFormat::Float32x2); + + vertex_layout + } + /// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants /// that use triangles. @@ -134,28 +184,6 @@ impl Mesh { }) } - // pub fn get_vertex_buffer_layout(&self) -> VertexBufferLayout { - // let mut attributes = Vec::new(); - // let mut accumulated_offset = 0; - // for (attribute_name, attribute_values) in self.attributes.iter() { - // let vertex_format = VertexFormat::from(attribute_values); - // attributes.push(VertexAttribute { - // name: attribute_name.clone(), - // offset: accumulated_offset, - // format: vertex_format, - // shader_location: 0, - // }); - // accumulated_offset += vertex_format.get_size(); - // } - - // VertexBufferLayout { - // name: Default::default(), - // stride: accumulated_offset, - // step_mode: InputStepMode::Vertex, - // attributes, - // } - // } - /// Counts all vertices of the mesh. /// /// # Panics @@ -181,17 +209,14 @@ impl Mesh { /// # Panics /// Panics if the attributes have different vertex counts. pub fn get_vertex_buffer_data(&self) -> Vec { - let mut vertex_size = 0; - for attribute_values in self.attributes.values() { - let vertex_format = VertexFormat::from(attribute_values); - vertex_size += vertex_format.get_size() as usize; - } - let vertex_count = self.count_vertices(); + let vertex_size = self.vertex_layout.array_stride as usize; + let mut attributes_interleaved_buffer = vec![0; vertex_count * vertex_size]; // bundle into interleaved buffers - let mut attribute_offset = 0; - for attribute_values in self.attributes.values() { + for (attribute_name, attribute_values) in self.attributes.iter() { + let vbd = self.vertex_layout.attribute_layout(attribute_name).unwrap(); + let attribute_offset = vbd.offset as usize; let vertex_format = VertexFormat::from(attribute_values); let attribute_size = vertex_format.get_size() as usize; let attributes_bytes = attribute_values.get_bytes(); @@ -202,8 +227,6 @@ impl Mesh { attributes_interleaved_buffer[offset..offset + attribute_size] .copy_from_slice(attribute_bytes); } - - attribute_offset += attribute_size; } attributes_interleaved_buffer @@ -591,6 +614,7 @@ impl From<&Indices> for IndexFormat { pub struct GpuMesh { /// Contains all attribute data for each vertex. pub vertex_buffer: Buffer, + pub vertex_layout: VertexBufferLayout, pub index_info: Option, pub has_tangents: bool, } @@ -638,6 +662,7 @@ impl RenderAsset for Mesh { Ok(GpuMesh { vertex_buffer, + vertex_layout: mesh.vertex_layout().clone(), index_info, has_tangents: mesh.attributes.contains_key(Mesh::ATTRIBUTE_TANGENT), }) diff --git a/pipelined/bevy_render2/src/render_resource/pipeline.rs b/pipelined/bevy_render2/src/render_resource/pipeline.rs index f462c98c5352ca..2f067d6bc94973 100644 --- a/pipelined/bevy_render2/src/render_resource/pipeline.rs +++ b/pipelined/bevy_render2/src/render_resource/pipeline.rs @@ -1,10 +1,16 @@ use crate::render_resource::{BindGroupLayout, Shader}; use bevy_asset::Handle; use bevy_reflect::Uuid; -use std::{borrow::Cow, ops::Deref, sync::Arc}; +use bevy_utils::HashMap; +use std::{ + borrow::Cow, + hash::{Hash, Hasher}, + ops::Deref, + sync::Arc, +}; use wgpu::{ BufferAddress, ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState, - VertexAttribute, VertexStepMode, + VertexAttribute, VertexFormat, VertexStepMode, }; /// A [`RenderPipeline`] identifier. @@ -118,14 +124,107 @@ pub struct VertexState { } /// Describes how the vertex buffer is interpreted. -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Default, Eq)] pub struct VertexBufferLayout { /// The stride, in bytes, between elements of this buffer. pub array_stride: BufferAddress, /// How often this vertex buffer is "stepped" forward. pub step_mode: VertexStepMode, /// The list of attributes which comprise a single vertex. - pub attributes: Vec, + attributes: Vec, + /// The list of attributes suitable for `wgpu`. + wgpu_attributes: Vec, + /// Attribute names for debugging and mapping types. + attribute_names: HashMap, +} + +impl Hash for VertexBufferLayout { + fn hash(&self, state: &mut H) { + self.array_stride.hash(state); + self.step_mode.hash(state); + self.attributes.hash(state); + } +} + +impl PartialEq for VertexBufferLayout { + fn eq(&self, other: &Self) -> bool { + self.array_stride == other.array_stride + && self.step_mode == other.step_mode + && self.attributes == other.attributes + } +} + +impl VertexBufferLayout { + /// Push a vertex attribute descriptor to the end of the list. + /// + /// The shader location is determined based on insertion order. + pub fn push(&mut self, name: &str, format: VertexFormat) { + let shader_location = if let Some(attribute) = self.attributes.last() { + attribute.shader_location + 1 + } else { + 0 + }; + + self.push_location(name, format, shader_location) + } + + /// Push a vertex attribute descriptor to the end of the list with an exact shader location. + pub fn push_location(&mut self, name: &str, format: VertexFormat, shader_location: u32) { + let offset = if let Some(attribute) = self.attributes.last() { + attribute.offset + attribute.format.size() + } else { + 0 + }; + + self.array_stride += format.size(); + self.attribute_names + .entry(name.to_string()) + .or_insert_with(|| self.attributes.len()); + self.attributes.push(VertexAttributeLayout { + name: name.to_string(), + format, + offset, + shader_location, + }); + self.wgpu_attributes.push(VertexAttribute { + format, + offset, + shader_location, + }) + } + + /// Get an attribute layout by name. + pub fn attribute_layout(&self, name: &str) -> Option<&VertexAttributeLayout> { + self.attribute_names.get(name).map(|i| &self.attributes[*i]) + } + + /// Get attributes suitable for `wgpu`. + pub fn attributes(&self) -> &[VertexAttribute] { + &self.wgpu_attributes + } +} + +/// Describes a vertex attribute's layout. +#[derive(Clone, Debug, Hash, Eq, PartialEq)] +pub struct VertexAttributeLayout { + /// The attribute's name. + pub name: String, + /// Format of the attribute. + pub format: VertexFormat, + /// Byte offset of this attribute within the array element. + pub offset: u64, + /// Attribute location as referenced by the shader. + pub shader_location: u32, +} + +impl From<&VertexAttributeLayout> for VertexAttribute { + fn from(value: &VertexAttributeLayout) -> Self { + Self { + format: value.format, + offset: value.offset, + shader_location: value.shader_location, + } + } } /// Describes the fragment process in a render pipeline. diff --git a/pipelined/bevy_render2/src/render_resource/pipeline_cache.rs b/pipelined/bevy_render2/src/render_resource/pipeline_cache.rs index 1dff4fe617ec03..02a5b1c67aa674 100644 --- a/pipelined/bevy_render2/src/render_resource/pipeline_cache.rs +++ b/pipelined/bevy_render2/src/render_resource/pipeline_cache.rs @@ -327,7 +327,7 @@ impl RenderPipelineCache { .iter() .map(|layout| VertexBufferLayout { array_stride: layout.array_stride, - attributes: &layout.attributes, + attributes: layout.attributes(), step_mode: layout.step_mode, }) .collect::>(); diff --git a/pipelined/bevy_render2/src/render_resource/pipeline_specializer.rs b/pipelined/bevy_render2/src/render_resource/pipeline_specializer.rs index a5cb472aa48f8b..ab4865748a3108 100644 --- a/pipelined/bevy_render2/src/render_resource/pipeline_specializer.rs +++ b/pipelined/bevy_render2/src/render_resource/pipeline_specializer.rs @@ -1,4 +1,6 @@ -use crate::render_resource::{CachedPipelineId, RenderPipelineCache, RenderPipelineDescriptor}; +use crate::render_resource::{ + CachedPipelineId, RenderPipelineCache, RenderPipelineDescriptor, VertexBufferLayout, +}; use bevy_utils::HashMap; use std::hash::Hash; @@ -20,9 +22,10 @@ impl SpecializedPipelines { cache: &mut RenderPipelineCache, specialize_pipeline: &S, key: S::Key, + vertex_layout: &VertexBufferLayout, ) -> CachedPipelineId { *self.cache.entry(key.clone()).or_insert_with(|| { - let descriptor = specialize_pipeline.specialize(key); + let descriptor = specialize_pipeline.specialize(key, vertex_layout); cache.queue(descriptor) }) } @@ -30,5 +33,9 @@ impl SpecializedPipelines { pub trait SpecializedPipeline { type Key: Clone + Hash + PartialEq + Eq; - fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor; + fn specialize( + &self, + key: Self::Key, + vertex_layout: &VertexBufferLayout, + ) -> RenderPipelineDescriptor; } diff --git a/pipelined/bevy_sprite2/src/render/mod.rs b/pipelined/bevy_sprite2/src/render/mod.rs index 0a0ddc620f0f3d..5df646801bd514 100644 --- a/pipelined/bevy_sprite2/src/render/mod.rs +++ b/pipelined/bevy_sprite2/src/render/mod.rs @@ -29,6 +29,21 @@ use bytemuck::{Pod, Zeroable}; pub struct SpritePipeline { view_layout: BindGroupLayout, material_layout: BindGroupLayout, + vertex_layouts: [VertexBufferLayout; 2], +} + +impl SpritePipeline { + fn create_vertex_layout(colored: bool) -> VertexBufferLayout { + let mut vertex_layout = VertexBufferLayout::default(); + + vertex_layout.push("position", VertexFormat::Float32x3); + vertex_layout.push("uv", VertexFormat::Float32x2); + if colored { + vertex_layout.push("color", VertexFormat::Uint32); + } + + vertex_layout + } } impl FromWorld for SpritePipeline { @@ -77,14 +92,20 @@ impl FromWorld for SpritePipeline { label: Some("sprite_material_layout"), }); + let vertex_layouts = [ + Self::create_vertex_layout(false), + Self::create_vertex_layout(true), + ]; + SpritePipeline { view_layout, material_layout, + vertex_layouts, } } } -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct SpritePipelineKey { colored: bool, } @@ -92,32 +113,14 @@ pub struct SpritePipelineKey { impl SpecializedPipeline for SpritePipeline { type Key = SpritePipelineKey; - fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let mut vertex_buffer_layout = VertexBufferLayout { - array_stride: 20, - step_mode: VertexStepMode::Vertex, - attributes: vec![ - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 0, - }, - VertexAttribute { - format: VertexFormat::Float32x2, - offset: 12, - shader_location: 1, - }, - ], - }; + fn specialize( + &self, + key: Self::Key, + vertex_layout: &VertexBufferLayout, + ) -> RenderPipelineDescriptor { let mut shader_defs = Vec::new(); if key.colored { shader_defs.push("COLORED".to_string()); - vertex_buffer_layout.attributes.push(VertexAttribute { - format: VertexFormat::Uint32, - offset: 20, - shader_location: 2, - }); - vertex_buffer_layout.array_stride += 4; } RenderPipelineDescriptor { @@ -125,7 +128,7 @@ impl SpecializedPipeline for SpritePipeline { shader: SPRITE_SHADER_HANDLE.typed::(), entry_point: "vertex".into(), shader_defs: shader_defs.clone(), - buffers: vec![vertex_buffer_layout], + buffers: vec![vertex_layout.clone()], }, fragment: Some(FragmentState { shader: SPRITE_SHADER_HANDLE.typed::(), @@ -468,12 +471,15 @@ pub fn queue_sprites( &mut pipeline_cache, &sprite_pipeline, SpritePipelineKey { colored: false }, + &sprite_pipeline.vertex_layouts[0], ); let colored_pipeline = pipelines.specialize( &mut pipeline_cache, &sprite_pipeline, SpritePipelineKey { colored: true }, + &sprite_pipeline.vertex_layouts[1], ); + for mut transparent_phase in views.iter_mut() { for (entity, batch) in sprite_batches.iter_mut() { image_bind_groups