Change mesh pipeline key to a bitfield.

This commit is contained in:
Robin KAY 2022-11-20 21:40:22 +00:00
parent 0f9c52cc38
commit 5898d7c17c
3 changed files with 83 additions and 36 deletions

View File

@ -17,6 +17,7 @@ bevy = { version = "0.8", default-features = false, features = [
"bevy_pbr", "bevy_pbr",
"bevy_core_pipeline", "bevy_core_pipeline",
] } ] }
bitfield = "0.14"
thiserror = "1.0" thiserror = "1.0"
[dev-dependencies] [dev-dependencies]

View File

@ -1,4 +1,4 @@
use bevy::pbr::{DrawMesh, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup}; use bevy::pbr::{DrawMesh, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup};
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::render_asset::RenderAssets; use bevy::render::render_asset::RenderAssets;
use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline}; use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline};
@ -6,7 +6,7 @@ use bevy::render::render_resource::{PipelineCache, SpecializedMeshPipelines};
use bevy::render::view::ExtractedView; use bevy::render::view::ExtractedView;
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
use crate::pipeline::{OutlinePipeline, PassType}; use crate::pipeline::{OutlinePipeline, PassType, PipelineKey};
use crate::uniforms::{ use crate::uniforms::{
OutlineFragmentUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, OutlineFragmentUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup,
}; };
@ -38,21 +38,17 @@ pub fn queue_outline_stencil_mesh(
.get_id::<DrawStencil>() .get_id::<DrawStencil>()
.unwrap(); .unwrap();
let base_key = MeshPipelineKey::from_msaa_samples(msaa.samples); let base_key = PipelineKey::new()
.with_msaa_samples(msaa.samples)
.with_pass_type(PassType::Stencil);
for (view, mut stencil_phase) in views.iter_mut() { for (view, mut stencil_phase) in views.iter_mut() {
let rangefinder = view.rangefinder3d(); let rangefinder = view.rangefinder3d();
for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() { for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() {
if let Some(mesh) = render_meshes.get(mesh_handle) { if let Some(mesh) = render_meshes.get(mesh_handle) {
let key = let key = base_key.with_primitive_topology(mesh.primitive_topology);
base_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology);
let pipeline = pipelines let pipeline = pipelines
.specialize( .specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout)
&mut pipeline_cache,
&stencil_pipeline,
(key, PassType::Stencil),
&mesh.layout,
)
.unwrap(); .unwrap();
let distance = rangefinder.distance(&mesh_uniform.transform); let distance = rangefinder.distance(&mesh_uniform.transform);
stencil_phase.add(StencilOutline { stencil_phase.add(StencilOutline {
@ -100,30 +96,22 @@ pub fn queue_outline_volume_mesh(
.get_id::<DrawOutline>() .get_id::<DrawOutline>()
.unwrap(); .unwrap();
let base_key = MeshPipelineKey::from_msaa_samples(msaa.samples); let base_key = PipelineKey::new().with_msaa_samples(msaa.samples);
for (view, mut opaque_phase, mut transparent_phase) in views.iter_mut() { for (view, mut opaque_phase, mut transparent_phase) in views.iter_mut() {
let rangefinder = view.rangefinder3d(); let rangefinder = view.rangefinder3d();
for (entity, mesh_uniform, mesh_handle, outline_fragment) in material_meshes.iter() { for (entity, mesh_uniform, mesh_handle, outline_fragment) in material_meshes.iter() {
if let Some(mesh) = render_meshes.get(mesh_handle) { if let Some(mesh) = render_meshes.get(mesh_handle) {
let transparent = outline_fragment.colour[3] < 1.0; let transparent = outline_fragment.colour[3] < 1.0;
let pass_type;
let key = base_key let key = base_key
| MeshPipelineKey::from_primitive_topology(mesh.primitive_topology) .with_primitive_topology(mesh.primitive_topology)
| if transparent { .with_pass_type(if transparent {
pass_type = PassType::Transparent; PassType::Transparent
MeshPipelineKey::TRANSPARENT_MAIN_PASS
} else { } else {
pass_type = PassType::Opaque; PassType::Opaque
MeshPipelineKey::NONE });
};
let pipeline = pipelines let pipeline = pipelines
.specialize( .specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout)
&mut pipeline_cache,
&outline_pipeline,
(key, pass_type),
&mesh.layout,
)
.unwrap(); .unwrap();
let distance = rangefinder.distance(&mesh_uniform.transform); let distance = rangefinder.distance(&mesh_uniform.transform);
if transparent { if transparent {

View File

@ -6,12 +6,13 @@ use bevy::render::render_resource::{
BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState,
BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState,
DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PolygonMode, DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PolygonMode,
PrimitiveState, ShaderSize, ShaderStages, StencilState, TextureFormat, VertexState, PrimitiveState, PrimitiveTopology, ShaderSize, ShaderStages, StencilState, TextureFormat,
VertexState,
}; };
use bevy::render::renderer::RenderDevice; use bevy::render::renderer::RenderDevice;
use bevy::render::texture::BevyDefault; use bevy::render::texture::BevyDefault;
use bevy::{ use bevy::{
pbr::{MeshPipeline, MeshPipelineKey}, pbr::MeshPipeline,
render::{ render::{
mesh::MeshVertexBufferLayout, mesh::MeshVertexBufferLayout,
render_resource::{ render_resource::{
@ -19,6 +20,7 @@ use bevy::{
}, },
}, },
}; };
use bitfield::{bitfield_bitrange, bitfield_fields};
use crate::uniforms::{OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform}; use crate::uniforms::{OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform};
use crate::view_uniforms::OutlineViewUniform; use crate::view_uniforms::OutlineViewUniform;
@ -30,11 +32,67 @@ pub const OUTLINE_SHADER_HANDLE: HandleUntyped =
pub const FRAGMENT_SHADER_HANDLE: HandleUntyped = pub const FRAGMENT_SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 12033806834125368121); HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 12033806834125368121);
#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(Clone, Copy, PartialEq, Eq)]
pub enum PassType { pub enum PassType {
Stencil, Stencil = 1,
Opaque, Opaque = 2,
Transparent, Transparent = 3,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct PipelineKey(u32);
bitfield_bitrange! {struct PipelineKey(u32)}
impl PipelineKey {
bitfield_fields! {
u32;
msaa_samples_minus_one, set_msaa_samples_minus_one: 5, 0;
primitive_topology_int, set_primitive_topology_int: 8, 6;
pass_type_int, set_pass_type_int: 10, 9;
}
pub fn new() -> Self {
PipelineKey(0)
}
pub fn with_msaa_samples(mut self, msaa_samples: u32) -> Self {
self.set_msaa_samples_minus_one(msaa_samples - 1);
self
}
pub fn msaa_samples(&self) -> u32 {
self.msaa_samples_minus_one() + 1
}
pub fn with_primitive_topology(mut self, primitive_topology: PrimitiveTopology) -> Self {
self.set_primitive_topology_int(primitive_topology as u32);
self
}
pub fn primitive_topology(&self) -> PrimitiveTopology {
match self.primitive_topology_int() {
x if x == PrimitiveTopology::PointList as u32 => PrimitiveTopology::PointList,
x if x == PrimitiveTopology::LineList as u32 => PrimitiveTopology::LineList,
x if x == PrimitiveTopology::LineStrip as u32 => PrimitiveTopology::LineStrip,
x if x == PrimitiveTopology::TriangleList as u32 => PrimitiveTopology::TriangleList,
x if x == PrimitiveTopology::TriangleStrip as u32 => PrimitiveTopology::TriangleStrip,
x => panic!("Invalid value for PrimitiveTopology: {}", x),
}
}
pub fn with_pass_type(mut self, pass_type: PassType) -> Self {
self.set_pass_type_int(pass_type as u32);
self
}
pub fn pass_type(&self) -> PassType {
match self.pass_type_int() {
x if x == PassType::Stencil as u32 => PassType::Stencil,
x if x == PassType::Opaque as u32 => PassType::Opaque,
x if x == PassType::Transparent as u32 => PassType::Transparent,
x => panic!("Invalid value for PassType: {}", x),
}
}
} }
pub struct OutlinePipeline { pub struct OutlinePipeline {
@ -117,11 +175,11 @@ impl FromWorld for OutlinePipeline {
} }
impl SpecializedMeshPipeline for OutlinePipeline { impl SpecializedMeshPipeline for OutlinePipeline {
type Key = (MeshPipelineKey, PassType); type Key = PipelineKey;
fn specialize( fn specialize(
&self, &self,
(key, pass_type): Self::Key, key: Self::Key,
mesh_layout: &MeshVertexBufferLayout, mesh_layout: &MeshVertexBufferLayout,
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> { ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
let mut targets = vec![]; let mut targets = vec![];
@ -142,7 +200,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
}, },
); );
bind_layouts.push(self.outline_view_bind_group_layout.clone()); bind_layouts.push(self.outline_view_bind_group_layout.clone());
match pass_type { match key.pass_type() {
PassType::Stencil => { PassType::Stencil => {
vertex_defs.push("OFFSET_ZERO".to_string()); vertex_defs.push("OFFSET_ZERO".to_string());
bind_layouts.push(self.outline_stencil_bind_group_layout.clone()); bind_layouts.push(self.outline_stencil_bind_group_layout.clone());
@ -151,7 +209,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
fragment_defs.push("VOLUME".to_string()); fragment_defs.push("VOLUME".to_string());
targets.push(Some(ColorTargetState { targets.push(Some(ColorTargetState {
format: TextureFormat::bevy_default(), format: TextureFormat::bevy_default(),
blend: Some(if pass_type == PassType::Transparent { blend: Some(if key.pass_type() == PassType::Transparent {
BlendState::ALPHA_BLENDING BlendState::ALPHA_BLENDING
} else { } else {
BlendState::REPLACE BlendState::REPLACE