diff options
| -rw-r--r-- | engine/src/rendering.rs | 48 | ||||
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 390 | ||||
| -rw-r--r-- | engine/src/rendering/object.rs | 1 |
3 files changed, 323 insertions, 116 deletions
diff --git a/engine/src/rendering.rs b/engine/src/rendering.rs index cb6ec08..ffb5a4f 100644 --- a/engine/src/rendering.rs +++ b/engine/src/rendering.rs @@ -235,6 +235,14 @@ pub enum Command update: TextureUpdate, }, RemoveTexture(ObjectId), + CreateFramebuffer(ObjectId), + RemoveFramebuffer(ObjectId), + UpdateFramebufferProperties + { + object_id: ObjectId, + properties: FramebufferProperties, + update_flags: FramebufferPropertiesUpdateFlags, + }, CreateMesh { obj_id: ObjectId, @@ -376,6 +384,12 @@ pub struct DrawProperties pub scissor_test_enabled: bool, pub scissor_box: ScissorBox, pub face_culling_enabled: bool, + + /// `None` for default framebuffer + pub draw_framebuffer: Option<ObjectId>, + + /// `None` for default framebuffer + pub read_framebuffer: Option<ObjectId>, } impl Default for DrawProperties @@ -391,13 +405,15 @@ impl Default for DrawProperties scissor_test_enabled: false, scissor_box: ScissorBox::default(), face_culling_enabled: false, + draw_framebuffer: None, + read_framebuffer: None, } } } bitflags! { #[derive(Debug, Clone, Copy)] - pub struct DrawPropertiesUpdateFlags: usize + pub struct DrawPropertiesUpdateFlags: u16 { const POLYGON_MODE_CONFIG = 1 << 0; const BLENDING_CONFIG = 1 << 1; @@ -407,6 +423,8 @@ bitflags! { const SCISSOR_TEST_ENABLED = 1 << 5; const SCISSOR_BOX = 1 << 6; const FACE_CULLING_ENABLED = 1 << 7; + const DRAW_FRAMEBUFFER = 1 << 8; + const READ_FRAMEBUFFER = 1 << 9; } } @@ -645,3 +663,31 @@ impl TexturePixelDataFormat } } } + +/// Index of a color texture attached to a framebuffer. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct FramebufferColorTextureIndex(pub u8); + +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct FramebufferProperties +{ + pub depth_texture: Option<FramebufferTexture>, + pub color_draw_buffer: Option<FramebufferColorTextureIndex>, +} + +bitflags! { + #[derive(Debug, Default, Clone)] + pub struct FramebufferPropertiesUpdateFlags: u8 + { + const DEPTH_TEXTURE = 1 << 0; + const COLOR_DRAW_BUFFER = 1 << 1; + } +} + +#[derive(Debug, Clone)] +pub struct FramebufferTexture +{ + pub object_id: ObjectId, + pub mipmap_level: u16, +} diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index 35dc801..444c757 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::convert::Infallible; use std::hint::cold_path; use std::num::NonZero; @@ -30,6 +31,13 @@ use opengl_bindings::debug::{ MessageType, SetDebugMessageControlError as GlSetDebugMessageControlError, }; +use opengl_bindings::framebuffer::{ + bind as gl_bind_framebuffer, + Attachment as GlFramebufferAttachment, + ColorAttachment as GlFramebufferColorAttachment, + Framebuffer as GlFramebuffer, + Target as GlFramebufferTarget, +}; use opengl_bindings::misc::{ clear_buffers, define_scissor_box as gl_define_scissor_box, @@ -110,7 +118,10 @@ use crate::rendering::{ CommandQueue, DepthFunction, DrawMeshOptions, + DrawProperties, DrawPropertiesUpdateFlags, + FramebufferProperties, + FramebufferPropertiesUpdateFlags, GraphicsProperties, Surface, SurfaceId, @@ -363,6 +374,10 @@ enum BackendResource pixel_data_format: TexturePixelDataFormat, kind: TextureKind, }, + Framebuffer + { + framebuffer: GlFramebuffer + }, } impl BackendResource @@ -373,6 +388,7 @@ impl BackendResource Self::Mesh { .. } => ObjectKind::Mesh, Self::Shader { .. } => ObjectKind::ShaderProgram, Self::Texture { .. } => ObjectKind::Texture, + Self::Framebuffer { .. } => ObjectKind::Framebuffer, } } @@ -388,6 +404,9 @@ impl BackendResource Self::Texture { texture, .. } => { texture.clone().delete(curr_gl_ctx); } + Self::Framebuffer { framebuffer } => { + framebuffer.clone().delete(curr_gl_ctx); + } } } } @@ -1048,6 +1067,39 @@ fn handle_commands( gl_context, ); } + Command::CreateFramebuffer(object_id) => { + backend_resources.try_create_resource::<Infallible>( + object_store, + object_id, + || { + Ok(BackendResource::Framebuffer { + framebuffer: GlFramebuffer::new(gl_context), + }) + }, + ); + } + Command::RemoveFramebuffer(object_id) => { + backend_resources.remove_resource( + object_store, + object_id, + ObjectKind::Framebuffer, + gl_context, + ); + } + Command::UpdateFramebufferProperties { + object_id, + properties, + update_flags, + } => { + update_framebuffer_properties( + backend_resources, + object_store, + gl_context, + object_id, + properties, + update_flags, + ); + } Command::CreateMesh { obj_id, mesh, usage: mesh_usage } => { let mesh = match &mesh { AssetOrValue::Asset(mesh_asset) => { @@ -1157,121 +1209,14 @@ fn handle_commands( tracing::error!("Failed to draw mesh: {err}"); }; } - Command::UpdateDrawProperties(draw_props, draw_props_update_flags) => { - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::POLYGON_MODE_CONFIG) - { - opengl_bindings::misc::set_polygon_mode( - gl_context, - draw_props.polygon_mode_config.face, - draw_props.polygon_mode_config.mode, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::BLENDING_ENABLED) - { - set_enabled( - gl_context, - Capability::Blend, - draw_props.blending_enabled, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::BLENDING_CONFIG) - { - gl_blending_configure( - gl_context, - GlBlendingConfig::default() - .with_source_factor(blending_factor_to_gl( - draw_props.blending_config.source_factor, - )) - .with_destination_factor(blending_factor_to_gl( - draw_props.blending_config.destination_factor, - )) - .with_equation(blending_equation_to_gl( - draw_props.blending_config.equation, - )), - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::DEPTH_TEST_ENABLED) - { - set_enabled( - gl_context, - Capability::DepthTest, - draw_props.depth_test_enabled, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::DEPTH_FUNCTION) - { - gl_set_depth_function( - gl_context, - match draw_props.depth_function { - DepthFunction::Never => GlDepthFunction::Never, - DepthFunction::Less => GlDepthFunction::Less, - DepthFunction::Equal => GlDepthFunction::Equal, - DepthFunction::LessOrEqual => GlDepthFunction::LessOrEqual, - DepthFunction::Greater => GlDepthFunction::Greater, - DepthFunction::NotEqual => GlDepthFunction::NotEqual, - DepthFunction::GreaterOrEqual => { - GlDepthFunction::GreaterOrEqual - } - DepthFunction::Always => GlDepthFunction::Always, - }, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::SCISSOR_TEST_ENABLED) - { - set_enabled( - gl_context, - Capability::ScissorTest, - draw_props.scissor_test_enabled, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::SCISSOR_BOX) - { - gl_define_scissor_box( - gl_context, - draw_props.scissor_box.lower_left_corner_pos.into(), - draw_props - .scissor_box - .size - .unwrap_or_else(|| { - let (_, viewport_size) = gl_get_viewport(gl_context); - - Dimens::<u16> { - width: viewport_size - .width - .try_into() - .expect("Viewport width too large"), - height: viewport_size - .height - .try_into() - .expect("Viewport height too large"), - } - }) - .into(), - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::FACE_CULLING_ENABLED) - { - set_enabled( - gl_context, - Capability::CullFace, - draw_props.face_culling_enabled, - ); - } + Command::UpdateDrawProperties(properties, update_flags) => { + update_draw_properties( + backend_resources, + object_store, + gl_context, + properties, + update_flags, + ); } } } @@ -1354,6 +1299,221 @@ fn update_texture_object( Ok(()) } +#[tracing::instrument(skip_all)] +fn update_draw_properties( + backend_resources: &BackendResourceStore, + object_store: &ObjectStore, + gl_context: &MaybeCurrentContextWithFns, + properties: DrawProperties, + update_flags: DrawPropertiesUpdateFlags, +) +{ + if update_flags.contains(DrawPropertiesUpdateFlags::POLYGON_MODE_CONFIG) { + opengl_bindings::misc::set_polygon_mode( + gl_context, + properties.polygon_mode_config.face, + properties.polygon_mode_config.mode, + ); + } + + if update_flags.contains(DrawPropertiesUpdateFlags::BLENDING_ENABLED) { + set_enabled(gl_context, Capability::Blend, properties.blending_enabled); + } + + if update_flags.contains(DrawPropertiesUpdateFlags::BLENDING_CONFIG) { + gl_blending_configure( + gl_context, + GlBlendingConfig::default() + .with_source_factor(blending_factor_to_gl( + properties.blending_config.source_factor, + )) + .with_destination_factor(blending_factor_to_gl( + properties.blending_config.destination_factor, + )) + .with_equation(blending_equation_to_gl( + properties.blending_config.equation, + )), + ); + } + + if update_flags.contains(DrawPropertiesUpdateFlags::DEPTH_TEST_ENABLED) { + set_enabled( + gl_context, + Capability::DepthTest, + properties.depth_test_enabled, + ); + } + + if update_flags.contains(DrawPropertiesUpdateFlags::DEPTH_FUNCTION) { + gl_set_depth_function( + gl_context, + match properties.depth_function { + DepthFunction::Never => GlDepthFunction::Never, + DepthFunction::Less => GlDepthFunction::Less, + DepthFunction::Equal => GlDepthFunction::Equal, + DepthFunction::LessOrEqual => GlDepthFunction::LessOrEqual, + DepthFunction::Greater => GlDepthFunction::Greater, + DepthFunction::NotEqual => GlDepthFunction::NotEqual, + DepthFunction::GreaterOrEqual => GlDepthFunction::GreaterOrEqual, + DepthFunction::Always => GlDepthFunction::Always, + }, + ); + } + + if update_flags.contains(DrawPropertiesUpdateFlags::SCISSOR_TEST_ENABLED) { + set_enabled( + gl_context, + Capability::ScissorTest, + properties.scissor_test_enabled, + ); + } + + if update_flags.contains(DrawPropertiesUpdateFlags::SCISSOR_BOX) { + gl_define_scissor_box( + gl_context, + properties.scissor_box.lower_left_corner_pos.into(), + properties + .scissor_box + .size + .unwrap_or_else(|| { + let (_, viewport_size) = gl_get_viewport(gl_context); + + Dimens::<u16> { + width: viewport_size + .width + .try_into() + .expect("Viewport width too large"), + height: viewport_size + .height + .try_into() + .expect("Viewport height too large"), + } + }) + .into(), + ); + } + + if update_flags.contains(DrawPropertiesUpdateFlags::FACE_CULLING_ENABLED) { + set_enabled( + gl_context, + Capability::CullFace, + properties.face_culling_enabled, + ); + } + + 'if_draw_fb: { + if update_flags.contains(DrawPropertiesUpdateFlags::DRAW_FRAMEBUFFER) { + let Some(framebuffer_obj_id) = properties.draw_framebuffer else { + gl_bind_framebuffer(gl_context, GlFramebufferTarget::Draw, None); + break 'if_draw_fb; + }; + + let Some(framebuffer_resource) = backend_resources.get_resource( + object_store, + framebuffer_obj_id, + ObjectKind::Framebuffer, + ) else { + break 'if_draw_fb; + }; + + let BackendResource::Framebuffer { framebuffer } = framebuffer_resource + else { + unreachable!(); + }; + + gl_bind_framebuffer(gl_context, GlFramebufferTarget::Draw, Some(framebuffer)); + } + } + + 'if_read_fb: { + if update_flags.contains(DrawPropertiesUpdateFlags::READ_FRAMEBUFFER) { + let Some(framebuffer_obj_id) = properties.read_framebuffer else { + gl_bind_framebuffer(gl_context, GlFramebufferTarget::Read, None); + break 'if_read_fb; + }; + + let Some(framebuffer_resource) = backend_resources.get_resource( + object_store, + framebuffer_obj_id, + ObjectKind::Framebuffer, + ) else { + break 'if_read_fb; + }; + + let BackendResource::Framebuffer { framebuffer } = framebuffer_resource + else { + unreachable!(); + }; + + gl_bind_framebuffer(gl_context, GlFramebufferTarget::Read, Some(framebuffer)); + } + } +} + +#[tracing::instrument(skip_all)] +fn update_framebuffer_properties( + backend_resources: &BackendResourceStore, + object_store: &ObjectStore, + current_context: &MaybeCurrentContextWithFns, + framebuffer_object_id: ObjectId, + properties: FramebufferProperties, + update_flags: FramebufferPropertiesUpdateFlags, +) +{ + let Some(resource) = backend_resources.get_resource( + object_store, + framebuffer_object_id, + ObjectKind::Framebuffer, + ) else { + return; + }; + + let BackendResource::Framebuffer { framebuffer } = resource else { + unreachable!(); + }; + + 'if_dt: { + if update_flags.contains(FramebufferPropertiesUpdateFlags::DEPTH_TEXTURE) { + let Some(framebuffer_depth_texture) = &properties.depth_texture else { + framebuffer + .detach_texture(current_context, GlFramebufferAttachment::Depth); + + break 'if_dt; + }; + + let Some(depth_texture_resource) = backend_resources.get_resource( + object_store, + framebuffer_depth_texture.object_id, + ObjectKind::Texture, + ) else { + break 'if_dt; + }; + + let BackendResource::Texture { texture: depth_texture, .. } = + depth_texture_resource + else { + unreachable!(); + }; + + framebuffer.attach_texture( + current_context, + GlFramebufferAttachment::Depth, + depth_texture.clone(), + framebuffer_depth_texture.mipmap_level, + ); + } + } + + if update_flags.contains(FramebufferPropertiesUpdateFlags::COLOR_DRAW_BUFFER) { + framebuffer.set_draw_buffer( + current_context, + properties.color_draw_buffer.map(|color_texture_index| { + GlFramebufferColorAttachment(color_texture_index.0) + }), + ); + } +} + fn draw_mesh( current_context: &MaybeCurrentContextWithFns, graphics_mesh: &GraphicsMesh, diff --git a/engine/src/rendering/object.rs b/engine/src/rendering/object.rs index 012a65e..c26b945 100644 --- a/engine/src/rendering/object.rs +++ b/engine/src/rendering/object.rs @@ -119,4 +119,5 @@ pub enum Kind Texture, ShaderProgram, Mesh, + Framebuffer, } |
