summaryrefslogtreecommitdiffstats
path: root/glow
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2022-11-03 18:57:09 +0100
committerLibravatar GitHub <noreply@github.com>2022-11-03 18:57:09 +0100
commitd222b5c8b0befab665c20ba0112b28199df0ae44 (patch)
tree0ac3a59f04e1c1ca89ff43800efbefd825b015ea /glow
parenta8f510c39917b2ac42fcc854f0a7eff13aee9838 (diff)
parentf31c8f2504ea7c004c5caed8913e5da28d2e50e2 (diff)
downloadiced-d222b5c8b0befab665c20ba0112b28199df0ae44.tar.gz
iced-d222b5c8b0befab665c20ba0112b28199df0ae44.tar.bz2
iced-d222b5c8b0befab665c20ba0112b28199df0ae44.zip
Merge pull request #1448 from bungoboingo/fear/linear-gradients
Add linear gradient support to canvas widget
Diffstat (limited to 'glow')
-rw-r--r--glow/src/backend.rs5
-rw-r--r--glow/src/quad/compatibility.rs6
-rw-r--r--glow/src/quad/core.rs6
-rw-r--r--glow/src/shader/common/gradient.frag59
-rw-r--r--glow/src/shader/common/triangle.frag6
-rw-r--r--glow/src/shader/common/triangle.vert8
-rw-r--r--glow/src/triangle.rs226
-rw-r--r--glow/src/triangle/gradient.rs162
-rw-r--r--glow/src/triangle/solid.rs91
-rw-r--r--glow/src/window/compositor.rs7
10 files changed, 419 insertions, 157 deletions
diff --git a/glow/src/backend.rs b/glow/src/backend.rs
index 78d4229e..21af2ecf 100644
--- a/glow/src/backend.rs
+++ b/glow/src/backend.rs
@@ -1,7 +1,6 @@
-use crate::program;
use crate::quad;
use crate::text;
-use crate::triangle;
+use crate::{program, triangle};
use crate::{Settings, Transformation, Viewport};
use iced_graphics::backend;
@@ -105,11 +104,11 @@ impl Backend {
* Transformation::scale(scale_factor, scale_factor);
self.triangle_pipeline.draw(
+ &layer.meshes,
gl,
target_height,
scaled,
scale_factor,
- &layer.meshes,
);
}
diff --git a/glow/src/quad/compatibility.rs b/glow/src/quad/compatibility.rs
index eb3fb7e0..28a5ea7c 100644
--- a/glow/src/quad/compatibility.rs
+++ b/glow/src/quad/compatibility.rs
@@ -70,11 +70,10 @@ impl Pipeline {
unsafe {
gl.use_program(Some(program));
- let matrix: [f32; 16] = Transformation::identity().into();
gl.uniform_matrix_4_f32_slice(
Some(&transform_location),
false,
- &matrix,
+ Transformation::identity().as_ref(),
);
gl.uniform_1_f32(Some(&scale_location), 1.0);
@@ -139,11 +138,10 @@ impl Pipeline {
if transformation != self.current_transform {
unsafe {
- let matrix: [f32; 16] = transformation.into();
gl.uniform_matrix_4_f32_slice(
Some(&self.transform_location),
false,
- &matrix,
+ transformation.as_ref(),
);
self.current_transform = transformation;
diff --git a/glow/src/quad/core.rs b/glow/src/quad/core.rs
index 3e51b1ca..16bec385 100644
--- a/glow/src/quad/core.rs
+++ b/glow/src/quad/core.rs
@@ -65,11 +65,10 @@ impl Pipeline {
unsafe {
gl.use_program(Some(program));
- let matrix: [f32; 16] = Transformation::identity().into();
gl.uniform_matrix_4_f32_slice(
Some(&transform_location),
false,
- &matrix,
+ Transformation::identity().as_ref(),
);
gl.uniform_1_f32(Some(&scale_location), 1.0);
@@ -119,11 +118,10 @@ impl Pipeline {
if transformation != self.current_transform {
unsafe {
- let matrix: [f32; 16] = transformation.into();
gl.uniform_matrix_4_f32_slice(
Some(&self.transform_location),
false,
- &matrix,
+ transformation.as_ref(),
);
self.current_transform = transformation;
diff --git a/glow/src/shader/common/gradient.frag b/glow/src/shader/common/gradient.frag
new file mode 100644
index 00000000..42d0201f
--- /dev/null
+++ b/glow/src/shader/common/gradient.frag
@@ -0,0 +1,59 @@
+#ifdef GL_ES
+ #ifdef GL_FRAGMENT_PRECISION_HIGH
+ precision highp float;
+ #else
+ precision mediump float;
+ #endif
+#endif
+
+#ifdef HIGHER_THAN_300
+ layout (location = 0) out vec4 fragColor;
+ #define gl_FragColor fragColor
+#endif
+
+in vec2 raw_position;
+
+uniform vec4 gradient_direction;
+uniform uint color_stops_size;
+// GLSL does not support dynamically sized arrays without SSBOs so this is capped to 16 stops
+//stored as color(vec4) -> offset(vec4) sequentially;
+uniform vec4 color_stops[32];
+
+//TODO: rewrite without branching to make ALUs happy
+void main() {
+ vec2 start = gradient_direction.xy;
+ vec2 end = gradient_direction.zw;
+ vec2 gradient_vec = vec2(end - start);
+ vec2 current_vec = vec2(raw_position.xy - start);
+ vec2 unit = normalize(gradient_vec);
+ float coord_offset = dot(unit, current_vec) / length(gradient_vec);
+ //if a gradient has a start/end stop that is identical, the mesh will have a transparent fill
+ fragColor = vec4(0.0, 0.0, 0.0, 0.0);
+
+ float min_offset = color_stops[1].x;
+ float max_offset = color_stops[color_stops_size - 1u].x;
+
+ for (uint i = 0u; i < color_stops_size - 2u; i += 2u) {
+ float curr_offset = color_stops[i+1u].x;
+ float next_offset = color_stops[i+3u].x;
+
+ if (coord_offset <= min_offset) {
+ //current coordinate is before the first defined offset, set it to the start color
+ fragColor = color_stops[0];
+ }
+
+ if (curr_offset <= coord_offset && coord_offset <= next_offset) {
+ //current fragment is between the current offset processing & the next one, interpolate colors
+ fragColor = mix(color_stops[i], color_stops[i+2u], smoothstep(
+ curr_offset,
+ next_offset,
+ coord_offset
+ ));
+ }
+
+ if (coord_offset >= max_offset) {
+ //current coordinate is before the last defined offset, set it to the last color
+ fragColor = color_stops[color_stops_size - 2u];
+ }
+ }
+}
diff --git a/glow/src/shader/common/triangle.frag b/glow/src/shader/common/triangle.frag
index e8689f2e..ead40fe5 100644
--- a/glow/src/shader/common/triangle.frag
+++ b/glow/src/shader/common/triangle.frag
@@ -11,8 +11,8 @@ out vec4 fragColor;
#define gl_FragColor fragColor
#endif
-in vec4 v_Color;
+uniform vec4 color;
void main() {
- gl_FragColor = v_Color;
-} \ No newline at end of file
+ fragColor = color;
+}
diff --git a/glow/src/shader/common/triangle.vert b/glow/src/shader/common/triangle.vert
index d0494a5f..fe505997 100644
--- a/glow/src/shader/common/triangle.vert
+++ b/glow/src/shader/common/triangle.vert
@@ -1,11 +1,9 @@
uniform mat4 u_Transform;
in vec2 i_Position;
-in vec4 i_Color;
-
-out vec4 v_Color;
+out vec2 raw_position;
void main() {
gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0);
- v_Color = i_Color;
-} \ No newline at end of file
+ raw_position = i_Position;
+}
diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs
index ae4f83ef..0e27bcf2 100644
--- a/glow/src/triangle.rs
+++ b/glow/src/triangle.rs
@@ -1,66 +1,32 @@
//! Draw meshes of triangles.
-use crate::program::{self, Shader};
+mod gradient;
+mod solid;
+
+use crate::program;
use crate::Transformation;
-use glow::HasContext;
-use iced_graphics::layer;
-use std::marker::PhantomData;
-pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
+use iced_graphics::layer::mesh::{self, Mesh};
+use iced_graphics::triangle::{self, Vertex2D};
-const VERTEX_BUFFER_SIZE: usize = 10_000;
-const INDEX_BUFFER_SIZE: usize = 10_000;
+use glow::HasContext;
+use std::marker::PhantomData;
#[derive(Debug)]
pub(crate) struct Pipeline {
- program: <glow::Context as HasContext>::Program,
vertex_array: <glow::Context as HasContext>::VertexArray,
vertices: Buffer<Vertex2D>,
indices: Buffer<u32>,
- transform_location: <glow::Context as HasContext>::UniformLocation,
- current_transform: Transformation,
+ programs: ProgramList,
}
-impl Pipeline {
- pub fn new(
- gl: &glow::Context,
- shader_version: &program::Version,
- ) -> Pipeline {
- let program = unsafe {
- let vertex_shader = Shader::vertex(
- gl,
- shader_version,
- include_str!("shader/common/triangle.vert"),
- );
- let fragment_shader = Shader::fragment(
- gl,
- shader_version,
- include_str!("shader/common/triangle.frag"),
- );
-
- program::create(
- gl,
- &[vertex_shader, fragment_shader],
- &[(0, "i_Position"), (1, "i_Color")],
- )
- };
-
- let transform_location =
- unsafe { gl.get_uniform_location(program, "u_Transform") }
- .expect("Get transform location");
-
- unsafe {
- gl.use_program(Some(program));
-
- let transform: [f32; 16] = Transformation::identity().into();
- gl.uniform_matrix_4_f32_slice(
- Some(&transform_location),
- false,
- &transform,
- );
-
- gl.use_program(None);
- }
+#[derive(Debug)]
+struct ProgramList {
+ solid: solid::Program,
+ gradient: gradient::Program,
+}
+impl Pipeline {
+ pub fn new(gl: &glow::Context, shader_version: &program::Version) -> Self {
let vertex_array =
unsafe { gl.create_vertex_array().expect("Create vertex array") };
@@ -73,7 +39,7 @@ impl Pipeline {
gl,
glow::ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
- VERTEX_BUFFER_SIZE,
+ std::mem::size_of::<Vertex2D>() as usize,
)
};
@@ -82,7 +48,7 @@ impl Pipeline {
gl,
glow::ELEMENT_ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
- INDEX_BUFFER_SIZE,
+ std::mem::size_of::<u32>() as usize,
)
};
@@ -92,83 +58,63 @@ impl Pipeline {
gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0);
- gl.enable_vertex_attrib_array(1);
- gl.vertex_attrib_pointer_f32(
- 1,
- 4,
- glow::FLOAT,
- false,
- stride,
- 4 * 2,
- );
-
gl.bind_vertex_array(None);
- }
+ };
- Pipeline {
- program,
+ Self {
vertex_array,
vertices,
indices,
- transform_location,
- current_transform: Transformation::identity(),
+ programs: ProgramList {
+ solid: solid::Program::new(gl, shader_version),
+ gradient: gradient::Program::new(gl, shader_version),
+ },
}
}
pub fn draw(
&mut self,
+ meshes: &[Mesh<'_>],
gl: &glow::Context,
target_height: u32,
transformation: Transformation,
scale_factor: f32,
- meshes: &[layer::Mesh<'_>],
) {
unsafe {
gl.enable(glow::MULTISAMPLE);
gl.enable(glow::SCISSOR_TEST);
- gl.use_program(Some(self.program));
- gl.bind_vertex_array(Some(self.vertex_array));
+ gl.bind_vertex_array(Some(self.vertex_array))
}
- // This looks a bit crazy, but we are just counting how many vertices
- // and indices we will need to handle.
- // TODO: Improve readability
- let (total_vertices, total_indices) = meshes
- .iter()
- .map(|layer::Mesh { buffers, .. }| {
- (buffers.vertices.len(), buffers.indices.len())
- })
- .fold((0, 0), |(total_v, total_i), (v, i)| {
- (total_v + v, total_i + i)
- });
-
- // Then we ensure the current buffers are big enough, resizing if
- // necessary
+ //count the total amount of vertices & indices we need to handle
+ let (total_vertices, total_indices) = mesh::attribute_count_of(meshes);
+
+ // Then we ensure the current attribute buffers are big enough, resizing if necessary
unsafe {
self.vertices.bind(gl, total_vertices);
self.indices.bind(gl, total_indices);
}
// We upload all the vertices and indices upfront
- let mut last_vertex = 0;
- let mut last_index = 0;
+ let mut vertex_offset = 0;
+ let mut index_offset = 0;
- for layer::Mesh { buffers, .. } in meshes {
+ for mesh in meshes {
unsafe {
gl.buffer_sub_data_u8_slice(
glow::ARRAY_BUFFER,
- (last_vertex * std::mem::size_of::<Vertex2D>()) as i32,
- bytemuck::cast_slice(&buffers.vertices),
+ (vertex_offset * std::mem::size_of::<Vertex2D>()) as i32,
+ bytemuck::cast_slice(&mesh.buffers.vertices),
);
gl.buffer_sub_data_u8_slice(
glow::ELEMENT_ARRAY_BUFFER,
- (last_index * std::mem::size_of::<u32>()) as i32,
- bytemuck::cast_slice(&buffers.indices),
+ (index_offset * std::mem::size_of::<u32>()) as i32,
+ bytemuck::cast_slice(&mesh.buffers.indices),
);
- last_vertex += buffers.vertices.len();
- last_index += buffers.indices.len();
+ vertex_offset += mesh.buffers.vertices.len();
+ index_offset += mesh.buffers.indices.len();
}
}
@@ -176,29 +122,13 @@ impl Pipeline {
let mut last_vertex = 0;
let mut last_index = 0;
- for layer::Mesh {
- buffers,
- origin,
- clip_bounds,
- } in meshes
- {
- let transform =
- transformation * Transformation::translate(origin.x, origin.y);
+ for mesh in meshes {
+ let transform = transformation
+ * Transformation::translate(mesh.origin.x, mesh.origin.y);
- let clip_bounds = (*clip_bounds * scale_factor).snap();
+ let clip_bounds = (mesh.clip_bounds * scale_factor).snap();
unsafe {
- if self.current_transform != transform {
- let matrix: [f32; 16] = transform.into();
- gl.uniform_matrix_4_f32_slice(
- Some(&self.transform_location),
- false,
- &matrix,
- );
-
- self.current_transform = transform;
- }
-
gl.scissor(
clip_bounds.x as i32,
(target_height - (clip_bounds.y + clip_bounds.height))
@@ -207,50 +137,74 @@ impl Pipeline {
clip_bounds.height as i32,
);
+ match mesh.style {
+ triangle::Style::Solid(color) => {
+ self.programs.solid.use_program(gl, color, &transform);
+ }
+ triangle::Style::Gradient(gradient) => {
+ self.programs
+ .gradient
+ .use_program(gl, gradient, &transform);
+ }
+ }
+
gl.draw_elements_base_vertex(
glow::TRIANGLES,
- buffers.indices.len() as i32,
+ mesh.buffers.indices.len() as i32,
glow::UNSIGNED_INT,
(last_index * std::mem::size_of::<u32>()) as i32,
last_vertex as i32,
);
- last_vertex += buffers.vertices.len();
- last_index += buffers.indices.len();
+ last_vertex += mesh.buffers.vertices.len();
+ last_index += mesh.buffers.indices.len();
}
}
unsafe {
gl.bind_vertex_array(None);
- gl.use_program(None);
gl.disable(glow::SCISSOR_TEST);
gl.disable(glow::MULTISAMPLE);
}
}
}
-#[repr(C)]
-#[derive(Debug, Clone, Copy)]
-struct Uniforms {
- transform: [f32; 16],
-}
-
-unsafe impl bytemuck::Zeroable for Uniforms {}
-unsafe impl bytemuck::Pod for Uniforms {}
-
-impl Default for Uniforms {
- fn default() -> Self {
- Self {
- transform: *Transformation::identity().as_ref(),
- }
+/// A simple shader program. Uses [`triangle.vert`] for its vertex shader and only binds position
+/// attribute location.
+pub(super) fn program(
+ gl: &glow::Context,
+ shader_version: &program::Version,
+ fragment_shader: &'static str,
+) -> <glow::Context as HasContext>::Program {
+ unsafe {
+ let vertex_shader = program::Shader::vertex(
+ gl,
+ shader_version,
+ include_str!("shader/common/triangle.vert"),
+ );
+
+ let fragment_shader =
+ program::Shader::fragment(gl, shader_version, fragment_shader);
+
+ program::create(
+ gl,
+ &[vertex_shader, fragment_shader],
+ &[(0, "i_Position")],
+ )
}
}
-impl From<Transformation> for Uniforms {
- fn from(transformation: Transformation) -> Uniforms {
- Self {
- transform: transformation.into(),
- }
+pub fn set_transform(
+ gl: &glow::Context,
+ location: <glow::Context as HasContext>::UniformLocation,
+ transform: Transformation,
+) {
+ unsafe {
+ gl.uniform_matrix_4_f32_slice(
+ Some(&location),
+ false,
+ transform.as_ref(),
+ );
}
}
diff --git a/glow/src/triangle/gradient.rs b/glow/src/triangle/gradient.rs
new file mode 100644
index 00000000..5225612e
--- /dev/null
+++ b/glow/src/triangle/gradient.rs
@@ -0,0 +1,162 @@
+use crate::program::Version;
+use crate::triangle;
+use glow::{Context, HasContext, NativeProgram};
+use iced_graphics::gradient::Gradient;
+use iced_graphics::gradient::Linear;
+use iced_graphics::Transformation;
+
+#[derive(Debug)]
+pub struct Program {
+ pub program: <Context as HasContext>::Program,
+ pub uniform_data: UniformData,
+}
+
+#[derive(Debug)]
+pub struct UniformData {
+ gradient: Gradient,
+ transform: Transformation,
+ uniform_locations: UniformLocations,
+}
+
+#[derive(Debug)]
+struct UniformLocations {
+ gradient_direction_location: <Context as HasContext>::UniformLocation,
+ color_stops_size_location: <Context as HasContext>::UniformLocation,
+ //currently the maximum number of stops is 16 due to lack of SSBO in GL2.1
+ color_stops_location: <Context as HasContext>::UniformLocation,
+ transform_location: <Context as HasContext>::UniformLocation,
+}
+
+impl Program {
+ pub fn new(gl: &Context, shader_version: &Version) -> Self {
+ let program = triangle::program(
+ gl,
+ shader_version,
+ include_str!("../shader/common/gradient.frag"),
+ );
+
+ Self {
+ program,
+ uniform_data: UniformData::new(gl, program),
+ }
+ }
+
+ pub fn write_uniforms(
+ &mut self,
+ gl: &Context,
+ gradient: &Gradient,
+ transform: &Transformation,
+ ) {
+ if transform != &self.uniform_data.transform {
+ triangle::set_transform(
+ gl,
+ self.uniform_data.uniform_locations.transform_location,
+ *transform,
+ );
+ }
+
+ if &self.uniform_data.gradient != gradient {
+ match gradient {
+ Gradient::Linear(linear) => unsafe {
+ gl.uniform_4_f32(
+ Some(
+ &self
+ .uniform_data
+ .uniform_locations
+ .gradient_direction_location,
+ ),
+ linear.start.x,
+ linear.start.y,
+ linear.end.x,
+ linear.end.y,
+ );
+
+ gl.uniform_1_u32(
+ Some(
+ &self
+ .uniform_data
+ .uniform_locations
+ .color_stops_size_location,
+ ),
+ (linear.color_stops.len() * 2) as u32,
+ );
+
+ let mut stops = [0.0; 128];
+
+ for (index, stop) in
+ linear.color_stops.iter().enumerate().take(16)
+ {
+ let [r, g, b, a] = stop.color.into_linear();
+
+ stops[index * 8] = r;
+ stops[(index * 8) + 1] = g;
+ stops[(index * 8) + 2] = b;
+ stops[(index * 8) + 3] = a;
+ stops[(index * 8) + 4] = stop.offset;
+ stops[(index * 8) + 5] = 0.;
+ stops[(index * 8) + 6] = 0.;
+ stops[(index * 8) + 7] = 0.;
+ }
+
+ gl.uniform_4_f32_slice(
+ Some(
+ &self
+ .uniform_data
+ .uniform_locations
+ .color_stops_location,
+ ),
+ &stops,
+ );
+ },
+ }
+
+ self.uniform_data.gradient = gradient.clone();
+ }
+ }
+
+ pub fn use_program(
+ &mut self,
+ gl: &Context,
+ gradient: &Gradient,
+ transform: &Transformation,
+ ) {
+ unsafe { gl.use_program(Some(self.program)) }
+ self.write_uniforms(gl, gradient, transform);
+ }
+}
+
+impl UniformData {
+ fn new(gl: &Context, program: NativeProgram) -> Self {
+ let gradient_direction_location =
+ unsafe { gl.get_uniform_location(program, "gradient_direction") }
+ .expect("Gradient - Get gradient_direction.");
+
+ let color_stops_size_location =
+ unsafe { gl.get_uniform_location(program, "color_stops_size") }
+ .expect("Gradient - Get color_stops_size.");
+
+ let color_stops_location = unsafe {
+ gl.get_uniform_location(program, "color_stops")
+ .expect("Gradient - Get color_stops.")
+ };
+
+ let transform_location =
+ unsafe { gl.get_uniform_location(program, "u_Transform") }
+ .expect("Gradient - Get u_Transform.");
+
+ Self {
+ gradient: Gradient::Linear(Linear {
+ start: Default::default(),
+ end: Default::default(),
+ color_stops: vec![],
+ }),
+ transform: Transformation::identity(),
+ uniform_locations: UniformLocations {
+ gradient_direction_location,
+ color_stops_size_location,
+ color_stops_location,
+ transform_location,
+ },
+ }
+ }
+}
diff --git a/glow/src/triangle/solid.rs b/glow/src/triangle/solid.rs
new file mode 100644
index 00000000..fb3d40c3
--- /dev/null
+++ b/glow/src/triangle/solid.rs
@@ -0,0 +1,91 @@
+use crate::program::Version;
+use crate::{triangle, Color};
+use glow::{Context, HasContext, NativeProgram};
+use iced_graphics::Transformation;
+
+#[derive(Debug)]
+pub struct Program {
+ program: <Context as HasContext>::Program,
+ uniform_data: UniformData,
+}
+
+#[derive(Debug)]
+struct UniformData {
+ pub color: Color,
+ pub color_location: <Context as HasContext>::UniformLocation,
+ pub transform: Transformation,
+ pub transform_location: <Context as HasContext>::UniformLocation,
+}
+
+impl UniformData {
+ fn new(gl: &Context, program: NativeProgram) -> Self {
+ Self {
+ color: Color::TRANSPARENT,
+ color_location: unsafe {
+ gl.get_uniform_location(program, "color")
+ }
+ .expect("Solid - Get color."),
+ transform: Transformation::identity(),
+ transform_location: unsafe {
+ gl.get_uniform_location(program, "u_Transform")
+ }
+ .expect("Solid - Get u_Transform."),
+ }
+ }
+}
+
+impl Program {
+ pub fn new(gl: &Context, shader_version: &Version) -> Self {
+ let program = triangle::program(
+ gl,
+ shader_version,
+ include_str!("../shader/common/triangle.frag"),
+ );
+
+ Self {
+ program,
+ uniform_data: UniformData::new(gl, program),
+ }
+ }
+
+ pub fn write_uniforms(
+ &mut self,
+ gl: &Context,
+ color: &Color,
+ transform: &Transformation,
+ ) {
+ if transform != &self.uniform_data.transform {
+ triangle::set_transform(
+ gl,
+ self.uniform_data.transform_location,
+ *transform,
+ )
+ }
+
+ if color != &self.uniform_data.color {
+ let [r, g, b, a] = color.into_linear();
+
+ unsafe {
+ gl.uniform_4_f32(
+ Some(&self.uniform_data.color_location),
+ r,
+ g,
+ b,
+ a,
+ );
+ }
+
+ self.uniform_data.color = *color;
+ }
+ }
+
+ pub fn use_program(
+ &mut self,
+ gl: &Context,
+ color: &Color,
+ transform: &Transformation,
+ ) {
+ unsafe { gl.use_program(Some(self.program)) }
+ self.write_uniforms(gl, color, transform)
+ }
+}
diff --git a/glow/src/window/compositor.rs b/glow/src/window/compositor.rs
index f6afaa68..20756032 100644
--- a/glow/src/window/compositor.rs
+++ b/glow/src/window/compositor.rs
@@ -26,8 +26,11 @@ impl<Theme> iced_graphics::window::GLCompositor for Compositor<Theme> {
log::info!("{:#?}", settings);
let version = gl.version();
- log::info!("Version: {:?}", version);
- log::info!("Embedded: {}", version.is_embedded);
+ log::info!(
+ "OpenGL version: {:?} (Embedded: {})",
+ version,
+ version.is_embedded
+ );
let renderer = gl.get_parameter_string(glow::RENDERER);
log::info!("Renderer: {}", renderer);