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.rs249
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),