From 5898d7c17cb6d0412518a868d205f91be9533226 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Sun, 20 Nov 2022 21:40:22 +0000 Subject: [PATCH] Change mesh pipeline key to a bitfield. --- Cargo.toml | 1 + src/draw.rs | 40 +++++++++---------------- src/pipeline.rs | 78 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 83 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d17c38e..955df20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ bevy = { version = "0.8", default-features = false, features = [ "bevy_pbr", "bevy_core_pipeline", ] } +bitfield = "0.14" thiserror = "1.0" [dev-dependencies] diff --git a/src/draw.rs b/src/draw.rs index 76ecb1a..325ad0f 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -1,4 +1,4 @@ -use bevy::pbr::{DrawMesh, MeshPipelineKey, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup}; +use bevy::pbr::{DrawMesh, MeshUniform, SetMeshBindGroup, SetMeshViewBindGroup}; use bevy::prelude::*; use bevy::render::render_asset::RenderAssets; 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 crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; -use crate::pipeline::{OutlinePipeline, PassType}; +use crate::pipeline::{OutlinePipeline, PassType, PipelineKey}; use crate::uniforms::{ OutlineFragmentUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, }; @@ -38,21 +38,17 @@ pub fn queue_outline_stencil_mesh( .get_id::() .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() { let rangefinder = view.rangefinder3d(); for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() { if let Some(mesh) = render_meshes.get(mesh_handle) { - let key = - base_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology); + let key = base_key.with_primitive_topology(mesh.primitive_topology); let pipeline = pipelines - .specialize( - &mut pipeline_cache, - &stencil_pipeline, - (key, PassType::Stencil), - &mesh.layout, - ) + .specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout) .unwrap(); let distance = rangefinder.distance(&mesh_uniform.transform); stencil_phase.add(StencilOutline { @@ -100,30 +96,22 @@ pub fn queue_outline_volume_mesh( .get_id::() .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() { let rangefinder = view.rangefinder3d(); for (entity, mesh_uniform, mesh_handle, outline_fragment) in material_meshes.iter() { if let Some(mesh) = render_meshes.get(mesh_handle) { let transparent = outline_fragment.colour[3] < 1.0; - let pass_type; let key = base_key - | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology) - | if transparent { - pass_type = PassType::Transparent; - MeshPipelineKey::TRANSPARENT_MAIN_PASS + .with_primitive_topology(mesh.primitive_topology) + .with_pass_type(if transparent { + PassType::Transparent } else { - pass_type = PassType::Opaque; - MeshPipelineKey::NONE - }; + PassType::Opaque + }); let pipeline = pipelines - .specialize( - &mut pipeline_cache, - &outline_pipeline, - (key, pass_type), - &mesh.layout, - ) + .specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout) .unwrap(); let distance = rangefinder.distance(&mesh_uniform.transform); if transparent { diff --git a/src/pipeline.rs b/src/pipeline.rs index be2231f..b8f157c 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -6,12 +6,13 @@ use bevy::render::render_resource::{ BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, 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::texture::BevyDefault; use bevy::{ - pbr::{MeshPipeline, MeshPipelineKey}, + pbr::MeshPipeline, render::{ mesh::MeshVertexBufferLayout, render_resource::{ @@ -19,6 +20,7 @@ use bevy::{ }, }, }; +use bitfield::{bitfield_bitrange, bitfield_fields}; use crate::uniforms::{OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform}; use crate::view_uniforms::OutlineViewUniform; @@ -30,11 +32,67 @@ pub const OUTLINE_SHADER_HANDLE: HandleUntyped = pub const FRAGMENT_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 12033806834125368121); -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum PassType { - Stencil, - Opaque, - Transparent, + Stencil = 1, + Opaque = 2, + 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 { @@ -117,11 +175,11 @@ impl FromWorld for OutlinePipeline { } impl SpecializedMeshPipeline for OutlinePipeline { - type Key = (MeshPipelineKey, PassType); + type Key = PipelineKey; fn specialize( &self, - (key, pass_type): Self::Key, + key: Self::Key, mesh_layout: &MeshVertexBufferLayout, ) -> Result { let mut targets = vec![]; @@ -142,7 +200,7 @@ impl SpecializedMeshPipeline for OutlinePipeline { }, ); bind_layouts.push(self.outline_view_bind_group_layout.clone()); - match pass_type { + match key.pass_type() { PassType::Stencil => { vertex_defs.push("OFFSET_ZERO".to_string()); bind_layouts.push(self.outline_stencil_bind_group_layout.clone()); @@ -151,7 +209,7 @@ impl SpecializedMeshPipeline for OutlinePipeline { fragment_defs.push("VOLUME".to_string()); targets.push(Some(ColorTargetState { format: TextureFormat::bevy_default(), - blend: Some(if pass_type == PassType::Transparent { + blend: Some(if key.pass_type() == PassType::Transparent { BlendState::ALPHA_BLENDING } else { BlendState::REPLACE