diff options
Diffstat (limited to 'engine/src/rendering/backend')
| -rw-r--r-- | engine/src/rendering/backend/opengl.rs | 249 |
1 files changed, 171 insertions, 78 deletions
diff --git a/engine/src/rendering/backend/opengl.rs b/engine/src/rendering/backend/opengl.rs index b8ac04b..0a58417 100644 --- a/engine/src/rendering/backend/opengl.rs +++ b/engine/src/rendering/backend/opengl.rs @@ -6,6 +6,7 @@ use std::convert::Infallible; use std::hint::cold_path; use std::num::NonZero; +use ecs::phase::INIT as INIT_PHASE; use ecs::query::term::With; use glutin::config::Config as GlutinConfig; use glutin::display::GetGlDisplay; @@ -61,7 +62,7 @@ use opengl_bindings::misc::{ }; use opengl_bindings::shader::{ Error as GlShaderError, - Kind as ShaderKind, + Kind as GlShaderKind, Program as GlShaderProgram, Shader as GlShader, }; @@ -118,12 +119,22 @@ use crate::rendering::shader::cursor::{ }; use crate::rendering::shader::reflection::Stage as ShaderStage; use crate::rendering::shader::{ + CompileTarget as ShaderCompileTarget, + CompileTargetFormat as ShaderCompileTargetFormat, + Context as ShaderContext, + ContextSessionInitOpts as ShaderContextSessionInitOpts, + DebugInfoLevel as ShaderDebugInfoLevel, + EntrypointFlags as ShaderEntrypointFlags, Error as ShaderError, + LineDirectiveMode as ShaderLineDirectiveMode, + OptimizationLevel as ShaderOptimizationLevel, Program as ShaderProgram, - ProgramMetadata as ShaderProgramMetadata, + VertexDescCreationError as ShaderVertexDescCreationError, + VertexDescription as ShaderVertexDescription, }; use crate::rendering::{ AssetOrValue, + BackendProperties, BufferClearMask, Command, CommandQueue, @@ -436,7 +447,7 @@ enum BackendResource Shader { program: GlShaderProgram, - program_metadata: ShaderProgramMetadata, + info: ShaderInfo, bindings: IntMap<ShaderBindingIndex, BackendShaderBinding>, }, Texture @@ -489,6 +500,14 @@ enum TextureKind CubeMap, } +#[derive(Debug, Clone)] +struct ShaderInfo +{ + /// If the shader program has a entry point in the vertex stage, this field will + /// contain a description of the vertex type passed to the entry point. + vertex_desc: Option<ShaderVertexDescription>, +} + #[derive(Debug, Default)] #[non_exhaustive] pub struct Extension {} @@ -497,6 +516,8 @@ impl crate::ecs::extension::Extension for Extension { fn collect(self, mut collector: crate::ecs::extension::Collector<'_>) { + collector.add_system(*INIT_PHASE, init); + collector.add_system(*RENDER_PHASE, handle_commands); collector.add_system(*POST_RENDER_PHASE, prepare_windows); @@ -506,6 +527,36 @@ impl crate::ecs::extension::Extension for Extension } } +fn init( + mut shader_context: Single<ShaderContext>, + mut actions: Actions, +) -> Result<(), crate::Error> +{ + let shader_context = shader_context.get_mut()?; + + let shader_target_ids = shader_context.init_session( + &if cfg!(debug_assertions) { + ShaderContextSessionInitOpts::default() + .optimization_level(ShaderOptimizationLevel::Default) + .debug_info_level(ShaderDebugInfoLevel::Maximal) + .line_directive_mode(ShaderLineDirectiveMode::Standard) + .no_mangle(true) + } else { + ShaderContextSessionInitOpts::default() + .optimization_level(ShaderOptimizationLevel::High) + .debug_info_level(ShaderDebugInfoLevel::None) + .line_directive_mode(ShaderLineDirectiveMode::None) + }, + &[&ShaderCompileTarget::default().format(ShaderCompileTargetFormat::Glsl)], + )?; + + actions.create_sole(BackendProperties { + shader_target_id: shader_target_ids[0], + }); + + Ok(()) +} + fn prepare_windows( window_query: Query<( Option<&Window>, @@ -756,6 +807,7 @@ fn handle_commands( mut object_store: Single<ObjectStore>, mut command_queue: Single<CommandQueue>, assets: Single<Assets>, + backend_properties: Single<BackendProperties>, ) -> Result<(), crate::Error> { let Ok(graphics_ctx) = graphics_ctx.get_mut() else { @@ -766,6 +818,10 @@ fn handle_commands( let command_queue = command_queue.get_mut()?; let assets = assets.get()?; + let Ok(backend_properties) = backend_properties.get() else { + return Ok(()); + }; + let GraphicsContext { ref gl_context, ref mut surfaces, @@ -776,11 +832,8 @@ fn handle_commands( return Ok(()); }; - let mut activated_gl_shader_program: Option<( - ObjectId, - GlShaderProgram, - ShaderProgramMetadata, - )> = None; + let mut activated_gl_shader_program: Option<(ObjectId, GlShaderProgram, ShaderInfo)> = + None; for command in command_queue.drain() { let tracing_span = tracing::info_span!( @@ -887,16 +940,29 @@ fn handle_commands( } Command::CreateShaderProgram(object_id, shader_program) => { if let Err(err) = backend_resources - .try_create_resource::<CreateShaderError>( + .try_create_resource::<GlShaderCreationError>( object_store, object_id, || { Ok(BackendResource::Shader { - program: create_shader_program( + program: create_and_init_gl_shader_program( gl_context, &shader_program, + backend_properties, )?, - program_metadata: shader_program.metadata().clone(), + info: ShaderInfo { + vertex_desc: if shader_program + .metadata() + .link_entrypoints + .contains(ShaderEntrypointFlags::VERTEX) + { + Some(shader_program.create_vertex_desc( + backend_properties.shader_target_id, + )?) + } else { + None + }, + }, bindings: IntMap::with_capacity(4), }) }, @@ -914,7 +980,7 @@ fn handle_commands( continue; }; - let BackendResource::Shader { program, program_metadata, bindings } = + let BackendResource::Shader { program, info: shader_info, bindings } = resource else { unreachable!(); @@ -927,7 +993,7 @@ fn handle_commands( } activated_gl_shader_program = - Some((shader_object_id, program.clone(), program_metadata.clone())); + Some((shader_object_id, program.clone(), shader_info.clone())); } Command::SetShaderBinding( shader_object_id, @@ -1162,7 +1228,7 @@ fn handle_commands( unreachable!(); }; - let Some((shader_program_obj_id, _, shader_program_metadata)) = + let Some((shader_program_obj_id, _, shader_info)) = &activated_gl_shader_program else { tracing::error!("No shader program is activated"); @@ -1174,8 +1240,7 @@ fn handle_commands( vertex_attrs_updated_for_shader != *shader_program_obj_id }, ) { - let Some(shader_program_vertex_desc) = - &shader_program_metadata.vertex_desc + let Some(shader_program_vertex_desc) = &shader_info.vertex_desc else { tracing::error!( "Activated shader program does not have a vertex description" @@ -1796,97 +1861,125 @@ fn cube_map_texture_face_to_gl(face: CubeMapTextureFace) -> GlCubeMapTextureFace } } -fn create_shader_program( +fn create_and_init_gl_shader_program( current_context: &MaybeCurrentContextWithFns, shader_program: &ShaderProgram, -) -> Result<GlShaderProgram, CreateShaderError> + backend_properties: &BackendProperties, +) -> Result<GlShaderProgram, GlShaderCreationError> { - let shader_program_reflection = shader_program.reflection(0).expect("Not possible"); - - let (vs_entry_point_index, vs_entry_point_reflection) = shader_program_reflection - .entry_points() - .enumerate() - .find(|(_, entry_point)| entry_point.stage() == ShaderStage::Vertex) - .ok_or_else(|| { - CreateShaderError::NoShaderStageEntrypointFound(ShaderStage::Vertex) - })?; + let gl_shader_program = GlShaderProgram::new(current_context); - let vertex_shader_entry_point_code = shader_program - .get_entry_point_code(vs_entry_point_index.try_into().expect( - "Vertex shader entry point index does not fit in 32-bit unsigned int", - )) - .map_err(|err| CreateShaderError::GetShaderEntryPointCodeFailed { - err, - stage: ShaderStage::Vertex, - entrypoint: vs_entry_point_reflection - .name() - .map_or("(none)".into(), |name| name.to_string().into()), - })?; + let shader_program_reflection = shader_program + .reflection(backend_properties.shader_target_id) + .expect("Not possible"); - let (fs_entry_point_index, fs_entry_point_reflection) = shader_program_reflection - .entry_points() - .enumerate() - .find(|(_, entry_point)| entry_point.stage() == ShaderStage::Fragment) - .ok_or_else(|| { - CreateShaderError::NoShaderStageEntrypointFound(ShaderStage::Fragment) - })?; + if shader_program + .metadata() + .link_entrypoints + .contains(ShaderEntrypointFlags::VERTEX) + { + let Some(vs_entry_point_index) = shader_program_reflection + .entry_points() + .position(|entry_point| entry_point.stage() == ShaderStage::Vertex) + else { + unreachable!(); + }; - let fragment_shader_entry_point_code = shader_program - .get_entry_point_code(fs_entry_point_index.try_into().expect( - "Fragment shader entry point index does not fit in 32-bit unsigned int", - )) - .map_err(|err| CreateShaderError::GetShaderEntryPointCodeFailed { - err, - stage: ShaderStage::Fragment, - entrypoint: fs_entry_point_reflection - .name() - .map_or("(none)".into(), |name| name.to_string().into()), - })?; + let gl_vertex_shader = create_and_init_gl_shader( + current_context, + shader_program, + vs_entry_point_index, + GlShaderKind::Vertex, + backend_properties, + )?; - let vertex_shader = GlShader::new(current_context, ShaderKind::Vertex); + gl_shader_program.attach(current_context, &gl_vertex_shader); + } - vertex_shader.set_source( - current_context, - vertex_shader_entry_point_code.as_str().unwrap(), - )?; + if shader_program + .metadata() + .link_entrypoints + .contains(ShaderEntrypointFlags::FRAGMENT) + { + let Some(fs_entry_point_index) = shader_program_reflection + .entry_points() + .position(|entry_point| entry_point.stage() == ShaderStage::Fragment) + else { + unreachable!(); + }; - vertex_shader.compile(current_context)?; + let gl_fragment_shader = create_and_init_gl_shader( + current_context, + shader_program, + fs_entry_point_index, + GlShaderKind::Fragment, + backend_properties, + )?; + + gl_shader_program.attach(current_context, &gl_fragment_shader); + } - let fragment_shader = GlShader::new(current_context, ShaderKind::Fragment); + gl_shader_program.link(current_context)?; - fragment_shader.set_source( - current_context, - fragment_shader_entry_point_code.as_str().unwrap(), - )?; + Ok(gl_shader_program) +} - fragment_shader.compile(current_context)?; +fn create_and_init_gl_shader( + current_context: &MaybeCurrentContextWithFns, + shader_program: &ShaderProgram, + entry_point_index: usize, + gl_shader_kind: GlShaderKind, + backend_properties: &BackendProperties, +) -> Result<GlShader, GlShaderCreationError> +{ + let entry_point_index = u32::try_from(entry_point_index) + .expect("Shader entry point index does not fit in 32-bit unsigned int"); - let gl_shader_program = GlShaderProgram::new(current_context); + let entry_point_code = shader_program + .get_entry_point_code(entry_point_index, backend_properties.shader_target_id) + .map_err(|err| GlShaderCreationError::GetShaderEntryPointCodeFailed { + err, + stage: match gl_shader_kind { + GlShaderKind::Vertex => ShaderStage::Vertex, + GlShaderKind::Fragment => ShaderStage::Fragment, + }, + entry_point: shader_program + .reflection(backend_properties.shader_target_id) + .ok() + .and_then(|program_reflection| { + program_reflection + .get_entry_point_by_index(entry_point_index)? + .name() + .map(ToOwned::to_owned) + }) + .map_or("<unknown>".into(), Into::into), + })?; - gl_shader_program.attach(current_context, &vertex_shader); - gl_shader_program.attach(current_context, &fragment_shader); + let gl_shader = GlShader::new(current_context, gl_shader_kind); - gl_shader_program.link(current_context)?; + gl_shader.set_source(current_context, entry_point_code.as_str().unwrap())?; - Ok(gl_shader_program) + gl_shader.compile(current_context)?; + + Ok(gl_shader) } #[derive(Debug, thiserror::Error)] -enum CreateShaderError +enum GlShaderCreationError { #[error( - "Failed to get code of shader program entry point {entrypoint} of stage {stage:?}" + "Failed to get code of shader program entry point {entry_point} of stage {stage:?}" )] GetShaderEntryPointCodeFailed { #[source] err: ShaderError, stage: ShaderStage, - entrypoint: Cow<'static, str>, + entry_point: Cow<'static, str>, }, - #[error("No entrypoint was found for shader stage {0:?}")] - NoShaderStageEntrypointFound(ShaderStage), + #[error("Failed to create shader vertex description")] + VertexDescCreationFailed(#[from] ShaderVertexDescCreationError), #[error(transparent)] ShaderError(#[from] GlShaderError), |
