diff --git a/blade-graphics/src/gles/egl.rs b/blade-graphics/src/gles/egl.rs index 30522174..6b9c4054 100644 --- a/blade-graphics/src/gles/egl.rs +++ b/blade-graphics/src/gles/egl.rs @@ -105,12 +105,12 @@ struct WindowSystemInterface { window_handle: raw_window_handle::RawWindowHandle, renderbuf: glow::Renderbuffer, framebuf: glow::Framebuffer, - surface_format: crate::TextureFormat, } struct Swapchain { surface: egl::Surface, extent: crate::Extent, + format: crate::TextureFormat, } struct ContextInner { @@ -316,7 +316,6 @@ impl Context { window_handle: window.raw_window_handle(), renderbuf, framebuf, - surface_format: crate::TextureFormat::Rgba8Unorm, }), inner: Mutex::new(ContextInner { egl: egl_context, @@ -389,6 +388,8 @@ impl Context { egl::SINGLE_BUFFER }, ]; + + //TODO: detect if linear color space is supported match inner.egl.srgb_kind { SrgbFrameBufferKind::None => {} SrgbFrameBufferKind::Core => { @@ -402,6 +403,11 @@ impl Context { } attributes.push(egl::ATTRIB_NONE as i32); + let format = match config.color_space { + crate::ColorSpace::Linear => crate::TextureFormat::Rgba8UnormSrgb, + crate::ColorSpace::Srgb => crate::TextureFormat::Rgba8Unorm, + }; + // Careful, we can still be in 1.4 version even if `upcast` succeeds let surface = match inner.egl.instance.upcast::() { Some(egl) => { @@ -434,9 +440,10 @@ impl Context { inner.swapchain = Some(Swapchain { surface, extent: config.size, + format, }); - let format_desc = super::describe_texture_format(wsi.surface_format); + let format_desc = super::describe_texture_format(format); inner.egl.make_current(); unsafe { let gl = &inner.glow; @@ -459,7 +466,7 @@ impl Context { }; inner.egl.unmake_current(); - wsi.surface_format + format } pub fn acquire_frame(&self) -> super::Frame { @@ -470,7 +477,7 @@ impl Context { texture: super::Texture { inner: super::TextureInner::Renderbuffer { raw: wsi.renderbuf }, target_size: [sc.extent.width as u16, sc.extent.height as u16], - format: wsi.surface_format, + format: sc.format, }, } } diff --git a/blade-graphics/src/lib.rs b/blade-graphics/src/lib.rs index a04068a3..39f620eb 100644 --- a/blade-graphics/src/lib.rs +++ b/blade-graphics/src/lib.rs @@ -959,11 +959,25 @@ pub struct RenderTargetSet<'a> { pub depth_stencil: Option, } +#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] +pub enum ColorSpace { + #[default] + Linear, + Srgb, +} + #[derive(Debug)] pub struct SurfaceConfig { pub size: Extent, pub usage: TextureUsage, pub frame_count: u32, + /// The color space that render output colors are expected to be in. + /// + /// This will affect the surface format returned by the `Context`. + /// + /// For example, if the display expects sRGB space and we render + /// in `ColorSpace::Linear` space, the returned format will be sRGB. + pub color_space: ColorSpace, } #[derive(Clone, Copy, Debug, PartialEq)] diff --git a/blade-graphics/src/metal/mod.rs b/blade-graphics/src/metal/mod.rs index 54319a6b..a3f136dd 100644 --- a/blade-graphics/src/metal/mod.rs +++ b/blade-graphics/src/metal/mod.rs @@ -15,7 +15,6 @@ mod surface; struct Surface { view: *mut objc::runtime::Object, render_layer: metal::MetalLayer, - format: crate::TextureFormat, } unsafe impl Send for Surface {} diff --git a/blade-graphics/src/metal/surface.rs b/blade-graphics/src/metal/surface.rs index c6fc5ac1..d197e6ab 100644 --- a/blade-graphics/src/metal/surface.rs +++ b/blade-graphics/src/metal/surface.rs @@ -63,15 +63,23 @@ impl super::Surface { Self { view: msg_send![view, retain], render_layer: mem::transmute::<_, &metal::MetalLayerRef>(raw_layer).to_owned(), - format: crate::TextureFormat::Bgra8UnormSrgb, } } - fn reconfigure(&mut self, device: &metal::DeviceRef, config: crate::SurfaceConfig) { + fn reconfigure( + &mut self, + device: &metal::DeviceRef, + config: crate::SurfaceConfig, + ) -> crate::TextureFormat { + let format = match config.color_space { + crate::ColorSpace::Linear => crate::TextureFormat::Bgra8UnormSrgb, + crate::ColorSpace::Srgb => crate::TextureFormat::Bgra8Unorm, + }; + self.render_layer.set_opaque(true); self.render_layer.set_device(device); self.render_layer - .set_pixel_format(super::map_texture_format(self.format)); + .set_pixel_format(super::map_texture_format(format)); self.render_layer .set_framebuffer_only(config.usage == crate::TextureUsage::TARGET); self.render_layer @@ -83,14 +91,15 @@ impl super::Surface { unsafe { let () = msg_send![self.render_layer, setDisplaySyncEnabled: true]; } + + format } } impl super::Context { pub fn resize(&self, config: crate::SurfaceConfig) -> crate::TextureFormat { let mut surface = self.surface.as_ref().unwrap().lock().unwrap(); - surface.reconfigure(&*self.device.lock().unwrap(), config); - surface.format + surface.reconfigure(&*self.device.lock().unwrap(), config) } pub fn acquire_frame(&self) -> super::Frame { diff --git a/blade-graphics/src/vulkan/init.rs b/blade-graphics/src/vulkan/init.rs index c90541a2..26a55cbf 100644 --- a/blade-graphics/src/vulkan/init.rs +++ b/blade-graphics/src/vulkan/init.rs @@ -621,7 +621,11 @@ impl super::Context { } let queue_families = [self.queue_family_index]; - let format = crate::TextureFormat::Bgra8UnormSrgb; + //TODO: consider supported color spaces by Vulkan + let format = match config.color_space { + crate::ColorSpace::Linear => crate::TextureFormat::Bgra8UnormSrgb, + crate::ColorSpace::Srgb => crate::TextureFormat::Bgra8Unorm, + }; let vk_format = super::map_texture_format(format); let create_info = vk::SwapchainCreateInfoKHR::builder() .surface(surface.raw) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index aa68d0fd..70c53178 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,9 @@ Changelog for Blade - support object motion - support clockwise mesh winding +## blade-graphics-0.4 (TBD) +- color space configuration for surfaces + ## blade-graphics-0.3, blade-render-0.2 (17 Nov 2023) - tangent space generation - spatio-temporal resampling diff --git a/examples/bunnymark/main.rs b/examples/bunnymark/main.rs index ef3a8ab3..ac203f79 100644 --- a/examples/bunnymark/main.rs +++ b/examples/bunnymark/main.rs @@ -72,6 +72,7 @@ impl Example { }, usage: gpu::TextureUsage::TARGET, frame_count: 3, + color_space: gpu::ColorSpace::Linear, }); let global_layout = ::layout(); diff --git a/examples/particle/main.rs b/examples/particle/main.rs index 2b45eb3d..b59cd05b 100644 --- a/examples/particle/main.rs +++ b/examples/particle/main.rs @@ -34,6 +34,7 @@ impl Example { }, usage: gpu::TextureUsage::TARGET, frame_count: 3, + color_space: gpu::ColorSpace::Linear, }); let gui_painter = blade_egui::GuiPainter::new(surface_format, &context); let particle_system = particle::System::new( diff --git a/examples/ray-query/main.rs b/examples/ray-query/main.rs index 9f9dbb4f..9fc09de4 100644 --- a/examples/ray-query/main.rs +++ b/examples/ray-query/main.rs @@ -88,6 +88,7 @@ impl Example { size: screen_size, usage: gpu::TextureUsage::TARGET, frame_count: 3, + color_space: gpu::ColorSpace::Linear, }); let source = std::fs::read_to_string("examples/ray-query/shader.wgsl").unwrap(); diff --git a/examples/scene/main.rs b/examples/scene/main.rs index 72082cff..e7fee6a5 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -162,6 +162,7 @@ impl Example { }, usage: gpu::TextureUsage::TARGET, frame_count: 3, + color_space: gpu::ColorSpace::Linear, } } diff --git a/src/lib.rs b/src/lib.rs index ae076aa7..acb2ecbc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -237,6 +237,7 @@ impl Engine { }, usage: gpu::TextureUsage::TARGET, frame_count: 3, + color_space: gpu::ColorSpace::Linear, } }