diff options
Diffstat (limited to 'engine/src/rendering/backend/opengl.rs')
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 691 |
1 files changed, 313 insertions, 378 deletions
diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index 2ee4a1a..755388c 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -130,7 +130,7 @@ use crate::texture::{ Texture, Wrapping as TextureWrapping, }; -use crate::util::OptionExt; +use crate::util::{MapVec, OptionExt}; use crate::vector::{Vec2, Vec3}; use crate::windowing::dpi::PhysicalSize; use crate::windowing::window::{ @@ -157,10 +157,189 @@ struct GraphicsContext surfaces: HashMap<SurfaceId, GraphicsContextSurface>, shader_uniform_buffer_objs: HashMap<ObjectId, HashMap<u32, opengl_bindings::buffer::Buffer<u8>>>, - objects: HashMap<ObjectRawValue, GraphicsContextObject>, - next_object_key: ObjectRawValue, + backend_resources: BackendResourceStore, } +#[derive(Debug, Default)] +struct BackendResourceStore +{ + inner: MapVec<BackendResourceId, BackendResource>, + next_id: BackendResourceId, +} + +impl BackendResourceStore +{ + fn try_create_resource<Err>( + &mut self, + object_store: &mut ObjectStore, + object_id: ObjectId, + resource_fn: impl FnOnce() -> Result<BackendResource, Err>, + ) -> Result<(), Err> + { + if object_store.contains_non_pending_with_id(&object_id) { + cold_path(); + tracing::error!( + ?object_id, + "Object store already contains a object with this ID" + ); + return Ok(()); + } + + let resource = resource_fn()?; + + let res_id = self.next_id; + + self.next_id.0 += 1; + + let object_kind = resource.object_kind(); + + self.inner.insert(res_id, resource); + + object_store.insert(object_id, Object::from_raw(res_id.0, object_kind)); + + Ok(()) + } + + fn get_resource( + &self, + object_store: &ObjectStore, + object_id: ObjectId, + object_kind: ObjectKind, + ) -> Option<&BackendResource> + { + let Some(object) = object_store.get_obj(&object_id) else { + cold_path(); + tracing::error!( + ?object_id, + "Object does not exist in the rendering object store" + ); + return None; + }; + + if object.kind() != object_kind { + cold_path(); + tracing::error!( + ?object_id, + expected_object_kind = ?object_kind, + found_object_kind = ?object.kind(), + "Unexpected object kind" + ); + return None; + } + + let resource_id = BackendResourceId(object.as_raw()); + + let Some(resource) = self.inner.get(&resource_id) else { + cold_path(); + tracing::error!(?object_id, ?resource_id, "Backend resource does not exist"); + return None; + }; + + if resource.object_kind() != object_kind { + cold_path(); + tracing::error!( + ?object_id, + ?resource_id, + "Backend resource has wrong associated object kind" + ); + return None; + } + + Some(resource) + } + + fn get_resource_mut( + &mut self, + object_store: &ObjectStore, + object_id: ObjectId, + object_kind: ObjectKind, + ) -> Option<&mut BackendResource> + { + let Some(object) = object_store.get_obj(&object_id) else { + cold_path(); + tracing::error!( + ?object_id, + "Object does not exist in the rendering object store" + ); + return None; + }; + + if object.kind() != object_kind { + cold_path(); + tracing::error!( + ?object_id, + expected_object_kind = ?object_kind, + found_object_kind = ?object.kind(), + "Unexpected object kind" + ); + return None; + } + + let resource_id = BackendResourceId(object.as_raw()); + + let Some(resource) = self.inner.get_mut(&resource_id) else { + cold_path(); + tracing::error!(?object_id, ?resource_id, "Backend resource does not exist"); + return None; + }; + + if resource.object_kind() != object_kind { + cold_path(); + tracing::error!( + ?object_id, + ?resource_id, + "Backend resource has wrong associated object kind" + ); + return None; + } + + Some(resource) + } + + fn remove_resource( + &mut self, + object_store: &mut ObjectStore, + object_id: ObjectId, + object_kind: ObjectKind, + curr_gl_ctx: &MaybeCurrentContextWithFns, + ) + { + if let Some(object) = object_store.get_obj(&object_id) { + if object.kind() != object_kind { + cold_path(); + tracing::error!( + ?object_id, + expected_object_kind = ?object_kind, + found_object_kind = ?object.kind(), + "Unexpected object kind" + ); + return; + } + } + + let Some(object) = object_store.remove(&object_id).flatten() else { + tracing::error!( + ?object_id, + "Object does not exist in the rendering object store" + ); + return; + }; + + let resource_id = BackendResourceId(object.as_raw()); + + let Some(resource) = self.inner.remove(resource_id) else { + cold_path(); + tracing::error!(?object_id, ?resource_id, "Backend resource does not exist"); + return; + }; + + resource.destroy(curr_gl_ctx); + } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +struct BackendResourceId(ObjectRawValue); + #[derive(Debug)] struct GraphicsContextSurface { @@ -169,7 +348,7 @@ struct GraphicsContextSurface } #[derive(Debug)] -enum GraphicsContextObject +enum BackendResource { Mesh { @@ -189,6 +368,33 @@ enum GraphicsContextObject }, } +impl BackendResource +{ + fn object_kind(&self) -> ObjectKind + { + match self { + Self::Mesh { .. } => ObjectKind::ImplementationSpecific, + Self::Shader { .. } => ObjectKind::ShaderProgram, + Self::Texture { .. } => ObjectKind::Texture, + } + } + + fn destroy(&self, curr_gl_ctx: &MaybeCurrentContextWithFns) + { + match self { + Self::Mesh { mesh, .. } => { + mesh.destroy(curr_gl_ctx); + } + Self::Shader { program, .. } => { + program.clone().delete(curr_gl_ctx); + } + Self::Texture { texture, .. } => { + texture.clone().delete(curr_gl_ctx); + } + } + } +} + #[derive(Debug)] enum TextureKind { @@ -482,8 +688,7 @@ fn handle_commands( ref gl_context, ref mut surfaces, ref mut shader_uniform_buffer_objs, - objects: ref mut graphics_ctx_objects, - next_object_key: ref mut next_graphics_ctx_object_key, + ref mut backend_resources, } = *graphics_ctx; let Some(gl_context) = gl_context else { @@ -599,95 +804,43 @@ fn handle_commands( tracing::error!("Failed to swap buffers: {err}"); } } - Command::CreateShaderProgram(shader_program_obj_id, shader_program) => { - if object_store.contains_non_pending_with_id(&shader_program_obj_id) { - tracing::error!( - shader_program_object_id=?shader_program_obj_id, - shader_asset_label=?shader_program_obj_id - .into_asset_id() - .and_then(|asset_id| assets.get_label_by_id(asset_id)), - "Object store already contains a object with this ID" - ); - continue; + Command::CreateShaderProgram(object_id, shader_program) => { + if let Err(err) = backend_resources + .try_create_resource::<CreateShaderError>( + object_store, + object_id, + || { + Ok(BackendResource::Shader { + program: create_shader_program( + gl_context, + &shader_program, + )?, + program_metadata: shader_program.metadata().clone(), + }) + }, + ) + { + tracing::error!("Failed to create shader program: {err}"); } - - let gl_shader_program = - match create_shader_program(gl_context, &shader_program) { - Ok(gl_shader_program) => gl_shader_program, - Err(err) => { - tracing::error!("Failed to create shader program: {err}"); - continue; - } - }; - - 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(key, ObjectKind::ShaderProgram), - ); - - *next_graphics_ctx_object_key += 1; } - Command::ActivateShader(shader_program_obj_id) => { - let Some(shader_program_obj) = - object_store.get_obj(&shader_program_obj_id) - else { - tracing::error!( - object_id = ?shader_program_obj_id, - "Object does not exist" - ); - + Command::ActivateShader(object_id) => { + let Some(resource) = backend_resources.get_resource( + object_store, + object_id, + ObjectKind::ShaderProgram, + ) else { continue; }; - 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" - ); - - continue; - } - - let key = shader_program_obj.as_raw(); - - 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 + let BackendResource::Shader { program, program_metadata } = resource else { - tracing::error!( - object_id = ?shader_program_obj_id, - key = key, - "Graphics context object is not a shader" - ); - continue; + unreachable!(); }; program.activate(gl_context); - activated_gl_shader_program = Some(( - shader_program_obj_id, - program.clone(), - program_metadata.clone(), - )); + activated_gl_shader_program = + Some((object_id, program.clone(), program_metadata.clone())); } Command::SetShaderBinding(ShaderBinding { location: binding_location, @@ -702,47 +855,18 @@ fn handle_commands( if let ShaderBindingValue::Texture(texture_object_id, _) = &binding_value { - let Some(texture_obj) = object_store.get_obj(texture_object_id) - else { - tracing::error!( - texture_object_id = ?texture_object_id, - "Texture object does not exist in rendering object store", - ); - + let Some(texture_resource) = backend_resources.get_resource( + object_store, + *texture_object_id, + ObjectKind::Texture, + ) else { continue; }; - if texture_obj.kind() != ObjectKind::Texture { - tracing::error!( - texture_object_id = ?texture_object_id, - "Object in rendering object store is not a texture", - ); - - continue; - } - - let Some(texture_graphics_ctx_obj) = - graphics_ctx_objects.get(&texture_obj.as_raw()) + let BackendResource::Texture { texture: gl_texture, .. } = + texture_resource else { - cold_path(); - tracing::error!( - ?texture_object_id, - key = texture_obj.as_raw(), - "Graphics context does not contain a object with this key" - ); - continue; - }; - - let GraphicsContextObject::Texture { texture: gl_texture, .. } = - texture_graphics_ctx_obj - else { - cold_path(); - tracing::error!( - ?texture_object_id, - key = texture_obj.as_raw(), - "Graphics context object with this key is not a texture" - ); - continue; + unreachable!(); }; gl_texture @@ -829,38 +953,22 @@ fn handle_commands( ) .unwrap(); } - Command::CreateTexture(texture_object_id, texture) => { - if object_store.contains_non_pending_with_id(&texture_object_id) { - tracing::error!( - texture_object_id=?texture_object_id, - "Object store already contains object with this ID" - ); - continue; - } - - let Ok((gl_texture, texture_pixel_data_format, texture_kind)) = - create_texture_object(gl_context, assets, texture) - else { - continue; - }; - - let key = *next_graphics_ctx_object_key; - - graphics_ctx_objects.insert( - key, - GraphicsContextObject::Texture { - texture: gl_texture, - pixel_data_format: texture_pixel_data_format, - metadata: texture_kind, + Command::CreateTexture(object_id, texture) => { + let _ = backend_resources.try_create_resource::<()>( + object_store, + object_id, + || { + let (gl_texture, texture_pixel_data_format, texture_kind) = + create_texture_object(gl_context, assets, texture) + .map_err(|_| ())?; + + Ok(BackendResource::Texture { + texture: gl_texture, + pixel_data_format: texture_pixel_data_format, + metadata: texture_kind, + }) }, ); - - object_store.insert( - texture_object_id, - Object::from_raw(key, ObjectKind::Texture), - ); - - *next_graphics_ctx_object_key += 1; } Command::UpdateTexture { obj_id, @@ -868,49 +976,21 @@ fn handle_commands( pixel_data_format, update, } => { - let Some(texture_obj) = object_store.get_obj(&obj_id) else { - cold_path(); - tracing::error!( - texture_object_id=?obj_id, - "Object store does not contain a object with this ID" - ); - continue; - }; - - if texture_obj.kind() != ObjectKind::Texture { - cold_path(); - tracing::error!( - texture_object_id=?obj_id, - "Object with this ID is not a texture" - ); - continue; - } - - let Some(texture_graphics_ctx_obj) = - graphics_ctx_objects.get(&texture_obj.as_raw()) - else { - cold_path(); - tracing::error!( - texture_object_id=?obj_id, - key=texture_obj.as_raw(), - "Graphics context does not contain a object with this key" - ); + let Some(texture_resource) = backend_resources.get_resource( + object_store, + obj_id, + ObjectKind::Texture, + ) else { continue; }; - let GraphicsContextObject::Texture { + let BackendResource::Texture { texture: gl_texture, pixel_data_format: tex_pixel_data_format, metadata: tex_metadata, - } = texture_graphics_ctx_obj + } = texture_resource else { - cold_path(); - tracing::error!( - object_id=?obj_id, - key=texture_obj.as_raw(), - "Graphics context object with this key is not a texture" - ); - continue; + unreachable!(); }; if !matches!( @@ -920,7 +1000,6 @@ fn handle_commands( ) { tracing::error!( texture_object_id = ?obj_id, - key = texture_obj.as_raw(), "Texture is of incorrect kind" ); continue; @@ -930,7 +1009,6 @@ fn handle_commands( cold_path(); tracing::error!( texture_object_id = ?obj_id, - key = texture_obj.as_raw(), expected_pixel_data_format = ?*tex_pixel_data_format, found_pixel_data_format = ?pixel_data_format, "Texture has incorrect pixel data format" @@ -948,72 +1026,15 @@ fn handle_commands( tracing::error!("Failed to update texture object: {err}"); } } - Command::RemoveTexture(texture_object_id) => { - if let Some(obj) = object_store.get_obj(&texture_object_id) { - if obj.kind() != ObjectKind::Texture { - cold_path(); - tracing::error!( - ?texture_object_id, - "Object with this ID is not a texture" - ); - continue; - } - } - - let Some(texture_object) = - object_store.remove(&texture_object_id).flatten() - else { - tracing::error!( - texture_object_id=?texture_object_id, - "Object store does not contain a object with this ID" - ); - continue; - }; - - let Some(texture_graphics_ctx_obj) = - graphics_ctx_objects.remove(&texture_object.as_raw()) - else { - cold_path(); - tracing::error!( - ?texture_object_id, - key = texture_object.as_raw(), - "Graphics context does not contain a object with this key" - ); - continue; - }; - - let GraphicsContextObject::Texture { texture: gl_texture, .. } = - texture_graphics_ctx_obj - else { - cold_path(); - tracing::error!( - object_id = ?texture_object_id, - key = texture_object.as_raw(), - "Graphics context object with this key is not a texture" - ); - continue; - }; - - gl_texture.delete(gl_context); + Command::RemoveTexture(object_id) => { + backend_resources.remove_resource( + object_store, + object_id, + ObjectKind::Texture, + gl_context, + ); } - Command::CreateMesh { - obj_id: mesh_object_id, - mesh, - usage: mesh_usage, - } => { - if object_store.contains_non_pending_with_id(&mesh_object_id) { - tracing::error!( - mesh_object_id=?mesh_object_id, - mesh_asset_label=?mesh_object_id - .into_asset_id() - .and_then(|asset_id| assets.get_label_by_id(asset_id)), - "Object store already contains a object with this ID" - ); - continue; - } - - let key = *next_graphics_ctx_object_key; - + Command::CreateMesh { obj_id, mesh, usage: mesh_usage } => { let mesh = match &mesh { AssetOrValue::Asset(mesh_asset) => { let Some(mesh) = assets.get(&mesh_asset) else { @@ -1029,147 +1050,61 @@ fn handle_commands( AssetOrValue::Value(mesh) => mesh, }; - let graphics_mesh = match GraphicsMesh::new(gl_context, &mesh, mesh_usage) + if let Err(err) = backend_resources + .try_create_resource::<graphics_mesh::Error>( + object_store, + obj_id, + || { + Ok(BackendResource::Mesh { + mesh: GraphicsMesh::new(gl_context, &mesh, mesh_usage)?, + vertex_attrs_updated_for_shader: None, + }) + }, + ) { - Ok(graphics_mesh) => graphics_mesh, - Err(err) => { - tracing::error!("Failed to create mesh: {err}"); - continue; - } - }; - - graphics_ctx_objects.insert( - key, - GraphicsContextObject::Mesh { - mesh: graphics_mesh, - vertex_attrs_updated_for_shader: None, - }, - ); - - object_store.insert( - mesh_object_id, - Object::from_raw(key, ObjectKind::ImplementationSpecific), - ); - - *next_graphics_ctx_object_key += 1; + tracing::error!("Failed to create mesh: {err}"); + } } - Command::UpdateMesh { - obj_id: mesh_object_id, - mesh, - usage: mesh_usage, - } => { - let Some(mesh_graphics_ctx_obj_key) = object_store - .get_obj(&mesh_object_id) - .map(|obj| obj.as_raw()) - else { - tracing::error!( - object_id=?mesh_object_id, - "Object store does not contain a mesh object with this ID" - ); - continue; - }; - - let Some(mesh_graphics_ctx_obj) = - graphics_ctx_objects.get_mut(&mesh_graphics_ctx_obj_key) - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context does not contain a mesh object with this key" - ); + Command::UpdateMesh { obj_id, mesh, usage: mesh_usage } => { + let Some(resource) = backend_resources.get_resource_mut( + object_store, + obj_id, + ObjectKind::ImplementationSpecific, + ) else { continue; }; - #[allow(irrefutable_let_patterns)] - let GraphicsContextObject::Mesh { - mesh: graphics_mesh, - vertex_attrs_updated_for_shader: _, - } = mesh_graphics_ctx_obj - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context object with this key is not a mesh" - ); - continue; + let BackendResource::Mesh { mesh: graphics_mesh, .. } = resource else { + unreachable!(); }; if let Err(err) = graphics_mesh.update(gl_context, &mesh, mesh_usage) { tracing::error!("Failed to update mesh: {err}"); } } - Command::RemoveMesh(mesh_object_id) => { - let Some(mesh_graphics_ctx_obj_key) = object_store - .remove(&mesh_object_id) - .flatten() - .map(|obj| obj.as_raw()) - else { - tracing::error!( - object_id=?mesh_object_id, - "Object store does not contain a mesh object with this ID" - ); - continue; - }; - - let Some(mesh_graphics_ctx_obj) = - graphics_ctx_objects.remove(&mesh_graphics_ctx_obj_key) - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context does not contain a mesh object with this key" - ); - continue; - }; - - #[allow(irrefutable_let_patterns)] - let GraphicsContextObject::Mesh { mesh: mut graphics_mesh, .. } = - mesh_graphics_ctx_obj - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context object with this key is not a mesh" - ); - continue; - }; - - graphics_mesh.destroy(gl_context); + Command::RemoveMesh(object_id) => { + backend_resources.remove_resource( + object_store, + object_id, + ObjectKind::ImplementationSpecific, + gl_context, + ); } - Command::DrawMesh(mesh_object_id, draw_mesh_opts) => { - let Some(mesh_graphics_ctx_obj_key) = object_store - .get_obj(&mesh_object_id) - .map(|obj| obj.as_raw()) - else { - tracing::error!( - object_id=?mesh_object_id, - "Object store does not contain a mesh object with this ID" - ); - continue; - }; - - let Some(mesh_graphics_ctx_obj) = - graphics_ctx_objects.get_mut(&mesh_graphics_ctx_obj_key) - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context does not contain a mesh object with this key" - ); + Command::DrawMesh(object_id, draw_mesh_opts) => { + let Some(resource) = backend_resources.get_resource_mut( + object_store, + object_id, + ObjectKind::ImplementationSpecific, + ) else { continue; }; - let GraphicsContextObject::Mesh { + let BackendResource::Mesh { mesh: graphics_mesh, vertex_attrs_updated_for_shader, - } = mesh_graphics_ctx_obj + } = resource else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context object with this key is not a mesh" - ); - continue; + unreachable!(); }; let Some((shader_program_obj_id, _, shader_program_metadata)) = |
