Intern mesh vertex buffer layouts so that we don't have to compare them over and over. (#12216)
Although we cached hashes of `MeshVertexBufferLayout`, we were paying the cost of `PartialEq` on `InnerMeshVertexBufferLayout` for every entity, every frame. This patch changes that logic to place `MeshVertexBufferLayout`s in `Arc`s so that they can be compared and hashed by pointer. This results in a 28% speedup in the `queue_material_meshes` phase of `many_cubes`, with frustum culling disabled. Additionally, this patch contains two minor changes: 1. This commit flattens the specialized mesh pipeline cache to one level of hash tables instead of two. This saves a hash lookup. 2. The example `many_cubes` has been given a `--no-frustum-culling` flag, to aid in benchmarking. See the Tracy profile: <img width="1064" alt="Screenshot 2024-02-29 144406" src="https://github.com/bevyengine/bevy/assets/157897/18632f1d-1fdd-4ac7-90ed-2d10306b2a1e"> ## Migration guide * Duplicate `MeshVertexBufferLayout`s are now combined into a single object, `MeshVertexBufferLayoutRef`, which contains an atomically-reference-counted pointer to the layout. Code that was using `MeshVertexBufferLayout` may need to be updated to use `MeshVertexBufferLayoutRef` instead.
This commit is contained in:
parent
fc0aa4f7b1
commit
f9cc91d5a1
@ -1,7 +1,7 @@
|
|||||||
use bevy_asset::{Asset, Handle};
|
use bevy_asset::{Asset, Handle};
|
||||||
use bevy_reflect::{impl_type_path, Reflect};
|
use bevy_reflect::{impl_type_path, Reflect};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
mesh::MeshVertexBufferLayout,
|
mesh::MeshVertexBufferLayoutRef,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AsBindGroup, AsBindGroupError, BindGroupLayout, RenderPipelineDescriptor, Shader,
|
AsBindGroup, AsBindGroupError, BindGroupLayout, RenderPipelineDescriptor, Shader,
|
||||||
@ -68,14 +68,14 @@ pub trait MaterialExtension: Asset + AsBindGroup + Clone + Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Customizes the default [`RenderPipelineDescriptor`] for a specific entity using the entity's
|
/// Customizes the default [`RenderPipelineDescriptor`] for a specific entity using the entity's
|
||||||
/// [`MaterialPipelineKey`] and [`MeshVertexBufferLayout`] as input.
|
/// [`MaterialPipelineKey`] and [`MeshVertexBufferLayoutRef`] as input.
|
||||||
/// Specialization for the base material is applied before this function is called.
|
/// Specialization for the base material is applied before this function is called.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn specialize(
|
fn specialize(
|
||||||
pipeline: &MaterialExtensionPipeline,
|
pipeline: &MaterialExtensionPipeline,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
key: MaterialExtensionKey<Self>,
|
key: MaterialExtensionKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -214,7 +214,7 @@ impl<B: Material, E: MaterialExtension> Material for ExtendedMaterial<B, E> {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
pipeline: &MaterialPipeline<Self>,
|
pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
key: MaterialPipelineKey<Self>,
|
key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
// Call the base material's specialize function
|
// Call the base material's specialize function
|
||||||
|
@ -159,7 +159,7 @@ fn extract_lightmaps(
|
|||||||
|| !render_mesh_instances
|
|| !render_mesh_instances
|
||||||
.get(&entity)
|
.get(&entity)
|
||||||
.and_then(|mesh_instance| meshes.get(mesh_instance.mesh_asset_id))
|
.and_then(|mesh_instance| meshes.get(mesh_instance.mesh_asset_id))
|
||||||
.is_some_and(|mesh| mesh.layout.contains(Mesh::ATTRIBUTE_UV_1.id))
|
.is_some_and(|mesh| mesh.layout.0.contains(Mesh::ATTRIBUTE_UV_1.id))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ use bevy_render::{
|
|||||||
camera::TemporalJitter,
|
camera::TemporalJitter,
|
||||||
extract_instances::{ExtractInstancesPlugin, ExtractedInstances},
|
extract_instances::{ExtractInstancesPlugin, ExtractedInstances},
|
||||||
extract_resource::ExtractResource,
|
extract_resource::ExtractResource,
|
||||||
mesh::{Mesh, MeshVertexBufferLayout},
|
mesh::{Mesh, MeshVertexBufferLayoutRef},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::*,
|
render_phase::*,
|
||||||
render_resource::*,
|
render_resource::*,
|
||||||
@ -171,13 +171,13 @@ pub trait Material: Asset + AsBindGroup + Clone + Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Customizes the default [`RenderPipelineDescriptor`] for a specific entity using the entity's
|
/// Customizes the default [`RenderPipelineDescriptor`] for a specific entity using the entity's
|
||||||
/// [`MaterialPipelineKey`] and [`MeshVertexBufferLayout`] as input.
|
/// [`MaterialPipelineKey`] and [`MeshVertexBufferLayoutRef`] as input.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn specialize(
|
fn specialize(
|
||||||
pipeline: &MaterialPipeline<Self>,
|
pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
key: MaterialPipelineKey<Self>,
|
key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -326,7 +326,7 @@ where
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
&self,
|
&self,
|
||||||
key: Self::Key,
|
key: Self::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key, layout)?;
|
let mut descriptor = self.mesh_pipeline.specialize(key.mesh_key, layout)?;
|
||||||
if let Some(vertex_shader) = &self.vertex_shader {
|
if let Some(vertex_shader) = &self.vertex_shader {
|
||||||
@ -585,6 +585,7 @@ pub fn queue_material_meshes<M: Material>(
|
|||||||
camera_3d.screen_space_specular_transmission_quality,
|
camera_3d.screen_space_specular_transmission_quality,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rangefinder = view.rangefinder3d();
|
let rangefinder = view.rangefinder3d();
|
||||||
for visible_entity in &visible_entities.entities {
|
for visible_entity in &visible_entities.entities {
|
||||||
let Some(material_asset_id) = render_material_instances.get(visible_entity) else {
|
let Some(material_asset_id) = render_material_instances.get(visible_entity) else {
|
||||||
|
@ -2,7 +2,9 @@ use bevy_asset::Asset;
|
|||||||
use bevy_color::Alpha;
|
use bevy_color::Alpha;
|
||||||
use bevy_math::{Affine2, Mat3, Vec4};
|
use bevy_math::{Affine2, Mat3, Vec4};
|
||||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||||
use bevy_render::{mesh::MeshVertexBufferLayout, render_asset::RenderAssets, render_resource::*};
|
use bevy_render::{
|
||||||
|
mesh::MeshVertexBufferLayoutRef, render_asset::RenderAssets, render_resource::*,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID;
|
use crate::deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
@ -813,7 +815,7 @@ impl Material for StandardMaterial {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
_pipeline: &MaterialPipeline<Self>,
|
_pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
_layout: &MeshVertexBufferLayout,
|
_layout: &MeshVertexBufferLayoutRef,
|
||||||
key: MaterialPipelineKey<Self>,
|
key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
if let Some(fragment) = descriptor.fragment.as_mut() {
|
if let Some(fragment) = descriptor.fragment.as_mut() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
mod prepass_bindings;
|
mod prepass_bindings;
|
||||||
|
|
||||||
|
use bevy_render::mesh::MeshVertexBufferLayoutRef;
|
||||||
use bevy_render::render_resource::binding_types::uniform_buffer;
|
use bevy_render::render_resource::binding_types::uniform_buffer;
|
||||||
pub use prepass_bindings::*;
|
pub use prepass_bindings::*;
|
||||||
|
|
||||||
@ -17,7 +18,6 @@ use bevy_math::{Affine3A, Mat4};
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
batching::batch_and_prepare_render_phase,
|
batching::batch_and_prepare_render_phase,
|
||||||
globals::{GlobalsBuffer, GlobalsUniform},
|
globals::{GlobalsBuffer, GlobalsUniform},
|
||||||
mesh::MeshVertexBufferLayout,
|
|
||||||
prelude::{Camera, Mesh},
|
prelude::{Camera, Mesh},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::*,
|
render_phase::*,
|
||||||
@ -302,7 +302,7 @@ where
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
&self,
|
&self,
|
||||||
key: Self::Key,
|
key: Self::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut bind_group_layouts = vec![if key
|
let mut bind_group_layouts = vec![if key
|
||||||
.mesh_key
|
.mesh_key
|
||||||
@ -347,7 +347,7 @@ where
|
|||||||
shader_defs.push("BLEND_ALPHA".into());
|
shader_defs.push("BLEND_ALPHA".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_POSITION) {
|
if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
|
||||||
shader_defs.push("VERTEX_POSITIONS".into());
|
shader_defs.push("VERTEX_POSITIONS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
||||||
}
|
}
|
||||||
@ -363,12 +363,12 @@ where
|
|||||||
shader_defs.push("PREPASS_FRAGMENT".into());
|
shader_defs.push("PREPASS_FRAGMENT".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_UV_0) {
|
if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
|
||||||
shader_defs.push("VERTEX_UVS".into());
|
shader_defs.push("VERTEX_UVS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(1));
|
vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_UV_1) {
|
if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
|
||||||
shader_defs.push("VERTEX_UVS_B".into());
|
shader_defs.push("VERTEX_UVS_B".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(2));
|
vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(2));
|
||||||
}
|
}
|
||||||
@ -383,7 +383,7 @@ where
|
|||||||
{
|
{
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(3));
|
vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(3));
|
||||||
shader_defs.push("NORMAL_PREPASS_OR_DEFERRED_PREPASS".into());
|
shader_defs.push("NORMAL_PREPASS_OR_DEFERRED_PREPASS".into());
|
||||||
if layout.contains(Mesh::ATTRIBUTE_TANGENT) {
|
if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
|
||||||
shader_defs.push("VERTEX_TANGENTS".into());
|
shader_defs.push("VERTEX_TANGENTS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
|
vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
|
||||||
}
|
}
|
||||||
@ -400,7 +400,7 @@ where
|
|||||||
shader_defs.push("DEFERRED_PREPASS".into());
|
shader_defs.push("DEFERRED_PREPASS".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_COLOR) {
|
if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
|
||||||
shader_defs.push("VERTEX_COLORS".into());
|
shader_defs.push("VERTEX_COLORS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(7));
|
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(7));
|
||||||
}
|
}
|
||||||
@ -430,7 +430,7 @@ where
|
|||||||
);
|
);
|
||||||
bind_group_layouts.insert(1, bind_group);
|
bind_group_layouts.insert(1, bind_group);
|
||||||
|
|
||||||
let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;
|
let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
|
||||||
|
|
||||||
// Setup prepass fragment targets - normals in slot 0 (or None if not needed), motion vectors in slot 1
|
// Setup prepass fragment targets - normals in slot 0 (or None if not needed), motion vectors in slot 1
|
||||||
let mut targets = vec![
|
let mut targets = vec![
|
||||||
|
@ -26,7 +26,7 @@ use bevy_render::{
|
|||||||
Extract,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::{tracing::error, Entry, HashMap, Hashed, Parallel};
|
use bevy_utils::{tracing::error, Entry, HashMap, Parallel};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use bevy_utils::warn_once;
|
use bevy_utils::warn_once;
|
||||||
@ -595,12 +595,13 @@ impl MeshPipelineKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_skinned(layout: &Hashed<InnerMeshVertexBufferLayout>) -> bool {
|
fn is_skinned(layout: &MeshVertexBufferLayoutRef) -> bool {
|
||||||
layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX) && layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
|
layout.0.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
|
||||||
|
&& layout.0.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
|
||||||
}
|
}
|
||||||
pub fn setup_morph_and_skinning_defs(
|
pub fn setup_morph_and_skinning_defs(
|
||||||
mesh_layouts: &MeshLayouts,
|
mesh_layouts: &MeshLayouts,
|
||||||
layout: &Hashed<InnerMeshVertexBufferLayout>,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
key: &MeshPipelineKey,
|
key: &MeshPipelineKey,
|
||||||
shader_defs: &mut Vec<ShaderDefVal>,
|
shader_defs: &mut Vec<ShaderDefVal>,
|
||||||
@ -638,7 +639,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
&self,
|
&self,
|
||||||
key: Self::Key,
|
key: Self::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut shader_defs = Vec::new();
|
let mut shader_defs = Vec::new();
|
||||||
let mut vertex_attributes = Vec::new();
|
let mut vertex_attributes = Vec::new();
|
||||||
@ -648,32 +649,32 @@ impl SpecializedMeshPipeline for MeshPipeline {
|
|||||||
|
|
||||||
shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
|
shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into());
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_POSITION) {
|
if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
|
||||||
shader_defs.push("VERTEX_POSITIONS".into());
|
shader_defs.push("VERTEX_POSITIONS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_NORMAL) {
|
if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
|
||||||
shader_defs.push("VERTEX_NORMALS".into());
|
shader_defs.push("VERTEX_NORMALS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
|
vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_UV_0) {
|
if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
|
||||||
shader_defs.push("VERTEX_UVS".into());
|
shader_defs.push("VERTEX_UVS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
|
vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_UV_1) {
|
if layout.0.contains(Mesh::ATTRIBUTE_UV_1) {
|
||||||
shader_defs.push("VERTEX_UVS_B".into());
|
shader_defs.push("VERTEX_UVS_B".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(3));
|
vertex_attributes.push(Mesh::ATTRIBUTE_UV_1.at_shader_location(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_TANGENT) {
|
if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
|
||||||
shader_defs.push("VERTEX_TANGENTS".into());
|
shader_defs.push("VERTEX_TANGENTS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
|
vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_COLOR) {
|
if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
|
||||||
shader_defs.push("VERTEX_COLORS".into());
|
shader_defs.push("VERTEX_COLORS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5));
|
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5));
|
||||||
}
|
}
|
||||||
@ -701,7 +702,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
|
|||||||
shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into());
|
shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;
|
let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
|
||||||
|
|
||||||
let (label, blend, depth_write_enabled);
|
let (label, blend, depth_write_enabled);
|
||||||
let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
|
let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
|
||||||
|
@ -5,7 +5,8 @@ use bevy_color::{Color, LinearRgba};
|
|||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
extract_resource::ExtractResource, mesh::MeshVertexBufferLayout, prelude::*, render_resource::*,
|
extract_resource::ExtractResource, mesh::MeshVertexBufferLayoutRef, prelude::*,
|
||||||
|
render_resource::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const WIREFRAME_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(192598014480025766);
|
pub const WIREFRAME_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(192598014480025766);
|
||||||
@ -208,7 +209,7 @@ impl Material for WireframeMaterial {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
_pipeline: &MaterialPipeline<Self>,
|
_pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
_layout: &MeshVertexBufferLayout,
|
_layout: &MeshVertexBufferLayoutRef,
|
||||||
_key: MaterialPipelineKey<Self>,
|
_key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
descriptor.primitive.polygon_mode = PolygonMode::Line;
|
descriptor.primitive.polygon_mode = PolygonMode::Line;
|
||||||
|
@ -13,11 +13,14 @@ use crate::{
|
|||||||
use bevy_asset::{Asset, Handle};
|
use bevy_asset::{Asset, Handle};
|
||||||
use bevy_core::cast_slice;
|
use bevy_core::cast_slice;
|
||||||
use bevy_derive::EnumVariantMeta;
|
use bevy_derive::EnumVariantMeta;
|
||||||
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
|
use bevy_ecs::system::{
|
||||||
|
lifetimeless::{SRes, SResMut},
|
||||||
|
SystemParamItem,
|
||||||
|
};
|
||||||
use bevy_log::warn;
|
use bevy_log::warn;
|
||||||
use bevy_math::*;
|
use bevy_math::*;
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_utils::{tracing::error, Hashed};
|
use bevy_utils::tracing::error;
|
||||||
use std::{collections::BTreeMap, hash::Hash, iter::FusedIterator};
|
use std::{collections::BTreeMap, hash::Hash, iter::FusedIterator};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
@ -25,6 +28,8 @@ use wgpu::{
|
|||||||
VertexStepMode,
|
VertexStepMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::{MeshVertexBufferLayoutRef, MeshVertexBufferLayouts};
|
||||||
|
|
||||||
pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
|
pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
|
||||||
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
|
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
|
||||||
|
|
||||||
@ -377,7 +382,10 @@ impl Mesh {
|
|||||||
/// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in [`SpecializedMeshPipeline`].
|
/// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in [`SpecializedMeshPipeline`].
|
||||||
///
|
///
|
||||||
/// [`SpecializedMeshPipeline`]: crate::render_resource::SpecializedMeshPipeline
|
/// [`SpecializedMeshPipeline`]: crate::render_resource::SpecializedMeshPipeline
|
||||||
pub fn get_mesh_vertex_buffer_layout(&self) -> MeshVertexBufferLayout {
|
pub fn get_mesh_vertex_buffer_layout(
|
||||||
|
&self,
|
||||||
|
mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
|
||||||
|
) -> MeshVertexBufferLayoutRef {
|
||||||
let mut attributes = Vec::with_capacity(self.attributes.len());
|
let mut attributes = Vec::with_capacity(self.attributes.len());
|
||||||
let mut attribute_ids = Vec::with_capacity(self.attributes.len());
|
let mut attribute_ids = Vec::with_capacity(self.attributes.len());
|
||||||
let mut accumulated_offset = 0;
|
let mut accumulated_offset = 0;
|
||||||
@ -391,14 +399,15 @@ impl Mesh {
|
|||||||
accumulated_offset += data.attribute.format.get_size();
|
accumulated_offset += data.attribute.format.get_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshVertexBufferLayout::new(InnerMeshVertexBufferLayout {
|
let layout = MeshVertexBufferLayout {
|
||||||
layout: VertexBufferLayout {
|
layout: VertexBufferLayout {
|
||||||
array_stride: accumulated_offset,
|
array_stride: accumulated_offset,
|
||||||
step_mode: VertexStepMode::Vertex,
|
step_mode: VertexStepMode::Vertex,
|
||||||
attributes,
|
attributes,
|
||||||
},
|
},
|
||||||
attribute_ids,
|
attribute_ids,
|
||||||
})
|
};
|
||||||
|
mesh_vertex_buffer_layouts.insert(layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Counts all vertices of the mesh.
|
/// Counts all vertices of the mesh.
|
||||||
@ -967,15 +976,13 @@ impl From<MeshVertexAttribute> for MeshVertexAttributeId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type MeshVertexBufferLayout = Hashed<InnerMeshVertexBufferLayout>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct InnerMeshVertexBufferLayout {
|
pub struct MeshVertexBufferLayout {
|
||||||
attribute_ids: Vec<MeshVertexAttributeId>,
|
attribute_ids: Vec<MeshVertexAttributeId>,
|
||||||
layout: VertexBufferLayout,
|
layout: VertexBufferLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerMeshVertexBufferLayout {
|
impl MeshVertexBufferLayout {
|
||||||
pub fn new(attribute_ids: Vec<MeshVertexAttributeId>, layout: VertexBufferLayout) -> Self {
|
pub fn new(attribute_ids: Vec<MeshVertexAttributeId>, layout: VertexBufferLayout) -> Self {
|
||||||
Self {
|
Self {
|
||||||
attribute_ids,
|
attribute_ids,
|
||||||
@ -1350,7 +1357,7 @@ pub struct GpuMesh {
|
|||||||
pub morph_targets: Option<TextureView>,
|
pub morph_targets: Option<TextureView>,
|
||||||
pub buffer_info: GpuBufferInfo,
|
pub buffer_info: GpuBufferInfo,
|
||||||
pub primitive_topology: PrimitiveTopology,
|
pub primitive_topology: PrimitiveTopology,
|
||||||
pub layout: MeshVertexBufferLayout,
|
pub layout: MeshVertexBufferLayoutRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The index/vertex buffer info of a [`GpuMesh`].
|
/// The index/vertex buffer info of a [`GpuMesh`].
|
||||||
@ -1367,7 +1374,11 @@ pub enum GpuBufferInfo {
|
|||||||
|
|
||||||
impl RenderAsset for Mesh {
|
impl RenderAsset for Mesh {
|
||||||
type PreparedAsset = GpuMesh;
|
type PreparedAsset = GpuMesh;
|
||||||
type Param = (SRes<RenderDevice>, SRes<RenderAssets<Image>>);
|
type Param = (
|
||||||
|
SRes<RenderDevice>,
|
||||||
|
SRes<RenderAssets<Image>>,
|
||||||
|
SResMut<MeshVertexBufferLayouts>,
|
||||||
|
);
|
||||||
|
|
||||||
fn asset_usage(&self) -> RenderAssetUsages {
|
fn asset_usage(&self) -> RenderAssetUsages {
|
||||||
self.asset_usage
|
self.asset_usage
|
||||||
@ -1376,7 +1387,9 @@ impl RenderAsset for Mesh {
|
|||||||
/// Converts the extracted mesh a into [`GpuMesh`].
|
/// Converts the extracted mesh a into [`GpuMesh`].
|
||||||
fn prepare_asset(
|
fn prepare_asset(
|
||||||
self,
|
self,
|
||||||
(render_device, images): &mut SystemParamItem<Self::Param>,
|
(render_device, images, ref mut mesh_vertex_buffer_layouts): &mut SystemParamItem<
|
||||||
|
Self::Param,
|
||||||
|
>,
|
||||||
) -> Result<Self::PreparedAsset, PrepareAssetError<Self>> {
|
) -> Result<Self::PreparedAsset, PrepareAssetError<Self>> {
|
||||||
let vertex_buffer_data = self.get_vertex_buffer_data();
|
let vertex_buffer_data = self.get_vertex_buffer_data();
|
||||||
let vertex_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
let vertex_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
||||||
@ -1399,7 +1412,8 @@ impl RenderAsset for Mesh {
|
|||||||
GpuBufferInfo::NonIndexed
|
GpuBufferInfo::NonIndexed
|
||||||
};
|
};
|
||||||
|
|
||||||
let mesh_vertex_buffer_layout = self.get_mesh_vertex_buffer_layout();
|
let mesh_vertex_buffer_layout =
|
||||||
|
self.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);
|
||||||
|
|
||||||
Ok(GpuMesh {
|
Ok(GpuMesh {
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
|
@ -3,13 +3,18 @@ mod mesh;
|
|||||||
pub mod morph;
|
pub mod morph;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
|
|
||||||
|
use bevy_utils::HashSet;
|
||||||
pub use mesh::*;
|
pub use mesh::*;
|
||||||
pub use primitives::*;
|
pub use primitives::*;
|
||||||
|
use std::{
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{prelude::Image, render_asset::RenderAssetPlugin};
|
use crate::{prelude::Image, render_asset::RenderAssetPlugin, RenderApp};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{AssetApp, Handle};
|
use bevy_asset::{AssetApp, Handle};
|
||||||
use bevy_ecs::entity::Entity;
|
use bevy_ecs::{entity::Entity, system::Resource};
|
||||||
|
|
||||||
/// Adds the [`Mesh`] as an asset and makes sure that they are extracted and prepared for the GPU.
|
/// Adds the [`Mesh`] as an asset and makes sure that they are extracted and prepared for the GPU.
|
||||||
pub struct MeshPlugin;
|
pub struct MeshPlugin;
|
||||||
@ -27,5 +32,58 @@ impl Plugin for MeshPlugin {
|
|||||||
.register_type::<Vec<Entity>>()
|
.register_type::<Vec<Entity>>()
|
||||||
// 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready
|
// 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready
|
||||||
.add_plugins(RenderAssetPlugin::<Mesh, Image>::default());
|
.add_plugins(RenderAssetPlugin::<Mesh, Image>::default());
|
||||||
|
|
||||||
|
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
render_app.init_resource::<MeshVertexBufferLayouts>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Describes the layout of the mesh vertices in GPU memory.
|
||||||
|
///
|
||||||
|
/// At most one copy of a mesh vertex buffer layout ever exists in GPU memory at
|
||||||
|
/// once. Therefore, comparing these for equality requires only a single pointer
|
||||||
|
/// comparison, and this type's [`PartialEq`] and [`Hash`] implementations take
|
||||||
|
/// advantage of this. To that end, this type doesn't implement
|
||||||
|
/// [`bevy_derive::Deref`] or [`bevy_derive::DerefMut`] in order to reduce the
|
||||||
|
/// possibility of accidental deep comparisons, which would be needlessly
|
||||||
|
/// expensive.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MeshVertexBufferLayoutRef(pub Arc<MeshVertexBufferLayout>);
|
||||||
|
|
||||||
|
/// Stores the single copy of each mesh vertex buffer layout.
|
||||||
|
#[derive(Clone, Default, Resource)]
|
||||||
|
pub struct MeshVertexBufferLayouts(HashSet<Arc<MeshVertexBufferLayout>>);
|
||||||
|
|
||||||
|
impl MeshVertexBufferLayouts {
|
||||||
|
/// Inserts a new mesh vertex buffer layout in the store and returns a
|
||||||
|
/// reference to it, reusing the existing reference if this mesh vertex
|
||||||
|
/// buffer layout was already in the store.
|
||||||
|
pub(crate) fn insert(&mut self, layout: MeshVertexBufferLayout) -> MeshVertexBufferLayoutRef {
|
||||||
|
// Because the special `PartialEq` and `Hash` implementations that
|
||||||
|
// compare by pointer are on `MeshVertexBufferLayoutRef`, not on
|
||||||
|
// `Arc<MeshVertexBufferLayout>`, this compares the mesh vertex buffer
|
||||||
|
// structurally, not by pointer.
|
||||||
|
MeshVertexBufferLayoutRef(
|
||||||
|
self.0
|
||||||
|
.get_or_insert_with(&layout, |layout| Arc::new(layout.clone()))
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for MeshVertexBufferLayoutRef {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
Arc::ptr_eq(&self.0, &other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for MeshVertexBufferLayoutRef {}
|
||||||
|
|
||||||
|
impl Hash for MeshVertexBufferLayoutRef {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
(&*self.0 as *const MeshVertexBufferLayout as usize).hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
|
use crate::mesh::MeshVertexBufferLayoutRef;
|
||||||
use crate::render_resource::CachedComputePipelineId;
|
use crate::render_resource::CachedComputePipelineId;
|
||||||
use crate::{
|
use crate::{
|
||||||
mesh::{InnerMeshVertexBufferLayout, MeshVertexBufferLayout, MissingVertexAttributeError},
|
mesh::MissingVertexAttributeError,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
CachedRenderPipelineId, ComputePipelineDescriptor, PipelineCache, RenderPipelineDescriptor,
|
CachedRenderPipelineId, ComputePipelineDescriptor, PipelineCache, RenderPipelineDescriptor,
|
||||||
VertexBufferLayout,
|
VertexBufferLayout,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bevy_ecs::system::Resource;
|
use bevy_ecs::system::Resource;
|
||||||
use bevy_utils::{
|
use bevy_utils::{default, hashbrown::hash_map::RawEntryMut, tracing::error, Entry, HashMap};
|
||||||
default, hashbrown::hash_map::RawEntryMut, tracing::error, Entry, HashMap, PreHashMap,
|
|
||||||
PreHashMapExt,
|
|
||||||
};
|
|
||||||
use std::{fmt::Debug, hash::Hash};
|
use std::{fmt::Debug, hash::Hash};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -79,14 +77,13 @@ pub trait SpecializedMeshPipeline {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
&self,
|
&self,
|
||||||
key: Self::Key,
|
key: Self::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError>;
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct SpecializedMeshPipelines<S: SpecializedMeshPipeline> {
|
pub struct SpecializedMeshPipelines<S: SpecializedMeshPipeline> {
|
||||||
mesh_layout_cache:
|
mesh_layout_cache: HashMap<(MeshVertexBufferLayoutRef, S::Key), CachedRenderPipelineId>,
|
||||||
PreHashMap<InnerMeshVertexBufferLayout, HashMap<S::Key, CachedRenderPipelineId>>,
|
|
||||||
vertex_layout_cache: HashMap<VertexBufferLayout, HashMap<S::Key, CachedRenderPipelineId>>,
|
vertex_layout_cache: HashMap<VertexBufferLayout, HashMap<S::Key, CachedRenderPipelineId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,12 +103,9 @@ impl<S: SpecializedMeshPipeline> SpecializedMeshPipelines<S> {
|
|||||||
cache: &PipelineCache,
|
cache: &PipelineCache,
|
||||||
specialize_pipeline: &S,
|
specialize_pipeline: &S,
|
||||||
key: S::Key,
|
key: S::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<CachedRenderPipelineId, SpecializedMeshPipelineError> {
|
) -> Result<CachedRenderPipelineId, SpecializedMeshPipelineError> {
|
||||||
let map = self
|
match self.mesh_layout_cache.entry((layout.clone(), key.clone())) {
|
||||||
.mesh_layout_cache
|
|
||||||
.get_or_insert_with(layout, Default::default);
|
|
||||||
match map.entry(key.clone()) {
|
|
||||||
Entry::Occupied(entry) => Ok(*entry.into_mut()),
|
Entry::Occupied(entry) => Ok(*entry.into_mut()),
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
let descriptor = specialize_pipeline
|
let descriptor = specialize_pipeline
|
||||||
|
@ -12,7 +12,7 @@ use bevy_ecs::{
|
|||||||
};
|
};
|
||||||
use bevy_log::error;
|
use bevy_log::error;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
mesh::{Mesh, MeshVertexBufferLayout},
|
mesh::{Mesh, MeshVertexBufferLayoutRef},
|
||||||
prelude::Image,
|
prelude::Image,
|
||||||
render_asset::{prepare_assets, RenderAssets},
|
render_asset::{prepare_assets, RenderAssets},
|
||||||
render_phase::{
|
render_phase::{
|
||||||
@ -125,7 +125,7 @@ pub trait Material2d: AsBindGroup + Asset + Clone + Sized {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn specialize(
|
fn specialize(
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
key: Material2dKey<Self>,
|
key: Material2dKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -271,7 +271,7 @@ where
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
&self,
|
&self,
|
||||||
key: Self::Key,
|
key: Self::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut descriptor = self.mesh2d_pipeline.specialize(key.mesh_key, layout)?;
|
let mut descriptor = self.mesh2d_pipeline.specialize(key.mesh_key, layout)?;
|
||||||
if let Some(vertex_shader) = &self.vertex_shader {
|
if let Some(vertex_shader) = &self.vertex_shader {
|
||||||
|
@ -11,13 +11,14 @@ use bevy_ecs::{
|
|||||||
};
|
};
|
||||||
use bevy_math::{Affine3, Vec4};
|
use bevy_math::{Affine3, Vec4};
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
|
use bevy_render::mesh::MeshVertexBufferLayoutRef;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
batching::{
|
batching::{
|
||||||
batch_and_prepare_render_phase, write_batched_instance_buffer, GetBatchData,
|
batch_and_prepare_render_phase, write_batched_instance_buffer, GetBatchData,
|
||||||
NoAutomaticBatching,
|
NoAutomaticBatching,
|
||||||
},
|
},
|
||||||
globals::{GlobalsBuffer, GlobalsUniform},
|
globals::{GlobalsBuffer, GlobalsUniform},
|
||||||
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
|
mesh::{GpuBufferInfo, Mesh},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||||
render_resource::{binding_types::uniform_buffer, *},
|
render_resource::{binding_types::uniform_buffer, *},
|
||||||
@ -436,32 +437,32 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
&self,
|
&self,
|
||||||
key: Self::Key,
|
key: Self::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut shader_defs = Vec::new();
|
let mut shader_defs = Vec::new();
|
||||||
let mut vertex_attributes = Vec::new();
|
let mut vertex_attributes = Vec::new();
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_POSITION) {
|
if layout.0.contains(Mesh::ATTRIBUTE_POSITION) {
|
||||||
shader_defs.push("VERTEX_POSITIONS".into());
|
shader_defs.push("VERTEX_POSITIONS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_NORMAL) {
|
if layout.0.contains(Mesh::ATTRIBUTE_NORMAL) {
|
||||||
shader_defs.push("VERTEX_NORMALS".into());
|
shader_defs.push("VERTEX_NORMALS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
|
vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_UV_0) {
|
if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
|
||||||
shader_defs.push("VERTEX_UVS".into());
|
shader_defs.push("VERTEX_UVS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
|
vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_TANGENT) {
|
if layout.0.contains(Mesh::ATTRIBUTE_TANGENT) {
|
||||||
shader_defs.push("VERTEX_TANGENTS".into());
|
shader_defs.push("VERTEX_TANGENTS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(3));
|
vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.contains(Mesh::ATTRIBUTE_COLOR) {
|
if layout.0.contains(Mesh::ATTRIBUTE_COLOR) {
|
||||||
shader_defs.push("VERTEX_COLORS".into());
|
shader_defs.push("VERTEX_COLORS".into());
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(4));
|
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(4));
|
||||||
}
|
}
|
||||||
@ -504,7 +505,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;
|
let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
|
||||||
|
|
||||||
let format = match key.contains(Mesh2dPipelineKey::HDR) {
|
let format = match key.contains(Mesh2dPipelineKey::HDR) {
|
||||||
true => ViewTarget::TEXTURE_FORMAT_HDR,
|
true => ViewTarget::TEXTURE_FORMAT_HDR,
|
||||||
|
@ -5,7 +5,7 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
render::{
|
render::{
|
||||||
mesh::{MeshVertexAttribute, MeshVertexBufferLayout},
|
mesh::{MeshVertexAttribute, MeshVertexBufferLayoutRef},
|
||||||
render_resource::*,
|
render_resource::*,
|
||||||
},
|
},
|
||||||
sprite::{Material2d, Material2dKey, Material2dPlugin, MaterialMesh2dBundle, Mesh2dHandle},
|
sprite::{Material2d, Material2dKey, Material2dPlugin, MaterialMesh2dBundle, Mesh2dHandle},
|
||||||
@ -70,10 +70,10 @@ impl Material2d for CustomMaterial {
|
|||||||
|
|
||||||
fn specialize(
|
fn specialize(
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
_key: Material2dKey<Self>,
|
_key: Material2dKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
let vertex_layout = layout.get_layout(&[
|
let vertex_layout = layout.0.get_layout(&[
|
||||||
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
|
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
|
||||||
Mesh::ATTRIBUTE_COLOR.at_shader_location(1),
|
Mesh::ATTRIBUTE_COLOR.at_shader_location(1),
|
||||||
ATTRIBUTE_BARYCENTRIC.at_shader_location(2),
|
ATTRIBUTE_BARYCENTRIC.at_shader_location(2),
|
||||||
|
@ -5,7 +5,7 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
render::{
|
render::{
|
||||||
mesh::{MeshVertexBufferLayout, PrimitiveTopology},
|
mesh::{MeshVertexBufferLayoutRef, PrimitiveTopology},
|
||||||
render_asset::RenderAssetUsages,
|
render_asset::RenderAssetUsages,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AsBindGroup, PolygonMode, RenderPipelineDescriptor, ShaderRef,
|
AsBindGroup, PolygonMode, RenderPipelineDescriptor, ShaderRef,
|
||||||
@ -78,7 +78,7 @@ impl Material for LineMaterial {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
_pipeline: &MaterialPipeline<Self>,
|
_pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
_layout: &MeshVertexBufferLayout,
|
_layout: &MeshVertexBufferLayoutRef,
|
||||||
_key: MaterialPipelineKey<Self>,
|
_key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
// This is the important part to tell bevy to render this material as a line between vertices
|
// This is the important part to tell bevy to render this material as a line between vertices
|
||||||
|
@ -5,7 +5,7 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
render::{
|
render::{
|
||||||
mesh::{MeshVertexAttribute, MeshVertexBufferLayout},
|
mesh::{MeshVertexAttribute, MeshVertexBufferLayoutRef},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError,
|
AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError,
|
||||||
VertexFormat,
|
VertexFormat,
|
||||||
@ -74,10 +74,10 @@ impl Material for CustomMaterial {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
_pipeline: &MaterialPipeline<Self>,
|
_pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
_key: MaterialPipelineKey<Self>,
|
_key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
let vertex_layout = layout.get_layout(&[
|
let vertex_layout = layout.0.get_layout(&[
|
||||||
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
|
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
|
||||||
ATTRIBUTE_BLEND_COLOR.at_shader_location(1),
|
ATTRIBUTE_BLEND_COLOR.at_shader_location(1),
|
||||||
])?;
|
])?;
|
||||||
|
@ -5,7 +5,7 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
render::{
|
render::{
|
||||||
mesh::MeshVertexBufferLayout,
|
mesh::MeshVertexBufferLayoutRef,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError,
|
AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError,
|
||||||
},
|
},
|
||||||
@ -62,7 +62,7 @@ impl Material for CustomMaterial {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
_pipeline: &MaterialPipeline<Self>,
|
_pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
_layout: &MeshVertexBufferLayout,
|
_layout: &MeshVertexBufferLayoutRef,
|
||||||
key: MaterialPipelineKey<Self>,
|
key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
if key.bind_group_data.is_red {
|
if key.bind_group_data.is_red {
|
||||||
|
@ -12,7 +12,7 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
||||||
mesh::{GpuBufferInfo, MeshVertexBufferLayout},
|
mesh::{GpuBufferInfo, MeshVertexBufferLayoutRef},
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::{
|
render_phase::{
|
||||||
AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
|
AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
|
||||||
@ -197,7 +197,7 @@ impl SpecializedMeshPipeline for CustomPipeline {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
&self,
|
&self,
|
||||||
key: Self::Key,
|
key: Self::Key,
|
||||||
layout: &MeshVertexBufferLayout,
|
layout: &MeshVertexBufferLayoutRef,
|
||||||
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||||
let mut descriptor = self.mesh_pipeline.specialize(key, layout)?;
|
let mut descriptor = self.mesh_pipeline.specialize(key, layout)?;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
render::{
|
render::{
|
||||||
mesh::MeshVertexBufferLayout,
|
mesh::MeshVertexBufferLayoutRef,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError,
|
AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError,
|
||||||
},
|
},
|
||||||
@ -78,7 +78,7 @@ impl Material for CustomMaterial {
|
|||||||
fn specialize(
|
fn specialize(
|
||||||
_pipeline: &MaterialPipeline<Self>,
|
_pipeline: &MaterialPipeline<Self>,
|
||||||
descriptor: &mut RenderPipelineDescriptor,
|
descriptor: &mut RenderPipelineDescriptor,
|
||||||
_layout: &MeshVertexBufferLayout,
|
_layout: &MeshVertexBufferLayoutRef,
|
||||||
_key: MaterialPipelineKey<Self>,
|
_key: MaterialPipelineKey<Self>,
|
||||||
) -> Result<(), SpecializedMeshPipelineError> {
|
) -> Result<(), SpecializedMeshPipelineError> {
|
||||||
descriptor.vertex.entry_point = "main".into();
|
descriptor.vertex.entry_point = "main".into();
|
||||||
|
@ -18,8 +18,9 @@ use bevy::{
|
|||||||
render::{
|
render::{
|
||||||
render_asset::RenderAssetUsages,
|
render_asset::RenderAssetUsages,
|
||||||
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
||||||
|
view::NoFrustumCulling,
|
||||||
},
|
},
|
||||||
window::{PresentMode, WindowPlugin, WindowResolution},
|
window::{PresentMode, WindowResolution},
|
||||||
winit::{UpdateMode, WinitSettings},
|
winit::{UpdateMode, WinitSettings},
|
||||||
};
|
};
|
||||||
use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
|
use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
|
||||||
@ -42,6 +43,10 @@ struct Args {
|
|||||||
/// the number of different textures from which to randomly select the material base color. 0 means no textures.
|
/// the number of different textures from which to randomly select the material base color. 0 means no textures.
|
||||||
#[argh(option, default = "0")]
|
#[argh(option, default = "0")]
|
||||||
material_texture_count: usize,
|
material_texture_count: usize,
|
||||||
|
|
||||||
|
/// whether to disable frustum culling, for stress testing purposes
|
||||||
|
#[argh(switch)]
|
||||||
|
no_frustum_culling: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
@ -131,12 +136,15 @@ fn setup(
|
|||||||
let spherical_polar_theta_phi =
|
let spherical_polar_theta_phi =
|
||||||
fibonacci_spiral_on_sphere(golden_ratio, i, N_POINTS);
|
fibonacci_spiral_on_sphere(golden_ratio, i, N_POINTS);
|
||||||
let unit_sphere_p = spherical_polar_to_cartesian(spherical_polar_theta_phi);
|
let unit_sphere_p = spherical_polar_to_cartesian(spherical_polar_theta_phi);
|
||||||
commands.spawn(PbrBundle {
|
let mut cube = commands.spawn(PbrBundle {
|
||||||
mesh: mesh.clone(),
|
mesh: mesh.clone(),
|
||||||
material: materials.choose(&mut material_rng).unwrap().clone(),
|
material: materials.choose(&mut material_rng).unwrap().clone(),
|
||||||
transform: Transform::from_translation((radius * unit_sphere_p).as_vec3()),
|
transform: Transform::from_translation((radius * unit_sphere_p).as_vec3()),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
if args.no_frustum_culling {
|
||||||
|
cube.insert(NoFrustumCulling);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// camera
|
// camera
|
||||||
|
Loading…
Reference in New Issue
Block a user