summaryrefslogtreecommitdiff
path: root/engine/src/rendering/backend
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/rendering/backend')
-rw-r--r--engine/src/rendering/backend/opengl.rs164
-rw-r--r--engine/src/rendering/backend/opengl/graphics_mesh.rs185
2 files changed, 243 insertions, 106 deletions
diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs
index 12aaaf0..0dfe960 100644
--- a/engine/src/rendering/backend/opengl.rs
+++ b/engine/src/rendering/backend/opengl.rs
@@ -47,7 +47,6 @@ use opengl_bindings::shader::{
Kind as ShaderKind,
Program as GlShaderProgram,
Shader as GlShader,
- // UniformLocation as GlUniformLocation,
};
use opengl_bindings::texture::{
ColorSpace as GlTextureColorSpace,
@@ -101,9 +100,9 @@ use crate::rendering::shader::cursor::{
BindingValue as ShaderBindingValue,
};
use crate::rendering::shader::{
- Context as ShaderContext,
Error as ShaderError,
Program as ShaderProgram,
+ ProgramMetadata as ShaderProgramMetadata,
Stage as ShaderStage,
};
use crate::rendering::{
@@ -173,7 +172,12 @@ enum GraphicsContextObject
Mesh
{
mesh: GraphicsMesh,
- compatible_shader_program_obj_id: ObjectId,
+ vertex_attrs_updated_for_shader: Option<ObjectId>,
+ },
+ Shader
+ {
+ program: GlShaderProgram,
+ program_metadata: ShaderProgramMetadata,
},
}
@@ -443,7 +447,6 @@ fn handle_commands(
mut object_store: Single<ObjectStore>,
mut command_queue: Single<CommandQueue>,
assets: Single<Assets>,
- shader_context: Single<ShaderContext>,
) -> Result<(), crate::Error>
{
let Ok(graphics_ctx) = graphics_ctx.get_mut() else {
@@ -453,7 +456,6 @@ fn handle_commands(
let object_store = object_store.get_mut()?;
let command_queue = command_queue.get_mut()?;
let assets = assets.get()?;
- let shader_context = shader_context.get()?;
let GraphicsContext {
ref gl_context,
@@ -467,7 +469,11 @@ fn handle_commands(
return Ok(());
};
- let mut activated_gl_shader_program: Option<(ObjectId, GlShaderProgram)> = None;
+ let mut activated_gl_shader_program: Option<(
+ ObjectId,
+ GlShaderProgram,
+ ShaderProgramMetadata,
+ )> = None;
for command in command_queue.drain() {
let tracing_span = tracing::info_span!(
@@ -593,35 +599,80 @@ fn handle_commands(
}
};
+ let key = *next_graphics_ctx_object_key;
+
+ graphics_ctx_objects.insert(
+ key,
+ GraphicsContextObject::Shader {
+ program: gl_shader_program,
+ program_metadata: shader_program.metadata().clone(),
+ },
+ );
+
object_store.insert(
shader_program_obj_id,
- Object::from_raw(
- gl_shader_program.into_raw(),
- ObjectKind::ShaderProgram,
- ),
+ Object::from_raw(key, ObjectKind::ShaderProgram),
);
+
+ *next_graphics_ctx_object_key += 1;
}
Command::ActivateShader(shader_program_obj_id) => {
let Some(shader_program_obj) =
- object_store.get_shader_program_obj(&shader_program_obj_id)
+ object_store.get_obj(&shader_program_obj_id)
else {
- tracing::error!("Shader object does not exist or has a wrong kind");
+ tracing::error!(
+ object_id = ?shader_program_obj_id,
+ "Object does not exist"
+ );
+
continue;
};
- let gl_shader_program =
- GlShaderProgram::from_raw(shader_program_obj.as_raw());
+ if shader_program_obj.kind() != ObjectKind::ShaderProgram {
+ tracing::error!(
+ object_id = ?shader_program_obj_id,
+ actual_kind = ?shader_program_obj.kind(),
+ "Invalid object kind: not a shader program"
+ );
- gl_shader_program.activate(gl_context);
+ continue;
+ }
+
+ let key = shader_program_obj.as_raw();
- activated_gl_shader_program =
- Some((shader_program_obj_id, gl_shader_program));
+ let Some(graphics_ctx_obj) = graphics_ctx_objects.get(&key) else {
+ tracing::error!(
+ object_id = ?shader_program_obj_id,
+ key = key,
+ "Object not found in graphics context object store"
+ );
+ continue;
+ };
+
+ let GraphicsContextObject::Shader { program, program_metadata } =
+ graphics_ctx_obj
+ else {
+ tracing::error!(
+ object_id = ?shader_program_obj_id,
+ key = key,
+ "Graphics context object is not a shader"
+ );
+ continue;
+ };
+
+ program.activate(gl_context);
+
+ activated_gl_shader_program = Some((
+ shader_program_obj_id,
+ program.clone(),
+ program_metadata.clone(),
+ ));
}
Command::SetShaderBinding(ShaderBinding {
location: binding_location,
value: binding_value,
}) => {
- let Some((activated_gl_shader_program_obj_id, _)) =
+ let Some((activated_gl_shader_program_obj_id, _, _)) =
&activated_gl_shader_program
else {
tracing::error!("No shader program is activated");
@@ -786,24 +837,6 @@ fn handle_commands(
continue;
}
- let Some((ObjectId::Asset(curr_shader_program_asset_id), _)) =
- &activated_gl_shader_program
- else {
- tracing::error!("No shader program is activated");
- continue;
- };
-
- let curr_shader_program_metadata = shader_context
- .get_program_metadata(curr_shader_program_asset_id)
- .expect("Not possible");
-
- let Some(vertex_desc) = &curr_shader_program_metadata.vertex_desc else {
- tracing::error!(
- "Current shader program does not have a vertex description"
- );
- continue;
- };
-
let key = *next_graphics_ctx_object_key;
let mesh = match &mesh {
@@ -821,12 +854,8 @@ fn handle_commands(
AssetOrValue::Value(mesh) => mesh,
};
- let graphics_mesh = match GraphicsMesh::new(
- gl_context,
- &mesh,
- mesh_usage,
- &vertex_desc,
- ) {
+ let graphics_mesh = match GraphicsMesh::new(gl_context, &mesh, mesh_usage)
+ {
Ok(graphics_mesh) => graphics_mesh,
Err(err) => {
tracing::error!("Failed to create mesh: {err}");
@@ -838,9 +867,7 @@ fn handle_commands(
key,
GraphicsContextObject::Mesh {
mesh: graphics_mesh,
- compatible_shader_program_obj_id: ObjectId::Asset(
- *curr_shader_program_asset_id,
- ),
+ vertex_attrs_updated_for_shader: None,
},
);
@@ -881,7 +908,7 @@ fn handle_commands(
#[allow(irrefutable_let_patterns)]
let GraphicsContextObject::Mesh {
mesh: graphics_mesh,
- compatible_shader_program_obj_id: _,
+ vertex_attrs_updated_for_shader: _,
} = mesh_graphics_ctx_obj
else {
tracing::error!(
@@ -947,7 +974,7 @@ fn handle_commands(
};
let Some(mesh_graphics_ctx_obj) =
- graphics_ctx_objects.get(&mesh_graphics_ctx_obj_key)
+ graphics_ctx_objects.get_mut(&mesh_graphics_ctx_obj_key)
else {
tracing::error!(
object_id=?mesh_object_id,
@@ -957,10 +984,9 @@ fn handle_commands(
continue;
};
- #[allow(irrefutable_let_patterns)]
let GraphicsContextObject::Mesh {
mesh: graphics_mesh,
- compatible_shader_program_obj_id,
+ vertex_attrs_updated_for_shader,
} = mesh_graphics_ctx_obj
else {
tracing::error!(
@@ -971,18 +997,36 @@ fn handle_commands(
continue;
};
- if Some(compatible_shader_program_obj_id)
- != activated_gl_shader_program.as_ref().map(
- |(activated_gl_shader_program_obj_id, _)| {
- activated_gl_shader_program_obj_id
- },
- )
- {
- tracing::error!(concat!(
- "Activated shader program is not the ",
- "compatible shader program of the mesh"
- ));
+ let Some((shader_program_obj_id, _, shader_program_metadata)) =
+ &activated_gl_shader_program
+ else {
+ tracing::error!("No shader program is activated");
continue;
+ };
+
+ if vertex_attrs_updated_for_shader.is_none_or(
+ |vertex_attrs_updated_for_shader| {
+ vertex_attrs_updated_for_shader != *shader_program_obj_id
+ },
+ ) {
+ let Some(shader_program_vertex_desc) =
+ &shader_program_metadata.vertex_desc
+ else {
+ tracing::error!(
+ "Activated shader program does not have a vertex description"
+ );
+ continue;
+ };
+
+ if let Err(err) = graphics_mesh.update_vertex_attrs_for_shader(
+ gl_context,
+ shader_program_vertex_desc,
+ ) {
+ tracing::error!("Cannot draw mesh: {err}");
+ continue;
+ }
+
+ *vertex_attrs_updated_for_shader = Some(*shader_program_obj_id);
}
if let Err(err) = draw_mesh(gl_context, graphics_mesh, &draw_mesh_opts) {
diff --git a/engine/src/rendering/backend/opengl/graphics_mesh.rs b/engine/src/rendering/backend/opengl/graphics_mesh.rs
index 6d5c248..a1c903b 100644
--- a/engine/src/rendering/backend/opengl/graphics_mesh.rs
+++ b/engine/src/rendering/backend/opengl/graphics_mesh.rs
@@ -1,3 +1,5 @@
+use std::hint::cold_path;
+
use opengl_bindings::buffer::{Buffer as GlBuffer, Usage as GlBufferUsage};
use opengl_bindings::vertex_array::{
AttributeFormat as GlVertexArrayAttributeFormat,
@@ -8,15 +10,20 @@ use opengl_bindings::vertex_array::{
};
use opengl_bindings::MaybeCurrentContextWithFns as GlCurrentContextWithFns;
+use crate::mesh::vertex_buffer::VertexAttrProperties as MeshVertexAttrProperties;
use crate::mesh::{Mesh, VertexAttrType};
use crate::rendering::shader::VertexDescription as ShaderVertexDescription;
use crate::rendering::MeshUsage;
+const VERTEX_BUF_BINDING_INDEX: u32 = 0;
+
#[derive(Debug)]
pub struct GraphicsMesh
{
/// Vertex and index buffer has to live as long as the vertex array
vertex_buffer: GlBuffer<u8>,
+ vertex_attr_props: Vec<MeshVertexAttrProperties>,
+ last_used_vertex_attr_cnt: u32,
pub index_buffer: Option<GlBuffer<u32>>,
pub element_cnt: u32,
pub vertex_arr: GlVertexArray,
@@ -29,7 +36,6 @@ impl GraphicsMesh
current_context: &GlCurrentContextWithFns,
mesh: &Mesh,
mesh_usage: MeshUsage,
- vertex_desc: &ShaderVertexDescription,
) -> Result<Self, Error>
{
let buffer_usage = mesh_usage_to_gl_buffer_usage(mesh_usage);
@@ -41,11 +47,9 @@ impl GraphicsMesh
.store(current_context, mesh.vertex_buf().as_bytes(), buffer_usage)
.map_err(Error::StoreVerticesFailed)?;
- let vertex_buf_binding_index = 0;
-
if let Err(err) = vertex_arr.bind_vertex_buffer(
current_context,
- vertex_buf_binding_index,
+ VERTEX_BUF_BINDING_INDEX,
&vertex_buffer,
GlVertexArrayVertexBufferSpec {
offset: 0,
@@ -69,48 +73,6 @@ impl GraphicsMesh
}
}
- for vertex_attr_props in mesh.vertex_buf().vertex_attr_props() {
- let vertex_field_desc = vertex_desc
- .fields
- .iter()
- .find(|vertex_field_desc| {
- *vertex_field_desc.name == vertex_attr_props.name
- })
- .unwrap();
-
- let attrib_index: u32 =
- vertex_field_desc.varying_input_offset.try_into().unwrap();
-
- vertex_arr.enable_attrib(current_context, attrib_index);
-
- vertex_arr.set_attrib_format(
- current_context,
- attrib_index,
- match &vertex_attr_props.ty {
- VertexAttrType::Float32 => GlVertexArrayAttributeFormat {
- data_type: GlVertexArrayDataType::Float,
- count: 1,
- normalized: false,
- offset: vertex_attr_props.byte_offset.try_into().unwrap(),
- },
- VertexAttrType::Float32Array { length } => {
- GlVertexArrayAttributeFormat {
- data_type: GlVertexArrayDataType::Float,
- count: (*length).try_into().unwrap(),
- normalized: false,
- offset: vertex_attr_props.byte_offset.try_into().unwrap(),
- }
- }
- },
- );
-
- vertex_arr.set_attrib_vertex_buf_binding(
- current_context,
- attrib_index,
- vertex_buf_binding_index,
- );
- }
-
if let Some(indices) = mesh.indices() {
let index_buffer = GlBuffer::new(current_context);
@@ -122,6 +84,8 @@ impl GraphicsMesh
return Ok(Self {
vertex_buffer: vertex_buffer,
+ vertex_attr_props: mesh.vertex_buf().vertex_attr_props().to_vec(),
+ last_used_vertex_attr_cnt: 0,
index_buffer: Some(index_buffer),
element_cnt: indices
.len()
@@ -133,6 +97,8 @@ impl GraphicsMesh
Ok(Self {
vertex_buffer: vertex_buffer,
+ vertex_attr_props: mesh.vertex_buf().vertex_attr_props().to_vec(),
+ last_used_vertex_attr_cnt: 0,
index_buffer: None,
element_cnt: mesh
.vertex_buf()
@@ -185,6 +151,113 @@ impl GraphicsMesh
Ok(())
}
+ pub fn update_vertex_attrs_for_shader(
+ &mut self,
+ curr_gl_ctx: &GlCurrentContextWithFns,
+ shader_vertex_desc: &ShaderVertexDescription,
+ ) -> Result<(), VertexAttrsUpdatingError>
+ {
+ let vertex_field_desc_cnt = u32::try_from(shader_vertex_desc.fields.len())
+ .expect("Shader has too many vertex fields. Count does not fit into u32");
+
+ if self.last_used_vertex_attr_cnt > vertex_field_desc_cnt {
+ for index in vertex_field_desc_cnt..self.last_used_vertex_attr_cnt {
+ self.vertex_arr.disable_attrib(curr_gl_ctx, index);
+ }
+ }
+
+ let mut used_vertex_attr_cnt = 0u32;
+
+ let mut last_attr_index: Option<u32> = None;
+
+ for vertex_attr_props in &self.vertex_attr_props {
+ let Some(vertex_field_desc) =
+ shader_vertex_desc.fields.iter().find(|vertex_field_desc| {
+ *vertex_field_desc.name == vertex_attr_props.name
+ })
+ else {
+ continue;
+ };
+
+ let attrib_index: u32 =
+ vertex_field_desc.varying_input_offset.try_into().unwrap();
+
+ if let Some(last_attr_index) = last_attr_index {
+ if last_attr_index.wrapping_add(1) != attrib_index {
+ cold_path();
+ return Err(
+ VertexAttrsUpdatingError::VertexAttrIndicesNotConsecutive,
+ );
+ }
+ } else if attrib_index != 0 {
+ cold_path();
+ return Err(VertexAttrsUpdatingError::FirstVertexAttrIndexNotZero {
+ vertex_attr_name: vertex_attr_props.name.to_string().into_boxed_str(),
+ unexpected_index: attrib_index,
+ });
+ }
+
+ last_attr_index = Some(attrib_index);
+
+ self.vertex_arr.enable_attrib(curr_gl_ctx, attrib_index);
+
+ self.vertex_arr.set_attrib_format(
+ curr_gl_ctx,
+ attrib_index,
+ match &vertex_attr_props.ty {
+ VertexAttrType::Float32 => GlVertexArrayAttributeFormat {
+ data_type: GlVertexArrayDataType::Float,
+ count: 1,
+ normalized: false,
+ offset: vertex_attr_props.byte_offset.try_into().unwrap(),
+ },
+ VertexAttrType::Float32Array { length } => {
+ GlVertexArrayAttributeFormat {
+ data_type: GlVertexArrayDataType::Float,
+ count: (*length).try_into().unwrap(),
+ normalized: false,
+ offset: vertex_attr_props.byte_offset.try_into().unwrap(),
+ }
+ }
+ },
+ );
+
+ self.vertex_arr.set_attrib_vertex_buf_binding(
+ curr_gl_ctx,
+ attrib_index,
+ VERTEX_BUF_BINDING_INDEX,
+ );
+
+ used_vertex_attr_cnt += 1;
+ }
+
+ self.last_used_vertex_attr_cnt = used_vertex_attr_cnt;
+
+ if used_vertex_attr_cnt as usize != shader_vertex_desc.fields.len() {
+ cold_path();
+
+ return Err(VertexAttrsUpdatingError::MissingVertexAttrs(
+ shader_vertex_desc
+ .fields
+ .iter()
+ .filter_map(|vertex_field_desc| {
+ if self
+ .vertex_attr_props
+ .iter()
+ .any(|prop| prop.name == *vertex_field_desc.name)
+ {
+ return None;
+ }
+
+ Some(vertex_field_desc.name.clone())
+ })
+ .collect(),
+ ));
+ }
+
+ Ok(())
+ }
+
pub fn destroy(&mut self, curr_gl_ctx: &GlCurrentContextWithFns)
{
self.vertex_arr.delete(curr_gl_ctx);
@@ -206,6 +279,26 @@ pub enum Error
StoreIndicesFailed(#[source] opengl_bindings::buffer::Error),
}
+#[derive(Debug, thiserror::Error)]
+pub enum VertexAttrsUpdatingError
+{
+ #[error("Mesh is missing vertex attribute(s) required by shader: {0:?}")]
+ MissingVertexAttrs(Vec<Box<str>>),
+
+ #[error("Shader's vertex attribute indices are not consecutive")]
+ VertexAttrIndicesNotConsecutive,
+
+ #[error(
+ "Shader's first vertex attribute ({vertex_attr_name}) index is not 0, is {}",
+ unexpected_index
+ )]
+ FirstVertexAttrIndexNotZero
+ {
+ vertex_attr_name: Box<str>,
+ unexpected_index: u32,
+ },
+}
+
fn mesh_usage_to_gl_buffer_usage(mesh_usage: MeshUsage) -> GlBufferUsage
{
match mesh_usage {