From 82f1122e104cd9b5cc1d93266909199df62ebb0e Mon Sep 17 00:00:00 2001 From: John-Mark Allen Date: Sun, 4 Jul 2021 18:37:14 +0100 Subject: [PATCH] Remove ShaderProvider Instead, always use the previous AutoShaderProvider --- imgui-glow-renderer/src/lib.rs | 345 ++++++++++----------------------- 1 file changed, 106 insertions(+), 239 deletions(-) diff --git a/imgui-glow-renderer/src/lib.rs b/imgui-glow-renderer/src/lib.rs index 0034623..037d49e 100644 --- a/imgui-glow-renderer/src/lib.rs +++ b/imgui-glow-renderer/src/lib.rs @@ -53,54 +53,38 @@ impl< pub fn auto_renderer( gl: G, imgui_context: &mut imgui::Context, -) -> Result>, InitError> { +) -> Result, InitError> { RendererBuilder::new().build_owning(gl, imgui_context) } -pub struct RendererBuilder +pub struct RendererBuilder where G: Gl, T: TextureMap, - S: ShaderProvider, { texture_map: T, - shader_provider: S, phantom_gl: PhantomData, } -impl RendererBuilder> { +impl RendererBuilder { #[allow(clippy::new_without_default)] #[must_use] pub fn new() -> Self { Self { texture_map: TrivialTextureMap(), - shader_provider: as Default>::default(), phantom_gl: PhantomData::default(), } } } -impl RendererBuilder +impl RendererBuilder where G: Gl, T: TextureMap, - S: ShaderProvider, { - pub fn with_texture_map(self, texture_map: T2) -> RendererBuilder { + pub fn with_texture_map(self, texture_map: T2) -> RendererBuilder { RendererBuilder { texture_map, - shader_provider: self.shader_provider, - phantom_gl: self.phantom_gl, - } - } - - pub fn with_shader_provider>( - self, - shader_provider: S2, - ) -> RendererBuilder { - RendererBuilder { - texture_map: self.texture_map, - shader_provider, phantom_gl: self.phantom_gl, } } @@ -115,9 +99,9 @@ where self, gl: G, imgui_context: &mut imgui::Context, - ) -> Result, InitError> { + ) -> Result, InitError> { let renderer = self.build_borrowing(&gl, imgui_context)?; - Ok(OwningRenderer:: { gl, renderer }) + Ok(OwningRenderer:: { gl, renderer }) } /// Build a renderer which needs to borrow a context in order to render. @@ -129,8 +113,8 @@ where self, gl: &G, imgui_context: &mut imgui::Context, - ) -> Result, InitError> { - Renderer::::initialize(gl, imgui_context, self.texture_map, self.shader_provider) + ) -> Result, InitError> { + Renderer::::initialize(gl, imgui_context, self.texture_map) } } @@ -140,21 +124,19 @@ where /// /// OpenGL context is still available to the rest of the application through /// the `[gl_context]` method. -pub struct OwningRenderer> +pub struct OwningRenderer where G: Gl, T: TextureMap, - S: ShaderProvider, { gl: G, - renderer: Renderer, + renderer: Renderer, } -impl OwningRenderer +impl OwningRenderer where G: Gl, T: TextureMap, - S: ShaderProvider, { /// Note: no need to provide a `mut` version of this, as all methods on /// `[glow::HasContext]` are immutable. @@ -164,7 +146,7 @@ where } #[inline] - pub fn renderer(&self) -> &Renderer { + pub fn renderer(&self) -> &Renderer { &self.renderer } @@ -177,25 +159,23 @@ where } } -impl Drop for OwningRenderer +impl Drop for OwningRenderer where G: Gl, T: TextureMap, - S: ShaderProvider, { fn drop(&mut self) { self.renderer.destroy(&self.gl); } } -pub struct Renderer> +pub struct Renderer where G: Gl, T: TextureMap, - S: ShaderProvider, { pub texture_map: T, - pub shader_provider: S, + shaders: Shaders, state_backup: GlStateBackup, pub vbo_handle: G::Buffer, pub ebo_handle: G::Buffer, @@ -207,11 +187,10 @@ where pub is_destroyed: bool, } -impl Renderer +impl Renderer where G: Gl, T: TextureMap, - S: ShaderProvider, { /// # Errors /// Any error initialising the OpenGL objects (including shaders) will @@ -220,7 +199,6 @@ where gl: &G, imgui_context: &mut imgui::Context, mut texture_map: T, - shader_provider: S, ) -> Result { #![allow( clippy::similar_names, @@ -256,8 +234,7 @@ where let font_atlas_texture = prepare_font_atlas(gl, imgui_context.fonts(), &mut texture_map)?; - let mut shader_provider = shader_provider; - shader_provider.initialize(gl, gl_version)?; + let shaders = Shaders::new(gl, gl_version)?; let vbo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?; let ebo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?; @@ -265,7 +242,7 @@ where let out = Self { texture_map, - shader_provider, + shaders, state_backup, vbo_handle, ebo_handle, @@ -297,7 +274,7 @@ where unsafe { gl.delete_buffer(self.ebo_handle) }; self.ebo_handle = 0; } - let program = self.shader_provider.data().program; + let program = self.shaders.program; if program != 0 { unsafe { gl.delete_program(program) }; } @@ -424,13 +401,12 @@ where let clip_origin_is_lower_left = true; let projection_matrix = calculate_matrix(draw_data, clip_origin_is_lower_left); - let shader_data = self.shader_provider.data(); unsafe { - gl.use_program(Some(shader_data.program)); - gl.uniform_1_i32(Some(&shader_data.texture_uniform_location), 0); + gl.use_program(Some(self.shaders.program)); + gl.uniform_1_i32(Some(&self.shaders.texture_uniform_location), 0); gl.uniform_matrix_4_f32_slice( - Some(&shader_data.matrix_uniform_location), + Some(&self.shaders.matrix_uniform_location), false, &projection_matrix, ); @@ -459,27 +435,27 @@ where unsafe { gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo_handle)); gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.ebo_handle)); - gl.enable_vertex_attrib_array(shader_data.position_attribute_index); + gl.enable_vertex_attrib_array(self.shaders.position_attribute_index); gl.vertex_attrib_pointer_f32( - shader_data.position_attribute_index, + self.shaders.position_attribute_index, 2, glow::FLOAT, false, size_of::() as _, position_field_offset, ); - gl.enable_vertex_attrib_array(shader_data.uv_attribute_index); + gl.enable_vertex_attrib_array(self.shaders.uv_attribute_index); gl.vertex_attrib_pointer_f32( - shader_data.uv_attribute_index, + self.shaders.uv_attribute_index, 2, glow::FLOAT, false, size_of::() as _, uv_field_offset, ); - gl.enable_vertex_attrib_array(shader_data.color_attribute_index); + gl.enable_vertex_attrib_array(self.shaders.color_attribute_index); gl.vertex_attrib_pointer_f32( - shader_data.color_attribute_index, + self.shaders.color_attribute_index, 4, glow::UNSIGNED_BYTE, true, @@ -794,32 +770,85 @@ impl GlStateBackup { } } -pub trait ShaderProvider { - /// Called during renderer initialization, before this call the shader - /// provide should be in a neutral state and have not interacted with the - /// OpenGL context. - /// - /// Implementors should use this opporunity to check whether the version of - /// the GL context (found with `[GlVersion::read]`) is compatible with the - /// shader they provide. - /// - /// # Errors - /// Any error creating the GL objects, compiling or linking or loading the - /// shaders, or an GL context with an incompatible OpenGL version will - /// result in an error. - fn initialize(&mut self, gl: &G, gl_version: GlVersion) -> Result<(), ShaderError>; - - fn data(&self) -> &GenericShaderData; +/// Parses `GL_VERSION` and `GL_SHADING_LANGUAGE_VERSION` at runtime in order to +/// generate shaders which should work on a wide variety of modern devices +/// (GL >= 3.3 and GLES >= 2.0 are expected to work). +struct Shaders { + program: G::Program, + texture_uniform_location: G::UniformLocation, + matrix_uniform_location: G::UniformLocation, + position_attribute_index: u32, + uv_attribute_index: u32, + color_attribute_index: u32, } -/// A generic shader provider that parses `GL_VERSION` and -/// `GL_SHADING_LANGUAGE_VERSION` at runtime in order to generate shaders which -/// should work on a wide variety of modern devices (GL >= 3.3 and GLES >= 2.0 -/// are expected to work). -pub struct AutoShaderProvider(GenericShaderData); +impl Shaders { + fn new(gl: &G, gl_version: GlVersion) -> Result { + let (vertex_source, fragment_source) = Self::get_shader_sources(gl, gl_version)?; -impl ShaderProvider for AutoShaderProvider { - fn initialize(&mut self, gl: &G, gl_version: GlVersion) -> Result<(), ShaderError> { + let vertex_shader = + unsafe { gl.create_shader(glow::VERTEX_SHADER) }.map_err(ShaderError::CreateShader)?; + unsafe { + gl.shader_source(vertex_shader, &vertex_source); + gl.compile_shader(vertex_shader); + if !gl.get_shader_compile_status(vertex_shader) { + return Err(ShaderError::CompileShader( + gl.get_shader_info_log(vertex_shader), + )); + } + } + + let fragment_shader = unsafe { gl.create_shader(glow::FRAGMENT_SHADER) } + .map_err(ShaderError::CreateShader)?; + unsafe { + gl.shader_source(fragment_shader, &fragment_source); + gl.compile_shader(fragment_shader); + if !gl.get_shader_compile_status(fragment_shader) { + return Err(ShaderError::CompileShader( + gl.get_shader_info_log(fragment_shader), + )); + } + } + + let program = unsafe { gl.create_program() }.map_err(ShaderError::CreateProgram)?; + unsafe { + gl.attach_shader(program, vertex_shader); + gl.attach_shader(program, fragment_shader); + gl.link_program(program); + + if !gl.get_program_link_status(program) { + return Err(ShaderError::LinkProgram(gl.get_program_info_log(program))); + } + + gl.detach_shader(program, vertex_shader); + gl.detach_shader(program, fragment_shader); + gl.delete_shader(vertex_shader); + gl.delete_shader(fragment_shader); + } + + Ok(unsafe { + Self { + program, + texture_uniform_location: gl + .get_uniform_location(program, "tex") + .ok_or_else(|| ShaderError::UniformNotFound("tex".into()))?, + matrix_uniform_location: gl + .get_uniform_location(program, "matrix") + .ok_or_else(|| ShaderError::UniformNotFound("matrix".into()))?, + position_attribute_index: gl + .get_attrib_location(program, "position") + .ok_or_else(|| ShaderError::AttributeNotFound("position".into()))?, + uv_attribute_index: gl + .get_attrib_location(program, "uv") + .ok_or_else(|| ShaderError::AttributeNotFound("uv".into()))?, + color_attribute_index: gl + .get_attrib_location(program, "color") + .ok_or_else(|| ShaderError::AttributeNotFound("color".into()))?, + } + }) + } + + fn get_shader_sources(gl: &G, gl_version: GlVersion) -> Result<(String, String), ShaderError> { const VERTEX_BODY: &str = r#" layout (location = 0) in vec2 position; layout (location = 1) in vec2 uv; @@ -897,170 +926,8 @@ void main() { body = FRAGMENT_BODY, ); - create_shaders(&mut self.0, gl, &vertex_source, &fragment_source) + Ok((vertex_source, fragment_source)) } - - fn data(&self) -> &GenericShaderData { - &self.0 - } -} - -impl Default for AutoShaderProvider { - fn default() -> Self { - Self( as Default>::default()) - } -} - -/// A shader provider for specific shaders for OpenGL ES (GLSL ES) version(s) -/// 3.0 -#[derive(Default)] -pub struct Es3ShaderProvider(GenericShaderData); - -impl ShaderProvider for Es3ShaderProvider { - fn initialize(&mut self, gl: &G, gl_version: GlVersion) -> Result<(), ShaderError> { - const VERTEX_SOURCE: &str = r#"#version 300 es -precision mediump float; - -layout (location = 0) in vec2 position; -layout (location = 1) in vec2 uv; -layout (location = 2) in vec4 color; - -uniform mat4 matrix; -out vec2 fragment_uv; -out vec4 fragment_color; - -void main() { - fragment_uv = uv; - fragment_color = color; - gl_Position = matrix * vec4(position.xy, 0, 1); -} -"#; - const FRAGMENT_SOURCE: &str = r#"#version 300 es -precision mediump float; - -in vec2 fragment_uv; -in vec4 fragment_color; - -uniform sampler2D tex; -layout (location = 0) out vec4 out_color; - -void main() { - out_color = fragment_color * texture(tex, fragment_uv.st); -} -"#; - - if !gl_version.is_gles { - return Err(ShaderError::IncompatibleVersion(format!( - "A version of OpenGL ES is required for this shader, found: {}.{}", - gl_version.major, gl_version.minor - ))); - } - if gl_version < GlVersion::gles(3, 0) { - return Err(ShaderError::IncompatibleVersion(format!( - "This shader requires OpenGL ES version 3.0 or higher, found: ES {}.{}", - gl_version.major, gl_version.minor - ))); - } - - create_shaders(&mut self.0, gl, VERTEX_SOURCE, FRAGMENT_SOURCE) - } - - fn data(&self) -> &GenericShaderData { - &self.0 - } -} - -pub struct GenericShaderData { - pub program: G::Program, - pub texture_uniform_location: G::UniformLocation, - pub matrix_uniform_location: G::UniformLocation, - pub position_attribute_index: u32, - pub uv_attribute_index: u32, - pub color_attribute_index: u32, -} - -impl Default for GenericShaderData { - fn default() -> Self { - Self { - program: Default::default(), - texture_uniform_location: Default::default(), - matrix_uniform_location: Default::default(), - position_attribute_index: Default::default(), - uv_attribute_index: Default::default(), - color_attribute_index: Default::default(), - } - } -} - -/// # Errors -/// Any error creating OpenGL objects, compiling, or linking the given shaders -/// results in an error. -pub fn create_shaders( - data: &mut GenericShaderData, - gl: &G, - vertex_source: &str, - fragment_source: &str, -) -> Result<(), ShaderError> { - let vertex_shader = - unsafe { gl.create_shader(glow::VERTEX_SHADER) }.map_err(ShaderError::CreateShader)?; - unsafe { - gl.shader_source(vertex_shader, vertex_source); - gl.compile_shader(vertex_shader); - if !gl.get_shader_compile_status(vertex_shader) { - return Err(ShaderError::CompileShader( - gl.get_shader_info_log(vertex_shader), - )); - } - } - - let fragment_shader = - unsafe { gl.create_shader(glow::FRAGMENT_SHADER) }.map_err(ShaderError::CreateShader)?; - unsafe { - gl.shader_source(fragment_shader, fragment_source); - gl.compile_shader(fragment_shader); - if !gl.get_shader_compile_status(fragment_shader) { - return Err(ShaderError::CompileShader( - gl.get_shader_info_log(fragment_shader), - )); - } - } - - let program = unsafe { gl.create_program() }.map_err(ShaderError::CreateProgram)?; - unsafe { - gl.attach_shader(program, vertex_shader); - gl.attach_shader(program, fragment_shader); - gl.link_program(program); - - if !gl.get_program_link_status(program) { - return Err(ShaderError::LinkProgram(gl.get_program_info_log(program))); - } - - gl.detach_shader(program, vertex_shader); - gl.detach_shader(program, fragment_shader); - gl.delete_shader(vertex_shader); - gl.delete_shader(fragment_shader); - } - - data.program = program; - unsafe { - data.texture_uniform_location = gl - .get_uniform_location(program, "tex") - .ok_or_else(|| ShaderError::UniformNotFound("tex".into()))?; - data.matrix_uniform_location = gl - .get_uniform_location(program, "matrix") - .ok_or_else(|| ShaderError::UniformNotFound("matrix".into()))?; - data.position_attribute_index = gl - .get_attrib_location(program, "position") - .ok_or_else(|| ShaderError::AttributeNotFound("position".into()))?; - data.uv_attribute_index = gl - .get_attrib_location(program, "uv") - .ok_or_else(|| ShaderError::AttributeNotFound("uv".into()))?; - data.color_attribute_index = gl - .get_attrib_location(program, "color") - .ok_or_else(|| ShaderError::AttributeNotFound("color".into()))?; - } - - Ok(()) } #[derive(Debug)]