diff options
| author | HampusM <hampus@hampusmat.com> | 2026-04-23 03:07:01 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-04-23 03:07:01 +0200 |
| commit | 6474394f49b67377c9fef66f51af61f108ae3cce (patch) | |
| tree | 60acc11667e315c3226dac82f130361bbec5a834 /engine/src/renderer/opengl.rs | |
| parent | 7699a1f498dd41d9abfc907d36e37dfed7a761c0 (diff) | |
Diffstat (limited to 'engine/src/renderer/opengl.rs')
| -rw-r--r-- | engine/src/renderer/opengl.rs | 1267 |
1 files changed, 632 insertions, 635 deletions
diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs index 860416e..2283b32 100644 --- a/engine/src/renderer/opengl.rs +++ b/engine/src/renderer/opengl.rs @@ -4,14 +4,15 @@ use std::borrow::Cow; use std::collections::HashMap; use ecs::actions::Actions; -use ecs::pair::Pair; use ecs::query::term::Without; use ecs::sole::Single; -use ecs::{Component, Query}; +use ecs::{Component, Query, Sole}; +use glutin::config::Config as GlutinConfig; use glutin::display::GetGlDisplay; +use glutin::error::Error as GlutinError; use glutin::prelude::{GlDisplay, PossiblyCurrentGlContext}; use glutin::surface::{ - GlSurface, + GlSurface as _, Surface as GlutinSurface, WindowSurface as GlutinWindowSurface, }; @@ -60,7 +61,12 @@ use opengl_bindings::vertex_array::{ PrimitiveKind, VertexArray, }; -use opengl_bindings::{ContextWithFns, CurrentContextWithFns}; +use opengl_bindings::{ + ContextWithFns, + CurrentContextWithFns, + MakeContextCurrentError as GlMakeContextCurrentError, +}; +use raw_window_handle::WindowHandle; use safer_ffi::layout::ReprC; use zerocopy::{Immutable, IntoBytes}; @@ -82,11 +88,9 @@ use crate::renderer::opengl::glutin_compat::{ }; use crate::renderer::opengl::graphics_mesh::GraphicsMesh; use crate::renderer::{ - ActiveDrawProperties, BufferClearMask, Command as RendererCommand, CommandQueue as RendererCommandQueue, - CtxUsedByWindow as RendererCtxUsedByWindow, DrawMeshOptions, DrawPropertiesUpdateFlags, GraphicsProperties, @@ -94,7 +98,6 @@ use crate::renderer::{ RENDER_PHASE, SurfaceId, SurfaceSpec, - WindowUsingRendererCtx, }; use crate::shader::cursor::BindingValue as ShaderBindingValue; use crate::shader::{ @@ -109,6 +112,7 @@ use crate::texture::{ Texture, Wrapping as TextureWrapping, }; +use crate::util::OptionExt; use crate::vector::{Vec2, Vec3}; use crate::windowing::Context as WindowingContext; use crate::windowing::window::{ @@ -124,13 +128,13 @@ mod graphics_mesh; #[derive(Debug, Component)] struct WindowGlConfig { - gl_config: glutin::config::Config, + gl_config: GlutinConfig, } -#[derive(Component)] +#[derive(Sole, Default)] struct GraphicsContext { - gl_context: ContextWithFns, + gl_context: Option<ContextWithFns>, surfaces: HashMap<SurfaceId, GlutinSurface<GlutinWindowSurface>>, shader_uniform_buffer_objs: HashMap<RendererObjectId, HashMap<u32, opengl_bindings::buffer::Buffer<u8>>>, @@ -160,12 +164,11 @@ impl ecs::extension::Extension for Extension collector.add_system(*POST_RENDER_PHASE, prepare_windows); collector.add_system(*POST_RENDER_PHASE, init_window_graphics); + + let _ = collector.add_sole(GraphicsContext::default()); } } -#[derive(Debug, Component)] -struct SetupFailed; - fn prepare_windows( window_query: Query< (Option<&Window>, &mut WindowCreationAttributes), @@ -173,7 +176,6 @@ fn prepare_windows( Without<CreationReady>, Without<WindowGlConfig>, Without<WindowClosed>, - Without<SetupFailed>, ), >, windowing_context: Single<WindowingContext>, @@ -209,7 +211,6 @@ fn prepare_windows( Ok(window_handle) => window_handle, Err(err) => { tracing::error!("Failed to get window handle: {err}"); - actions.add_components(window_ent_id, (SetupFailed,)); continue; } }; @@ -231,7 +232,6 @@ fn prepare_windows( } Err(err) => { tracing::error!("Failed to create platform graphics display: {err}"); - actions.add_components(window_ent_id, (SetupFailed,)); continue; } }; @@ -248,17 +248,19 @@ fn prepare_windows( #[tracing::instrument(skip_all)] fn init_window_graphics( - window_query: Query< - (&Window, &WindowGlConfig), - (Without<SurfaceSpec>, Without<SetupFailed>), - >, + window_query: Query<(&Window, &WindowGlConfig), (Without<SurfaceSpec>,)>, windowing_context: Single<WindowingContext>, graphics_props: Single<GraphicsProperties>, + mut graphics_ctx: Single<GraphicsContext>, mut actions: Actions, ) { for (window_ent_id, (window, window_gl_config)) in window_query.iter_with_euids() { - tracing::info!("Initializing graphics for window {window_ent_id}"); + tracing::info!( + window_entity_id=%window_ent_id, + window_title=&*window.title, + "Initializing graphics for window" + ); let display = window_gl_config.gl_config.display(); @@ -273,12 +275,10 @@ fn init_window_graphics( entity_id = %window_ent_id, "Windowing context does not contain window" ); - actions.add_components(window_ent_id, (SetupFailed,)); continue; } Err(err) => { tracing::error!("Failed to get window handle: {err}"); - actions.add_components(window_ent_id, (SetupFailed,)); continue; } }; @@ -310,31 +310,23 @@ fn init_window_graphics( } }; - let context = match unsafe { - display.create_context( + let gl_context = match graphics_ctx.gl_context.get_or_try_insert_with_fn(|| { + create_gl_context( &window_gl_config.gl_config, - &glutin::context::ContextAttributesBuilder::new() - .with_debug(graphics_props.debug) - .build(Some(window_handle.as_raw())), + &graphics_props, + window_handle, + &surface, ) - } { - Ok(context) => context, - Err(err) => { - tracing::error!("Failed to create graphics context: {err}"); - continue; - } - }; - - let gl_context = match ContextWithFns::new(context, &surface) { - Ok(context) => context, + }) { + Ok(gl_context) => gl_context, Err(err) => { - tracing::error!("Failed to create graphics context: {err}"); + tracing::error!("Failed to create GL context: {err:#?}"); continue; } }; let Ok(curr_gl_context) = gl_context.make_current(&surface) else { - tracing::error!("Failed to make graphics context current"); + tracing::error!("Failed to make GL context current"); continue; }; @@ -384,692 +376,696 @@ fn init_window_graphics( let surface_id = SurfaceId::new_unique(); - let renderer_ctx_ent_id = actions.spawn(( - GraphicsContext { - gl_context, - surfaces: HashMap::from([(surface_id, surface)]), - shader_uniform_buffer_objs: HashMap::new(), - objects: HashMap::new(), - next_object_key: RendererObjectRawValue::default(), - }, - RendererObjectStore::default(), - RendererCommandQueue::default(), - Pair::builder() - .relation::<RendererCtxUsedByWindow>() - .target_id(window_ent_id) - .build(), - ActiveDrawProperties::default(), - )); - - actions.add_components( - window_ent_id, - ( - SurfaceSpec { id: surface_id }, - Pair::builder() - .relation::<WindowUsingRendererCtx>() - .target_id(renderer_ctx_ent_id) - .build(), - ), - ); + actions.add_components(window_ent_id, (SurfaceSpec { id: surface_id },)); + + graphics_ctx.surfaces.insert(surface_id, surface); } } #[tracing::instrument(skip_all)] fn handle_commands( - renderer_ctx_query: Query<( - &mut GraphicsContext, - &mut RendererObjectStore, - &mut RendererCommandQueue, - )>, + mut graphics_ctx: Single<GraphicsContext>, + mut object_store: Single<RendererObjectStore>, + mut command_queue: Single<RendererCommandQueue>, assets: Single<Assets>, shader_context: Single<ShaderContext>, ) { - for (mut graphics_ctx, mut renderer_object_store, mut command_queue) in - &renderer_ctx_query - { - let GraphicsContext { - 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, - } = *graphics_ctx; - - let mut opt_curr_gl_ctx: Option<CurrentContextWithFns> = None; - - let mut activated_gl_shader_program: Option<(RendererObjectId, GlShaderProgram)> = - None; - - for command in command_queue.drain() { - let tracing_span = tracing::info_span!("handle_cmd"); - let _tracing_span_enter = tracing_span.enter(); - - match command { - RendererCommand::RemoveSurface(surface_id) => { - let Some(surface) = surfaces.remove(&surface_id) else { - tracing::error!(surface_id=?surface_id, "Surface does not exist"); - continue; - }; + let GraphicsContext { + 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, + } = *graphics_ctx; + + let Some(gl_context) = gl_context else { + return; + }; - if surface.is_current(gl_context.context()) { - opt_curr_gl_ctx = None; + let mut opt_curr_gl_ctx: Option<CurrentContextWithFns> = None; - if let Err(err) = gl_context.context().make_not_current_in_place() - { - tracing::error!( - "Failed to make GL context not current: {err}" - ); - } - } + let mut activated_gl_shader_program: Option<(RendererObjectId, GlShaderProgram)> = + None; - drop(surface); - } - RendererCommand::MakeCurrent(surface_id) => { - let Some(surface) = surfaces.get(&surface_id) else { - tracing::error!(surface_id=?surface_id, "Surface does not exist"); - continue; - }; + for command in command_queue.drain() { + let tracing_span = tracing::info_span!("handle_cmd"); + let _tracing_span_enter = tracing_span.enter(); - let curr_gl_ctx = match gl_context.make_current(surface) { - Ok(current_graphics_context) => current_graphics_context, - Err(err) => { - tracing::error!( - "Failed to make graphics context current: {err}" - ); - continue; - } - }; + match command { + RendererCommand::RemoveSurface(surface_id) => { + let Some(surface) = surfaces.remove(&surface_id) else { + tracing::error!(surface_id=?surface_id, "Surface does not exist"); + continue; + }; + + if surface.is_current(gl_context.context()) { + opt_curr_gl_ctx = None; - opt_curr_gl_ctx = Some(curr_gl_ctx); + if let Err(err) = gl_context.context().make_not_current_in_place() { + tracing::error!("Failed to make GL context not current: {err}"); + } } - RendererCommand::ClearBuffers(buffer_clear_mask) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; - let mut clear_mask = GlBufferClearMask::empty(); + drop(surface); + } + RendererCommand::MakeCurrent(surface_id) => { + let Some(surface) = surfaces.get(&surface_id) else { + tracing::error!(surface_id=?surface_id, "Surface does not exist"); + continue; + }; - clear_mask.set( - GlBufferClearMask::COLOR, - buffer_clear_mask.contains(BufferClearMask::COLOR), - ); + let curr_gl_ctx = match gl_context.make_current(surface) { + Ok(current_graphics_context) => current_graphics_context, + Err(err) => { + tracing::error!("Failed to make graphics context current: {err}"); + continue; + } + }; - clear_mask.set( - GlBufferClearMask::DEPTH, - buffer_clear_mask.contains(BufferClearMask::DEPTH), - ); + opt_curr_gl_ctx = Some(curr_gl_ctx); + } + RendererCommand::ClearBuffers(buffer_clear_mask) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; - clear_mask.set( - GlBufferClearMask::STENCIL, - buffer_clear_mask.contains(BufferClearMask::STENCIL), - ); + let mut clear_mask = GlBufferClearMask::empty(); - clear_buffers(&curr_gl_ctx, clear_mask); - } - RendererCommand::SwapBuffers(surface_id) => { - let Some(surface) = surfaces.get(&surface_id) else { - tracing::error!(surface_id=?surface_id, "Surface does not exist"); - continue; - }; + clear_mask.set( + GlBufferClearMask::COLOR, + buffer_clear_mask.contains(BufferClearMask::COLOR), + ); - if let Err(err) = surface.swap_buffers(gl_context.context()) { - tracing::error!("Failed to swap buffers: {err}"); - } - } - RendererCommand::CreateShaderProgram( - shader_program_obj_id, - shader_program, - ) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; + clear_mask.set( + GlBufferClearMask::DEPTH, + buffer_clear_mask.contains(BufferClearMask::DEPTH), + ); - if renderer_object_store.contains_with_id(&shader_program_obj_id) { - tracing::error!( - object_id=?shader_program_obj_id, - "Object store already contains a object with this ID" - ); - continue; - } + clear_mask.set( + GlBufferClearMask::STENCIL, + buffer_clear_mask.contains(BufferClearMask::STENCIL), + ); - let gl_shader_program = - match create_shader_program(&curr_gl_ctx, &shader_program) { - Ok(gl_shader_program) => gl_shader_program, - Err(err) => { - tracing::error!("Failed to create shader program: {err}"); - continue; - } - }; + clear_buffers(&curr_gl_ctx, clear_mask); + } + RendererCommand::SwapBuffers(surface_id) => { + let Some(surface) = surfaces.get(&surface_id) else { + tracing::error!(surface_id=?surface_id, "Surface does not exist"); + continue; + }; - renderer_object_store.insert( - shader_program_obj_id, - RendererObject::from_raw( - gl_shader_program.into_raw(), - RendererObjectKind::ShaderProgram, - ), + if let Err(err) = surface.swap_buffers(gl_context.context()) { + tracing::error!("Failed to swap buffers: {err}"); + } + } + RendererCommand::CreateShaderProgram( + shader_program_obj_id, + shader_program, + ) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; + + 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; } - RendererCommand::ActivateShader(shader_program_obj_id) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; - let Some(shader_program_obj) = renderer_object_store - .get_shader_program_obj(&shader_program_obj_id) - else { - tracing::error!( - "Shader object does not exist or has a wrong kind" - ); - continue; + let gl_shader_program = + match create_shader_program(&curr_gl_ctx, &shader_program) { + Ok(gl_shader_program) => gl_shader_program, + Err(err) => { + tracing::error!("Failed to create shader program: {err}"); + continue; + } }; - let gl_shader_program = - GlShaderProgram::from_raw(shader_program_obj.as_raw()); + object_store.insert( + shader_program_obj_id, + RendererObject::from_raw( + gl_shader_program.into_raw(), + RendererObjectKind::ShaderProgram, + ), + ); + } + RendererCommand::ActivateShader(shader_program_obj_id) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; - gl_shader_program.activate(&curr_gl_ctx); + let Some(shader_program_obj) = + object_store.get_shader_program_obj(&shader_program_obj_id) + else { + tracing::error!("Shader object does not exist or has a wrong kind"); + continue; + }; - activated_gl_shader_program = - Some((shader_program_obj_id, gl_shader_program)); - } - RendererCommand::SetShaderBinding(binding_location, binding_value) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; + let gl_shader_program = + GlShaderProgram::from_raw(shader_program_obj.as_raw()); - let Some((activated_gl_shader_program_obj_id, _)) = - &activated_gl_shader_program - else { - tracing::error!("No shader program is activated"); - continue; - }; + gl_shader_program.activate(&curr_gl_ctx); - if let ShaderBindingValue::Texture(texture_asset) = &binding_value { - let Some(texture_obj) = renderer_object_store.get_texture_obj( - &RendererObjectId::Asset(texture_asset.id()), - ) else { - tracing::error!( - "Texture {:?} does not exist in renderer object store", - assets.get_label(texture_asset) - ); - continue; - }; + activated_gl_shader_program = + Some((shader_program_obj_id, gl_shader_program)); + } + RendererCommand::SetShaderBinding(binding_location, binding_value) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; - let gl_texture = GlTexture::from_raw(texture_obj.as_raw()); + let Some((activated_gl_shader_program_obj_id, _)) = + &activated_gl_shader_program + else { + tracing::error!("No shader program is activated"); + continue; + }; - gl_texture.bind_to_texture_unit( - curr_gl_ctx, - binding_location.binding_index, + if let ShaderBindingValue::Texture(texture_asset) = &binding_value { + let Some(texture_obj) = object_store + .get_texture_obj(&RendererObjectId::Asset(texture_asset.id())) + else { + tracing::error!( + "Texture {:?} does not exist in renderer object store", + assets.get_label(texture_asset) ); - - // gl_shader_program.set_uniform_at_location( - // curr_gl_ctx, - // GlUniformLocation::from_number( - // binding_location.binding_index as i32, - // ), - // &binding_location.binding_index, - // ); - continue; - } + }; + + let gl_texture = GlTexture::from_raw(texture_obj.as_raw()); - let binding_index = binding_location.binding_index; - - let uniform_buffer_objs = shader_uniform_buffer_objs - .entry(*activated_gl_shader_program_obj_id) - .or_default(); - - let uniform_buffer = - uniform_buffer_objs.entry(binding_index).or_insert_with(|| { - let uniform_buf = - opengl_bindings::buffer::Buffer::<u8>::new(curr_gl_ctx); - - uniform_buf - .init( - curr_gl_ctx, - binding_location.binding_size, - opengl_bindings::buffer::Usage::Dynamic, - ) - .unwrap(); - - uniform_buf - }); - - // The index into the uniform buffer binding target is for whatever - // shader program is currently bound so the uniform buffer object has - // to be re-bound so that a uniform buffer from another shader isn't - // used - uniform_buffer.bind_to_indexed_target( + gl_texture.bind_to_texture_unit( curr_gl_ctx, - opengl_bindings::buffer::BindingTarget::UniformBuffer, - binding_index as u32, + binding_location.binding_index, ); - let fvec3_value; + // gl_shader_program.set_uniform_at_location( + // curr_gl_ctx, + // GlUniformLocation::from_number( + // binding_location.binding_index as i32, + // ), + // &binding_location.binding_index, + // ); - uniform_buffer - .store_at_byte_offset( - curr_gl_ctx, - binding_location.byte_offset, - match binding_value { - ShaderBindingValue::Uint(ref value) => value.as_bytes(), - ShaderBindingValue::Int(ref value) => value.as_bytes(), - ShaderBindingValue::Float(ref value) => value.as_bytes(), - ShaderBindingValue::FVec3(value) => { - fvec3_value = CF32Vec3::from(value); - - fvec3_value.as_bytes() - } - ShaderBindingValue::FMat4x4(ref value) => { - value.items().as_bytes() - } - ShaderBindingValue::Texture(_) => unreachable!(), - }, - ) - .unwrap(); + continue; } - RendererCommand::CreateTexture(texture_asset) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; - if let Err(err) = create_texture_object( + let binding_index = binding_location.binding_index; + + let uniform_buffer_objs = shader_uniform_buffer_objs + .entry(*activated_gl_shader_program_obj_id) + .or_default(); + + let uniform_buffer = + uniform_buffer_objs.entry(binding_index).or_insert_with(|| { + let uniform_buf = + opengl_bindings::buffer::Buffer::<u8>::new(curr_gl_ctx); + + uniform_buf + .init( + curr_gl_ctx, + binding_location.binding_size, + opengl_bindings::buffer::Usage::Dynamic, + ) + .unwrap(); + + uniform_buf + }); + + // The index into the uniform buffer binding target is for whatever + // shader program is currently bound so the uniform buffer object has + // to be re-bound so that a uniform buffer from another shader isn't + // used + uniform_buffer.bind_to_indexed_target( + curr_gl_ctx, + opengl_bindings::buffer::BindingTarget::UniformBuffer, + binding_index as u32, + ); + + let fvec3_value; + + uniform_buffer + .store_at_byte_offset( curr_gl_ctx, - &mut renderer_object_store, - &assets, - &texture_asset, - ) { - tracing::error!("Failed to create texture object: {err}"); - } + binding_location.byte_offset, + match binding_value { + ShaderBindingValue::Uint(ref value) => value.as_bytes(), + ShaderBindingValue::Int(ref value) => value.as_bytes(), + ShaderBindingValue::Float(ref value) => value.as_bytes(), + ShaderBindingValue::FVec3(value) => { + fvec3_value = CF32Vec3::from(value); + + fvec3_value.as_bytes() + } + ShaderBindingValue::FMat4x4(ref value) => { + value.items().as_bytes() + } + ShaderBindingValue::Texture(_) => unreachable!(), + }, + ) + .unwrap(); + } + RendererCommand::CreateTexture(texture_asset) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; + + if let Err(err) = create_texture_object( + curr_gl_ctx, + &mut object_store, + &assets, + &texture_asset, + ) { + tracing::error!("Failed to create texture object: {err}"); } - RendererCommand::CreateMesh { - obj_id: mesh_object_id, - mesh, - usage: mesh_usage, - } => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; + } + RendererCommand::CreateMesh { + obj_id: mesh_object_id, + mesh, + usage: mesh_usage, + } => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; - if renderer_object_store.contains_with_id(&mesh_object_id) { - tracing::error!( - object_id=?mesh_object_id, - "Object store already contains a object with this ID" - ); - continue; - } + 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 Some((RendererObjectId::Asset(curr_shader_program_asset_id), _)) = - &activated_gl_shader_program - else { - tracing::error!("No shader program is activated"); - continue; - }; + let Some((RendererObjectId::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 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 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_object_id { - RendererObjectId::Asset(mesh_asset_id) => match mesh.as_ref() { - Some(mesh) => mesh, - None => { - let Some(mesh) = - assets.get(&AssetHandle::from_id(mesh_asset_id)) - else { - tracing::error!( - asset_id=?mesh_asset_id, - "Mesh asset does not exist" - ); - continue; - }; - - mesh - } - }, - RendererObjectId::Sequential(_) => { - let Some(mesh) = mesh.as_ref() else { + let key = *next_graphics_ctx_object_key; + + let mesh = match mesh_object_id { + RendererObjectId::Asset(mesh_asset_id) => match mesh.as_ref() { + Some(mesh) => mesh, + None => { + let Some(mesh) = + assets.get(&AssetHandle::from_id(mesh_asset_id)) + else { tracing::error!( - object_id=?mesh_object_id, - "Object ID is sequential but no mesh data is given" + asset_id=?mesh_asset_id, + "Mesh asset does not exist" ); continue; }; mesh } - }; - - let graphics_mesh = match GraphicsMesh::new( - &curr_gl_ctx, - &mesh, - mesh_usage, - &vertex_desc, - ) { - Ok(graphics_mesh) => graphics_mesh, - Err(err) => { - tracing::error!("Failed to create mesh: {err}"); + }, + RendererObjectId::Sequential(_) => { + let Some(mesh) = mesh.as_ref() else { + tracing::error!( + object_id=?mesh_object_id, + "Object ID is sequential but no mesh data is given" + ); continue; - } - }; + }; - graphics_ctx_objects.insert( - key, - GraphicsContextObject::Mesh { - mesh: graphics_mesh, - compatible_shader_program_obj_id: RendererObjectId::Asset( - *curr_shader_program_asset_id, - ), - }, - ); + mesh + } + }; + + let graphics_mesh = match GraphicsMesh::new( + &curr_gl_ctx, + &mesh, + mesh_usage, + &vertex_desc, + ) { + Ok(graphics_mesh) => graphics_mesh, + Err(err) => { + tracing::error!("Failed to create mesh: {err}"); + continue; + } + }; - renderer_object_store.insert( - mesh_object_id, - RendererObject::from_raw( - key, - RendererObjectKind::ImplementationSpecific, + graphics_ctx_objects.insert( + key, + GraphicsContextObject::Mesh { + mesh: graphics_mesh, + compatible_shader_program_obj_id: RendererObjectId::Asset( + *curr_shader_program_asset_id, ), - ); + }, + ); - *next_graphics_ctx_object_key += 1; - } - RendererCommand::UpdateMesh { - obj_id: mesh_object_id, - mesh, - usage: mesh_usage, - } => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; + object_store.insert( + mesh_object_id, + RendererObject::from_raw( + key, + RendererObjectKind::ImplementationSpecific, + ), + ); - let Some(mesh_graphics_ctx_obj_key) = renderer_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; - }; + *next_graphics_ctx_object_key += 1; + } + RendererCommand::UpdateMesh { + obj_id: mesh_object_id, + mesh, + usage: mesh_usage, + } => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + 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" - ); - continue; - }; + 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; + }; - #[allow(irrefutable_let_patterns)] - let GraphicsContextObject::Mesh { - mesh: graphics_mesh, - compatible_shader_program_obj_id: _, - } = 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 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" + ); + continue; + }; + + #[allow(irrefutable_let_patterns)] + let GraphicsContextObject::Mesh { + mesh: graphics_mesh, + compatible_shader_program_obj_id: _, + } = 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; + }; - if let Err(err) = graphics_mesh.update(curr_gl_ctx, &mesh, mesh_usage) - { - tracing::error!("Failed to update mesh: {err}"); - } + if let Err(err) = graphics_mesh.update(curr_gl_ctx, &mesh, mesh_usage) { + tracing::error!("Failed to update mesh: {err}"); } - RendererCommand::RemoveMesh(mesh_object_id) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; - - let Some(mesh_graphics_ctx_obj_key) = renderer_object_store - .remove(&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.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; - }; + } + RendererCommand::RemoveMesh(mesh_object_id) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + 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; - }; + 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; + }; - graphics_mesh.destroy(curr_gl_ctx); - } - RendererCommand::DrawMesh(mesh_object_id, draw_mesh_opts) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - 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; + }; - let Some(mesh_graphics_ctx_obj_key) = renderer_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; - }; + #[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; + }; - let Some(mesh_graphics_ctx_obj) = - graphics_ctx_objects.get(&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; - }; + graphics_mesh.destroy(curr_gl_ctx); + } + RendererCommand::DrawMesh(mesh_object_id, draw_mesh_opts) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; - #[allow(irrefutable_let_patterns)] - let GraphicsContextObject::Mesh { - mesh: graphics_mesh, - compatible_shader_program_obj_id, - } = 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 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; + }; - 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" - )); - continue; - } + let Some(mesh_graphics_ctx_obj) = + graphics_ctx_objects.get(&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: graphics_mesh, + compatible_shader_program_obj_id, + } = 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; + }; - if let Err(err) = - draw_mesh(&curr_gl_ctx, graphics_mesh, &draw_mesh_opts) - { - tracing::error!("Failed to draw mesh: {err}"); - }; + 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" + )); + continue; } - RendererCommand::UpdateDrawProperties( - draw_props, - draw_props_update_flags, - ) => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::POLYGON_MODE_CONFIG) - { - opengl_bindings::misc::set_polygon_mode( - &curr_gl_ctx, - draw_props.polygon_mode_config.face, - draw_props.polygon_mode_config.mode, - ); - } + if let Err(err) = draw_mesh(&curr_gl_ctx, graphics_mesh, &draw_mesh_opts) + { + tracing::error!("Failed to draw mesh: {err}"); + }; + } + RendererCommand::UpdateDrawProperties( + draw_props, + draw_props_update_flags, + ) => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::BLENDING_ENABLED) - { - set_enabled( - curr_gl_ctx, - Capability::Blend, - draw_props.blending_enabled, - ); - } + if draw_props_update_flags + .contains(DrawPropertiesUpdateFlags::POLYGON_MODE_CONFIG) + { + opengl_bindings::misc::set_polygon_mode( + &curr_gl_ctx, + draw_props.polygon_mode_config.face, + draw_props.polygon_mode_config.mode, + ); + } - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::BLENDING_CONFIG) - { - gl_blending_configure( - curr_gl_ctx, - 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::BLENDING_ENABLED) + { + set_enabled( + curr_gl_ctx, + Capability::Blend, + draw_props.blending_enabled, + ); + } - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::DEPTH_TEST_ENABLED) - { - set_enabled( - curr_gl_ctx, - Capability::DepthTest, - draw_props.depth_test_enabled, - ); - } + if draw_props_update_flags + .contains(DrawPropertiesUpdateFlags::BLENDING_CONFIG) + { + gl_blending_configure( + curr_gl_ctx, + 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::SCISSOR_TEST_ENABLED) - { - set_enabled( - curr_gl_ctx, - Capability::ScissorTest, - draw_props.scissor_test_enabled, - ); - } + if draw_props_update_flags + .contains(DrawPropertiesUpdateFlags::DEPTH_TEST_ENABLED) + { + set_enabled( + curr_gl_ctx, + Capability::DepthTest, + draw_props.depth_test_enabled, + ); + } - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::SCISSOR_BOX) - { - gl_define_scissor_box( - curr_gl_ctx, - draw_props.scissor_box.lower_left_corner_pos.into(), - draw_props - .scissor_box - .size - .unwrap_or_else(|| { - let (_, viewport_size) = gl_get_viewport(curr_gl_ctx); - - 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::SCISSOR_TEST_ENABLED) + { + set_enabled( + curr_gl_ctx, + Capability::ScissorTest, + draw_props.scissor_test_enabled, + ); + } - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::FACE_CULLING_ENABLED) - { - set_enabled( - curr_gl_ctx, - Capability::CullFace, - draw_props.face_culling_enabled, - ); - } + if draw_props_update_flags + .contains(DrawPropertiesUpdateFlags::SCISSOR_BOX) + { + gl_define_scissor_box( + curr_gl_ctx, + draw_props.scissor_box.lower_left_corner_pos.into(), + draw_props + .scissor_box + .size + .unwrap_or_else(|| { + let (_, viewport_size) = gl_get_viewport(curr_gl_ctx); + + 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(), + ); } - RendererCommand::SetViewport { - size: viewport_size, - position: viewport_position, - } => { - let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { - tracing::error!("No GL context is current"); - continue; - }; - if let Err(err) = gl_set_viewport( + if draw_props_update_flags + .contains(DrawPropertiesUpdateFlags::FACE_CULLING_ENABLED) + { + set_enabled( curr_gl_ctx, - &viewport_position.into(), - &viewport_size.into(), - ) { - tracing::error!("Failed to set viewport: {err}"); - } + Capability::CullFace, + draw_props.face_culling_enabled, + ); + } + } + RendererCommand::SetViewport { + size: viewport_size, + position: viewport_position, + } => { + let Some(curr_gl_ctx) = &opt_curr_gl_ctx else { + tracing::error!("No GL context is current"); + continue; + }; + + if let Err(err) = gl_set_viewport( + curr_gl_ctx, + &viewport_position.into(), + &viewport_size.into(), + ) { + tracing::error!("Failed to set viewport: {err}"); } } } } } +fn create_gl_context( + gl_config: &GlutinConfig, + graphics_props: &GraphicsProperties, + window_handle: WindowHandle<'_>, + surface: &GlutinSurface<GlutinWindowSurface>, +) -> Result<ContextWithFns, CreateGlContextError> +{ + let display = gl_config.display(); + + let glutin_context = unsafe { + display.create_context( + gl_config, + &glutin::context::ContextAttributesBuilder::new() + .with_debug(graphics_props.debug) + .build(Some(window_handle.as_raw())), + ) + } + .map_err(CreateGlContextError::CreateGlutinContext)?; + + ContextWithFns::new(glutin_context, &surface) + .map_err(CreateGlContextError::MakeContextCurrent) +} + +#[derive(Debug, thiserror::Error)] +enum CreateGlContextError +{ + #[error("Glutin context creation failed")] + CreateGlutinContext(#[source] GlutinError), + + #[error("Making GL context current failed")] + MakeContextCurrent(#[source] GlMakeContextCurrentError), +} + #[tracing::instrument(skip_all)] fn create_texture_object( curr_gl_ctx: &CurrentContextWithFns<'_>, @@ -1080,9 +1076,10 @@ fn create_texture_object( { let object_id = RendererObjectId::Asset(texture_asset.id()); - if renderer_object_store.contains_with_id(&object_id) { + if renderer_object_store.contains_non_pending_with_id(&object_id) { tracing::error!( texture_object_id=?object_id, + texture_asset_label=?assets.get_label(texture_asset), "Renderer object store already contains object with this ID" ); return Ok(()); |
