summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/src/rendering.rs48
-rw-r--r--engine/src/rendering/backend/opengl.rs390
-rw-r--r--engine/src/rendering/object.rs1
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,
}