Skip to content

Commit

Permalink
Some work on culling
Browse files Browse the repository at this point in the history
  • Loading branch information
mattkleiny committed Jan 22, 2024
1 parent 96c6ab6 commit 7149135
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 32 deletions.
2 changes: 1 addition & 1 deletion common/src/maths/linear/frustum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::*;

/// A frustum in 3-space.
#[repr(C)]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct Frustum {
pub near: Plane,
pub far: Plane,
Expand Down
4 changes: 4 additions & 0 deletions modules/graphics/src/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ impl GraphicsBackend for HeadlessGraphicsBackend {
None
}

fn shader_metadata(&self, shader: ShaderId) -> Result<ShaderFlags, ShaderError> {
Ok(ShaderFlags::empty())
}

fn shader_set_uniform(&self, shader: ShaderId, location: usize, value: &ShaderUniform) -> Result<(), ShaderError> {
Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions modules/graphics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Graphics engine for Surreal.
#![feature(impl_trait_in_assoc_type)]
#![feature(slice_group_by)]

pub use buffers::*;
pub use colors::*;
Expand Down Expand Up @@ -183,6 +184,7 @@ pub trait GraphicsBackend {
// shaders
fn shader_create(&self) -> Result<ShaderId, ShaderError>;
fn shader_link(&self, shader: ShaderId, kernels: &[ShaderKernel]) -> Result<(), ShaderError>;
fn shader_metadata(&self, shader: ShaderId) -> Result<ShaderFlags, ShaderError>;
fn shader_uniform_location(&self, shader: ShaderId, name: &str) -> Option<usize>;
fn shader_set_uniform(&self, shader: ShaderId, location: usize, value: &ShaderUniform) -> Result<(), ShaderError>;
fn shader_set_uniforms(&self, shader: ShaderId, location: usize, value: &[ShaderUniform]) -> Result<(), ShaderError>;
Expand Down
5 changes: 5 additions & 0 deletions modules/graphics/src/materials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ impl Material {
}
}

/// Gets the underlying [`ShaderProgram`] of the material.
pub fn shader(&self) -> &ShaderProgram {
&self.shader
}

/// Gets the blend state of the material.
pub fn blend_state(&self) -> BlendState {
self.blend_state
Expand Down
4 changes: 4 additions & 0 deletions modules/graphics/src/opengl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,10 @@ impl GraphicsBackend for OpenGLGraphicsBackend {
}
}

fn shader_metadata(&self, _shader: ShaderId) -> Result<ShaderFlags, ShaderError> {
todo!()
}

fn shader_set_uniform(&self, shader: ShaderId, location: usize, value: &ShaderUniform) -> Result<(), ShaderError> {
unsafe {
let shader_id = shader.into();
Expand Down
135 changes: 114 additions & 21 deletions modules/graphics/src/rendering/culling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use common::Frustum;
use super::*;

bitflags! {
/// Flags that can be used to control the behavior of a material.
/// Flags that indicate the required state of the graphics pipeline for a material.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
struct MaterialFlags: u32 {
pub struct MaterialFlags: u32 {
const ALPHA_BLENDING = 0b00000001;
const ALPHA_TESTING = 0b00000010;
const BACKFACE_CULLING = 0b00000100;
Expand All @@ -23,22 +23,60 @@ bitflags! {
/// This is used to sort materials into batches for efficient rendering,
/// minimizing state changes between draw calls.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
struct MaterialSortingKey {
pub struct MaterialSortingKey {
flags: MaterialFlags,
}

impl From<MaterialFlags> for MaterialSortingKey {
/// Gets the sorting key for the given material flags.
fn from(flags: MaterialFlags) -> Self {
Self { flags }
}
}

impl From<&Material> for MaterialSortingKey {
/// Gets the sorting key for the given material.
fn from(_value: &Material) -> Self {
todo!()
fn from(material: &Material) -> Self {
let mut flags = MaterialFlags::empty();

let shader = material.shader();
let metadata = shader.flags();

if material.blend_state() != BlendState::Disabled {
flags.insert(MaterialFlags::ALPHA_BLENDING);
}

if material.culling_mode() != CullingMode::Disabled {
flags.insert(MaterialFlags::BACKFACE_CULLING);
}

if material.scissor_mode() != ScissorMode::Disabled {
flags.insert(MaterialFlags::SCISSOR_TESTING);
}

if metadata.contains(ShaderFlags::ALPHA_TESTING) {
flags.insert(MaterialFlags::ALPHA_TESTING);
}

if metadata.contains(ShaderFlags::DEPTH_TESTING) {
flags.insert(MaterialFlags::DEPTH_TESTING);
}

if metadata.contains(ShaderFlags::DEPTH_WRITING) {
flags.insert(MaterialFlags::DEPTH_WRITING);
}

Self { flags }
}
}

/// Represents an object that is visible to a camera, along with it's material
/// properties that are used to render it.
pub struct VisibleObject {
object: Box<dyn RenderObject>,
material_sort_key: MaterialSortingKey,
/// The object that is visible.
pub object: Box<dyn RenderObject>,
/// The sorting key for the material of the object.
pub material_sort_key: MaterialSortingKey,
}

/// A set of visible objects that can be rendered in a scene.
Expand All @@ -53,32 +91,87 @@ pub struct VisibleObjectSet {
pub objects: Vec<VisibleObject>,
}

/// Allows iterating over the [`VisibleObject`]s in a [`VisibleObjectSet`] by
/// batching them by [`MaterialSortingKey`].
///
/// This is useful for efficiently rendering the objects in a set by minimizing
/// state changes between draw calls.
pub struct VisibleObjectIterator<'a> {
visible_objects: Vec<&'a [VisibleObject]>,
current_index: usize,
}

impl<'a> IntoIterator for &'a VisibleObjectSet {
type Item = &'a VisibleObject;
type Item = &'a [VisibleObject];
type IntoIter = VisibleObjectIterator<'a>;

fn into_iter(self) -> Self::IntoIter {
let visible_objects = self
.objects
.group_by(|a, b| a.material_sort_key == b.material_sort_key)
.collect();

VisibleObjectIterator {
visible_objects: &self.objects,
visible_objects,
current_index: 0,
}
}
}

/// Allows iterating over the [`VisibleObject`]s in a [`VisibleObjectSet`] by
/// batching them by [`MaterialSortingKey`].
///
/// This is useful for efficiently rendering the objects in a set by minimizing
/// state changes between draw calls.
pub struct VisibleObjectIterator<'a> {
visible_objects: &'a [VisibleObject],
current_index: usize,
}

impl<'a> Iterator for VisibleObjectIterator<'a> {
type Item = &'a VisibleObject;
type Item = &'a [VisibleObject];

fn next(&mut self) -> Option<Self::Item> {
todo!()
if self.current_index >= self.visible_objects.len() {
return None;
}

let index = self.current_index;
let batch = self.visible_objects[index];

self.current_index += 1;

Some(batch)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[derive(Default)]
struct TestObject;

impl RenderObject for TestObject {
fn render(&self, _renderer: &mut Renderer) {
// no-op
}
}

#[test]
fn test_iteration_over_group_by_key() {
let objects = VisibleObjectSet {
frustum: Frustum::default(),
objects: vec![
VisibleObject {
object: Box::new(TestObject::default()),
material_sort_key: MaterialSortingKey::from(MaterialFlags::ALPHA_BLENDING),
},
VisibleObject {
object: Box::new(TestObject::default()),
material_sort_key: MaterialSortingKey::from(MaterialFlags::DEPTH_TESTING),
},
VisibleObject {
object: Box::new(TestObject::default()),
material_sort_key: MaterialSortingKey::from(MaterialFlags::ALPHA_BLENDING),
},
],
};

for batch in &objects {
for object in batch {
println!("{:?}", object.material_sort_key);
}
}
}
}
37 changes: 27 additions & 10 deletions modules/graphics/src/shaders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use core::str;
use std::{cell::RefCell, rc::Rc};

use bitflags::bitflags;
pub use glsl::*;
pub use templates::*;

Expand All @@ -18,6 +19,15 @@ use common::*;

use super::*;

/// Represents a language for [`ShaderKernel`] compilation.
///
/// Abstracting over shader languages allows us to build out new language
/// paradigms in the future.
pub trait ShaderLanguage {
/// Parses the given raw source code into one or more [`ShaderKernel`]s.
fn parse_kernels(source_code: &str) -> common::Result<Vec<ShaderKernel>>;
}

/// Different types of shaders supported by the engine.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum ShaderKind {
Expand All @@ -33,13 +43,14 @@ pub struct ShaderKernel {
pub code: String,
}

/// Represents a language for [`ShaderKernel`] compilation.
///
/// Abstracting over shader languages allows us to build out new language
/// paradigms in the future.
pub trait ShaderLanguage {
/// Parses the given raw source code into one or more [`ShaderKernel`]s.
fn parse_kernels(source_code: &str) -> common::Result<Vec<ShaderKernel>>;
bitflags! {
/// Metadata flags indicating what state the shader program requires.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub struct ShaderFlags: u32 {
const ALPHA_TESTING = 0b0000001;
const DEPTH_TESTING = 0b00000010;
const DEPTH_WRITING = 0b00000100;
}
}

/// Represents a single compiled shader program.
Expand All @@ -53,6 +64,7 @@ struct ShaderProgramState {
id: ShaderId,
graphics: GraphicsEngine,
location_cache: FastHashMap<String, Option<usize>>,
flags: ShaderFlags,
}

impl ShaderProgram {
Expand All @@ -63,6 +75,7 @@ impl ShaderProgram {
id: graphics.shader_create()?,
graphics: graphics.clone(),
location_cache: FastHashMap::default(),
flags: ShaderFlags::empty(),
})),
})
}
Expand Down Expand Up @@ -108,9 +121,12 @@ impl ShaderProgram {

/// Returns the [`ShaderId`] of the underlying program.
pub fn id(&self) -> ShaderId {
let state = self.state.borrow();
self.state.borrow().id
}

state.id
/// Returns the [`ShaderFlags`] for the underlying program.
pub fn flags(&self) -> ShaderFlags {
self.state.borrow().flags
}

/// Retrieves the binding location of the given shader uniform in the
Expand Down Expand Up @@ -166,10 +182,11 @@ impl ShaderProgram {

/// Reloads the [`ShaderProgram`] from the given shader code.
pub fn load_kernels(&self, kernels: &[ShaderKernel]) -> common::Result<()> {
let state = self.state.borrow();
let mut state = self.state.borrow_mut();
let graphics = &state.graphics;

graphics.shader_link(state.id, &kernels)?;
state.flags = graphics.shader_metadata(state.id)?;

Ok(())
}
Expand Down

0 comments on commit 7149135

Please sign in to comment.