Skip to content

Commit

Permalink
Change shader traits to handle ID enums instead of integers (#488)
Browse files Browse the repository at this point in the history
  • Loading branch information
thatcomputerguy0101 authored Sep 25, 2024
1 parent bf84983 commit c475f83
Show file tree
Hide file tree
Showing 38 changed files with 151 additions and 102 deletions.
4 changes: 2 additions & 2 deletions examples/fireworks/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ impl Material for FireworksMaterial {
MaterialType::Transparent
}

fn id(&self) -> u16 {
0b1u16
fn id(&self) -> EffectMaterialId {
EffectMaterialId(0b1u16)
}
}
// Entry point for non-wasm
Expand Down
4 changes: 2 additions & 2 deletions examples/logo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ impl Material for LogoMaterial<'_> {
include_str!("shader.frag").to_string()
}

fn id(&self) -> u16 {
0b1u16
fn id(&self) -> EffectMaterialId {
EffectMaterialId(0b1u16)
}

fn fragment_attributes(&self) -> FragmentAttributes {
Expand Down
4 changes: 2 additions & 2 deletions examples/mandelbrot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ impl Material for MandelbrotMaterial {
MaterialType::Opaque
}

fn id(&self) -> u16 {
0b11u16
fn id(&self) -> EffectMaterialId {
EffectMaterialId(0b11u16)
}
}

Expand Down
48 changes: 35 additions & 13 deletions src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub enum RendererError {
}

mod shader_ids;
pub(crate) use shader_ids::*;
pub use shader_ids::*;

mod camera;
pub use camera::*;
Expand Down Expand Up @@ -378,6 +378,20 @@ impl_render_target_extensions!(
impl_render_target_extensions!(ColorTargetMultisample<C: TextureDataType>);
impl_render_target_extensions!(DepthTargetMultisample<D: DepthTextureDataType>);

///
/// Combines shader ID components together into a single ID vector, to be used as a key in shader caching.
///
fn combine_ids(
geometry: GeometryId,
effect_material: EffectMaterialId,
lights: impl Iterator<Item = LightId>,
) -> Vec<u8> {
let mut id = geometry.0.to_le_bytes().to_vec();
id.extend(effect_material.0.to_le_bytes());
id.extend(lights.map(|l| l.0));
return id;
}

///
/// Render the given [Geometry] with the given [Material].
/// Must be called in the callback given as input to a [RenderTarget], [ColorTarget] or [DepthTarget] write method.
Expand All @@ -391,9 +405,11 @@ pub fn render_with_material(
lights: &[&dyn Light],
) {
let fragment_attributes = material.fragment_attributes();
let mut id = geometry.id(fragment_attributes).to_le_bytes().to_vec();
id.extend(material.id().to_le_bytes());
id.extend(lights.iter().map(|l| l.id()));
let id = combine_ids(
geometry.id(fragment_attributes),
material.id(),
lights.iter().map(|l| l.id()),
);

let mut programs = context.programs.write().unwrap();
let program = programs.entry(id).or_insert_with(|| {
Expand Down Expand Up @@ -428,9 +444,11 @@ pub fn render_with_effect(
depth_texture: Option<DepthTexture>,
) {
let fragment_attributes = effect.fragment_attributes();
let mut id = geometry.id(fragment_attributes).to_le_bytes().to_vec();
id.extend(effect.id(color_texture, depth_texture).to_le_bytes());
id.extend(lights.iter().map(|l| l.id()));
let id = combine_ids(
geometry.id(fragment_attributes),
effect.id(color_texture, depth_texture),
lights.iter().map(|l| l.id()),
);

let mut programs = context.programs.write().unwrap();
let program = programs.entry(id).or_insert_with(|| {
Expand Down Expand Up @@ -460,9 +478,11 @@ pub fn apply_screen_material(
if fragment_attributes.normal || fragment_attributes.position || fragment_attributes.tangents {
panic!("Not possible to use the given material to render full screen, the full screen geometry only provides uv coordinates and color");
}
let mut id = GeometryId::Screen.0.to_le_bytes().to_vec();
id.extend(material.id().to_le_bytes());
id.extend(lights.iter().map(|l| l.id()));
let id = combine_ids(
GeometryId::Screen,
material.id(),
lights.iter().map(|l| l.id()),
);

let mut programs = context.programs.write().unwrap();
let program = programs.entry(id).or_insert_with(|| {
Expand Down Expand Up @@ -499,9 +519,11 @@ pub fn apply_screen_effect(
if fragment_attributes.normal || fragment_attributes.position || fragment_attributes.tangents {
panic!("Not possible to use the given effect to render full screen, the full screen geometry only provides uv coordinates and color");
}
let mut id = GeometryId::Screen.0.to_le_bytes().to_vec();
id.extend(effect.id(color_texture, depth_texture).to_le_bytes());
id.extend(lights.iter().map(|l| l.id()));
let id = combine_ids(
GeometryId::Screen,
effect.id(color_texture, depth_texture),
lights.iter().map(|l| l.id()),
);

let mut programs = context.programs.write().unwrap();
let program = programs.entry(id).or_insert_with(|| {
Expand Down
16 changes: 12 additions & 4 deletions src/renderer/effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ macro_rules! impl_effect_body {
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> u16 {
) -> EffectMaterialId {
self.$inner().id(color_texture, depth_texture)
}

Expand Down Expand Up @@ -88,9 +88,13 @@ pub trait Effect {
/// Returns a unique ID for each variation of the shader source returned from [Effect::fragment_shader_source].
///
/// **Note:** The first 16 bits are reserved to internally implemented effects, so if implementing the [Effect] trait
/// outside of this crate, always return an id that is larger than or equal to `0b1u16 << 16`.
/// outside of this crate, always return an id in the public use range as defined by [EffectMaterialId].
///
fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16;
fn id(
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> EffectMaterialId;

///
/// Returns a [FragmentAttributes] struct that describes which fragment attributes,
Expand Down Expand Up @@ -152,7 +156,11 @@ impl<T: Effect> Effect for std::sync::RwLock<T> {
.fragment_shader_source(lights, color_texture, depth_texture)
}

fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16 {
fn id(
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> EffectMaterialId {
self.read().unwrap().id(color_texture, depth_texture)
}

Expand Down
8 changes: 6 additions & 2 deletions src/renderer/effect/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,12 @@ impl Effect for CopyEffect {
)
}

fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16 {
EffectMaterialId::CopyEffect(color_texture, depth_texture).0
fn id(
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> EffectMaterialId {
EffectMaterialId::CopyEffect(color_texture, depth_texture)
}

fn fragment_attributes(&self) -> FragmentAttributes {
Expand Down
7 changes: 5 additions & 2 deletions src/renderer/effect/fog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ impl Effect for FogEffect {
)
}

fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16 {
fn id(
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> EffectMaterialId {
EffectMaterialId::FogEffect(
color_texture.expect("Must supply a color texture to apply a fog effect"),
depth_texture.expect("Must supply a depth texture to apply a fog effect"),
)
.0
}

fn fragment_attributes(&self) -> FragmentAttributes {
Expand Down
8 changes: 6 additions & 2 deletions src/renderer/effect/full_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ impl Effect for ScreenEffect {
)
}

fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16 {
EffectMaterialId::ScreenEffect(color_texture, depth_texture).0
fn id(
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> EffectMaterialId {
EffectMaterialId::ScreenEffect(color_texture, depth_texture)
}

fn fragment_attributes(&self) -> FragmentAttributes {
Expand Down
7 changes: 5 additions & 2 deletions src/renderer/effect/fxaa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ impl Effect for FxaaEffect {
)
}

fn id(&self, color_texture: Option<ColorTexture>, _depth_texture: Option<DepthTexture>) -> u16 {
fn id(
&self,
color_texture: Option<ColorTexture>,
_depth_texture: Option<DepthTexture>,
) -> EffectMaterialId {
EffectMaterialId::FxaaEffect(
color_texture.expect("Must supply a color texture to apply a fxaa effect"),
)
.0
}

fn fragment_attributes(&self) -> FragmentAttributes {
Expand Down
8 changes: 6 additions & 2 deletions src/renderer/effect/lighting_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ impl Effect for LightingPassEffect {
fragment_shader
}

fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16 {
EffectMaterialId::LightingPassEffect(color_texture.unwrap(), depth_texture.unwrap()).0
fn id(
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> EffectMaterialId {
EffectMaterialId::LightingPassEffect(color_texture.unwrap(), depth_texture.unwrap())
}

fn fragment_attributes(&self) -> FragmentAttributes {
Expand Down
7 changes: 5 additions & 2 deletions src/renderer/effect/water.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ impl Effect for WaterEffect {
)
}

fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16 {
fn id(
&self,
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) -> EffectMaterialId {
EffectMaterialId::WaterEffect(
color_texture.expect("Must supply a color texture to apply a water effect"),
depth_texture.expect("Must supply a depth texture to apply a water effect"),
)
.0
}

fn fragment_attributes(&self) -> FragmentAttributes {
Expand Down
8 changes: 4 additions & 4 deletions src/renderer/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ macro_rules! impl_geometry_body {
self.$inner().vertex_shader_source(required_attributes)
}

fn id(&self, required_attributes: FragmentAttributes) -> u16 {
fn id(&self, required_attributes: FragmentAttributes) -> GeometryId {
self.$inner().id(required_attributes)
}

Expand Down Expand Up @@ -127,9 +127,9 @@ pub trait Geometry {
/// Returns a unique ID for each variation of the shader source returned from `Geometry::vertex_shader_source`.
///
/// **Note:** The last bit is reserved to internally implemented geometries, so if implementing the `Geometry` trait
/// outside of this crate, always return an id that is smaller than `0b1u16 << 15`.
/// outside of this crate, always return an id in the public use range as defined by [GeometryId].
///
fn id(&self, required_attributes: FragmentAttributes) -> u16;
fn id(&self, required_attributes: FragmentAttributes) -> GeometryId;

///
/// Render the geometry with the given [Material].
Expand Down Expand Up @@ -216,7 +216,7 @@ impl<T: Geometry> Geometry for std::sync::RwLock<T> {
.vertex_shader_source(required_attributes)
}

fn id(&self, required_attributes: FragmentAttributes) -> u16 {
fn id(&self, required_attributes: FragmentAttributes) -> GeometryId {
self.read().unwrap().id(required_attributes)
}

Expand Down
3 changes: 1 addition & 2 deletions src/renderer/geometry/instanced_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ impl Geometry for InstancedMesh {
)
}

fn id(&self, required_attributes: FragmentAttributes) -> u16 {
fn id(&self, required_attributes: FragmentAttributes) -> GeometryId {
let instance_buffers = &self
.instance_buffers
.read()
Expand All @@ -324,7 +324,6 @@ impl Geometry for InstancedMesh {
instance_buffers.contains_key("instance_translation"),
required_attributes.uv && instance_buffers.contains_key("tex_transform_row1"),
)
.0
}

fn aabb(&self) -> AxisAlignedBoundingBox {
Expand Down
3 changes: 1 addition & 2 deletions src/renderer/geometry/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,13 @@ impl Geometry for Mesh {
)
}

fn id(&self, required_attributes: FragmentAttributes) -> u16 {
fn id(&self, required_attributes: FragmentAttributes) -> GeometryId {
GeometryId::Mesh(
required_attributes.normal,
required_attributes.tangents,
required_attributes.uv,
required_attributes.color,
)
.0
}

fn render_with_material(
Expand Down
3 changes: 1 addition & 2 deletions src/renderer/geometry/particles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl<'a> IntoIterator for &'a ParticleSystem {
}

impl Geometry for ParticleSystem {
fn id(&self, required_attributes: FragmentAttributes) -> u16 {
fn id(&self, required_attributes: FragmentAttributes) -> GeometryId {
GeometryId::ParticleSystem(
required_attributes.normal,
required_attributes.tangents,
Expand All @@ -196,7 +196,6 @@ impl Geometry for ParticleSystem {
required_attributes.color && self.instance_buffers.contains_key("instance_color"),
required_attributes.uv && self.instance_buffers.contains_key("tex_transform_row1"),
)
.0
}

fn vertex_shader_source(&self, required_attributes: FragmentAttributes) -> String {
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/geometry/sprites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ impl Geometry for Sprites {
include_str!("shaders/sprites.vert").to_owned()
}

fn id(&self, _required_attributes: FragmentAttributes) -> u16 {
GeometryId::Sprites.0
fn id(&self, _required_attributes: FragmentAttributes) -> GeometryId {
GeometryId::Sprites
}

fn render_with_material(
Expand Down
9 changes: 5 additions & 4 deletions src/renderer/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ macro_rules! impl_light_body {
fn use_uniforms(&self, program: &Program, i: u32) {
self.$inner().use_uniforms(program, i)
}
fn id(&self) -> u8 {
fn id(&self) -> LightId {
self.$inner().id()
}
};
Expand Down Expand Up @@ -42,6 +42,7 @@ pub use environment::*;

use crate::core::*;
use crate::renderer::camera::*;
use crate::renderer::LightId;

///
/// Specifies how the intensity of a light fades over distance.
Expand Down Expand Up @@ -83,9 +84,9 @@ pub trait Light {
/// Returns a unique ID for each variation of the shader source returned from `Light::shader_source`.
///
/// **Note:** The last bit is reserved to internally implemented materials, so if implementing the `Light` trait
/// outside of this crate, always return an id that is smaller than `0b1u8 << 7`.
/// outside of this crate, always return an id in the public use range as defined by [LightId].
///
fn id(&self) -> u8;
fn id(&self) -> LightId;
}

impl<T: Light + ?Sized> Light for &T {
Expand Down Expand Up @@ -119,7 +120,7 @@ impl<T: Light> Light for std::sync::Arc<std::sync::RwLock<T>> {
fn use_uniforms(&self, program: &Program, i: u32) {
self.read().unwrap().use_uniforms(program, i)
}
fn id(&self) -> u8 {
fn id(&self) -> LightId {
self.read().unwrap().id()
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/light/ambient_light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ impl Light for AmbientLight {
);
}

fn id(&self) -> u8 {
LightId::AmbientLight(self.environment.is_some()).0
fn id(&self) -> LightId {
LightId::AmbientLight(self.environment.is_some())
}
}

Expand Down
Loading

0 comments on commit c475f83

Please sign in to comment.