From f958d416bbac40f17fe0d420910d8303e575c5e5 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 21 Apr 2024 22:21:37 -0700 Subject: [PATCH] Support transparency and forbidden full screen Extends SurfaceConfig with a few extra fields, adds Default derive, and switches the resize() result type to the new SurfaceInfo struct. --- blade-egui/src/lib.rs | 7 +- blade-graphics/src/gles/egl.rs | 23 +++-- blade-graphics/src/gles/web.rs | 10 ++- blade-graphics/src/lib.rs | 18 +++- blade-graphics/src/metal/surface.rs | 11 ++- blade-graphics/src/vulkan/init.rs | 131 ++++++++++++++++++++++++---- blade-graphics/src/vulkan/mod.rs | 1 + blade-render/code/blur.wgsl | 2 +- blade-render/src/render/debug.rs | 8 +- blade-render/src/render/mod.rs | 58 ++++++------ docs/CHANGELOG.md | 5 +- examples/bunnymark/main.rs | 6 +- examples/particle/main.rs | 8 +- examples/ray-query/main.rs | 9 +- examples/scene/main.rs | 18 ++-- src/lib.rs | 18 ++-- 16 files changed, 237 insertions(+), 96 deletions(-) diff --git a/blade-egui/src/lib.rs b/blade-egui/src/lib.rs index 2a70469c..1f7e9f74 100644 --- a/blade-egui/src/lib.rs +++ b/blade-egui/src/lib.rs @@ -120,10 +120,7 @@ impl GuiPainter { /// It supports renderpasses with only a color attachment, /// and this attachment format must be The `output_format`. #[profiling::function] - pub fn new( - output_format: blade_graphics::TextureFormat, - context: &blade_graphics::Context, - ) -> Self { + pub fn new(info: blade_graphics::SurfaceInfo, context: &blade_graphics::Context) -> Self { let shader = context.create_shader(blade_graphics::ShaderDesc { source: SHADER_SOURCE, }); @@ -141,7 +138,7 @@ impl GuiPainter { depth_stencil: None, //TODO? fragment: shader.at("fs_main"), color_targets: &[blade_graphics::ColorTargetState { - format: output_format, + format: info.format, blend: Some(blade_graphics::BlendState::ALPHA_BLENDING), write_mask: blade_graphics::ColorWrites::all(), }], diff --git a/blade-graphics/src/gles/egl.rs b/blade-graphics/src/gles/egl.rs index 56394f93..64bb45ae 100644 --- a/blade-graphics/src/gles/egl.rs +++ b/blade-graphics/src/gles/egl.rs @@ -17,8 +17,6 @@ const EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE: u32 = 0x3489; const EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE: u32 = 0x348F; const EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED: u32 = 0x3451; const EGL_PLATFORM_SURFACELESS_MESA: u32 = 0x31DD; -const EGL_GL_COLORSPACE_KHR: u32 = 0x309D; -const EGL_GL_COLORSPACE_SRGB_KHR: u32 = 0x3089; const EGL_DEBUG_MSG_CRITICAL_KHR: u32 = 0x33B9; const EGL_DEBUG_MSG_ERROR_KHR: u32 = 0x33BA; @@ -346,7 +344,7 @@ impl Context { }) } - pub fn resize(&self, config: crate::SurfaceConfig) -> crate::TextureFormat { + pub fn resize(&self, config: crate::SurfaceConfig) -> crate::SurfaceInfo { use raw_window_handle::RawWindowHandle as Rwh; let wsi = self.wsi.as_ref().unwrap(); @@ -394,6 +392,10 @@ impl Context { } }; + if !config.allow_exclusive_full_screen { + log::warn!("Unable to forbid exclusive full screen"); + } + let mut inner = self.inner.lock().unwrap(); let mut attributes = vec![ @@ -411,15 +413,18 @@ impl Context { //TODO: detect if linear color space is supported match inner.egl.srgb_kind { SrgbFrameBufferKind::None => {} - SrgbFrameBufferKind::Core => { + SrgbFrameBufferKind::Core | SrgbFrameBufferKind::Khr => { attributes.push(egl::GL_COLORSPACE); attributes.push(egl::GL_COLORSPACE_SRGB); } - SrgbFrameBufferKind::Khr => { - attributes.push(EGL_GL_COLORSPACE_KHR as i32); - attributes.push(EGL_GL_COLORSPACE_SRGB_KHR as i32); - } } + let alpha = if config.transparent { + attributes.push(egl::TRANSPARENT_TYPE); + attributes.push(egl::TRANSPARENT_RGB); + crate::AlphaMode::PostMultiplied //TODO: verify + } else { + crate::AlphaMode::Ignored + }; attributes.push(egl::ATTRIB_NONE as i32); let format = match config.color_space { @@ -489,7 +494,7 @@ impl Context { }; inner.egl.unmake_current(); - format + crate::SurfaceInfo { format, alpha } } pub fn acquire_frame(&self) -> super::Frame { diff --git a/blade-graphics/src/gles/web.rs b/blade-graphics/src/gles/web.rs index a60c3807..978cbf0d 100644 --- a/blade-graphics/src/gles/web.rs +++ b/blade-graphics/src/gles/web.rs @@ -48,6 +48,7 @@ impl Context { &wasm_bindgen::JsValue::FALSE, ) .expect("Cannot create context options"); + //Note: could also set: "alpha", "premultipliedAlpha" canvas .get_context_with_context_options("webgl2", &context_options) @@ -81,7 +82,8 @@ impl Context { }) } - pub fn resize(&self, config: crate::SurfaceConfig) -> crate::TextureFormat { + pub fn resize(&self, config: crate::SurfaceConfig) -> crate::SurfaceInfo { + //TODO: create WebGL context here let sc = &self.swapchain; let format_desc = super::describe_texture_format(sc.format); let gl = &self.glow; @@ -104,7 +106,11 @@ impl Context { gl.bind_renderbuffer(glow::RENDERBUFFER, None); } sc.extent.set(config.size); - sc.format + + crate::SurfaceInfo { + format: sc.format, + alpha: crate::AlphaMode::PreMultiplied, + } } pub fn acquire_frame(&self) -> super::Frame { diff --git a/blade-graphics/src/lib.rs b/blade-graphics/src/lib.rs index 617eeb8d..d4e05f1f 100644 --- a/blade-graphics/src/lib.rs +++ b/blade-graphics/src/lib.rs @@ -1009,7 +1009,7 @@ pub enum ColorSpace { Srgb, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct SurfaceConfig { pub size: Extent, pub usage: TextureUsage, @@ -1021,6 +1021,22 @@ pub struct SurfaceConfig { /// 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, + pub transparent: bool, + pub allow_exclusive_full_screen: bool, +} + +#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] +pub enum AlphaMode { + #[default] + Ignored, + PreMultiplied, + PostMultiplied, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct SurfaceInfo { + pub format: TextureFormat, + pub alpha: AlphaMode, } #[derive(Clone, Copy, Debug, PartialEq)] diff --git a/blade-graphics/src/metal/surface.rs b/blade-graphics/src/metal/surface.rs index d97aa9c9..34583c7a 100644 --- a/blade-graphics/src/metal/surface.rs +++ b/blade-graphics/src/metal/surface.rs @@ -70,7 +70,7 @@ impl super::Surface { &mut self, device: &metal::DeviceRef, config: crate::SurfaceConfig, - ) -> crate::TextureFormat { + ) -> crate::SurfaceInfo { let format = match config.color_space { crate::ColorSpace::Linear => crate::TextureFormat::Bgra8UnormSrgb, crate::ColorSpace::Srgb => crate::TextureFormat::Bgra8Unorm, @@ -80,7 +80,7 @@ impl super::Surface { crate::DisplaySync::Recent | crate::DisplaySync::Tear => false, }; - self.render_layer.set_opaque(true); + self.render_layer.set_opaque(!config.transparent); self.render_layer.set_device(device); self.render_layer .set_pixel_format(super::map_texture_format(format)); @@ -95,12 +95,15 @@ impl super::Surface { let () = msg_send![self.render_layer, setDisplaySyncEnabled: vsync]; } - format + crate::SurfaceInfo { + format, + alpha: crate::AlphaMode::PostMultiplied, + } } } impl super::Context { - pub fn resize(&self, config: crate::SurfaceConfig) -> crate::TextureFormat { + pub fn resize(&self, config: crate::SurfaceConfig) -> crate::SurfaceInfo { let mut surface = self.surface.as_ref().unwrap().lock().unwrap(); surface.reconfigure(&*self.device.lock().unwrap(), config) } diff --git a/blade-graphics/src/vulkan/init.rs b/blade-graphics/src/vulkan/init.rs index 949814eb..e6e75a65 100644 --- a/blade-graphics/src/vulkan/init.rs +++ b/blade-graphics/src/vulkan/init.rs @@ -31,6 +31,7 @@ struct AdapterCapabilities { ray_tracing: bool, buffer_marker: bool, shader_info: bool, + full_screen_exclusive: bool, } #[derive(Debug)] @@ -215,6 +216,7 @@ unsafe fn inspect_adapter( let buffer_marker = supported_extensions.contains(&vk::AMD_BUFFER_MARKER_NAME); let shader_info = supported_extensions.contains(&vk::AMD_SHADER_INFO_NAME); + let full_screen_exclusive = supported_extensions.contains(&vk::EXT_FULL_SCREEN_EXCLUSIVE_NAME); Some(AdapterCapabilities { api_version, @@ -224,6 +226,7 @@ unsafe fn inspect_adapter( ray_tracing, buffer_marker, shader_info, + full_screen_exclusive, }) } @@ -406,6 +409,9 @@ impl super::Context { if capabilities.shader_info { device_extensions.push(vk::AMD_SHADER_INFO_NAME); } + if capabilities.full_screen_exclusive { + device_extensions.push(vk::EXT_FULL_SCREEN_EXCLUSIVE_NAME); + } let str_pointers = device_extensions .iter() @@ -494,6 +500,14 @@ impl super::Context { } else { None }, + full_screen_exclusive: if capabilities.full_screen_exclusive { + Some(ext::full_screen_exclusive::Device::new( + &instance.core, + &device_core, + )) + } else { + None + }, core: device_core, //TODO: detect GPU family workarounds: super::Workarounds { @@ -661,7 +675,7 @@ impl super::Context { } impl super::Context { - pub fn resize(&self, config: crate::SurfaceConfig) -> crate::TextureFormat { + pub fn resize(&self, config: crate::SurfaceConfig) -> crate::SurfaceInfo { let surface_khr = self.instance.surface.as_ref().unwrap(); let mut surface = self.surface.as_ref().unwrap().lock().unwrap(); @@ -682,6 +696,40 @@ impl super::Context { ); } + let (alpha, composite_alpha) = if config.transparent { + if capabilities + .supported_composite_alpha + .contains(vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED) + { + ( + crate::AlphaMode::PostMultiplied, + vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED, + ) + } else if capabilities + .supported_composite_alpha + .contains(vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED) + { + ( + crate::AlphaMode::PreMultiplied, + vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED, + ) + } else { + log::error!( + "No composite alpha flag for transparency: {:?}", + capabilities.supported_composite_alpha + ); + ( + crate::AlphaMode::Ignored, + vk::CompositeAlphaFlagsKHR::OPAQUE, + ) + } + } else { + ( + crate::AlphaMode::Ignored, + vk::CompositeAlphaFlagsKHR::OPAQUE, + ) + }; + let (requested_frame_count, mode_preferences) = match config.display_sync { crate::DisplaySync::Block => (3, [vk::PresentModeKHR::FIFO].as_slice()), crate::DisplaySync::Recent => ( @@ -709,32 +757,84 @@ impl super::Context { log::info!("Using surface present mode {:?}", present_mode); let queue_families = [self.queue_family_index]; - //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 supported_formats = unsafe { + surface_khr + .get_physical_device_surface_formats(self.physical_device, surface.raw) + .unwrap() }; - let vk_format = super::map_texture_format(format); - let create_info = vk::SwapchainCreateInfoKHR { + let (format, surface_format) = match config.color_space { + crate::ColorSpace::Linear => { + let surface_format = vk::SurfaceFormatKHR { + format: vk::Format::B8G8R8A8_UNORM, + color_space: vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT, + }; + if supported_formats.contains(&surface_format) { + log::info!("Using linear SRGB color space"); + (crate::TextureFormat::Bgra8Unorm, surface_format) + } else { + ( + crate::TextureFormat::Bgra8UnormSrgb, + vk::SurfaceFormatKHR { + format: vk::Format::B8G8R8A8_SRGB, + color_space: vk::ColorSpaceKHR::default(), + }, + ) + } + } + crate::ColorSpace::Srgb => ( + crate::TextureFormat::Bgra8Unorm, + vk::SurfaceFormatKHR { + format: vk::Format::B8G8R8A8_UNORM, + color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR, + }, + ), + }; + if !supported_formats.is_empty() && !supported_formats.contains(&surface_format) { + log::error!("Surface formats are incompatible: {:?}", supported_formats); + } + + let vk_usage = super::resource::map_texture_usage(config.usage, crate::TexelAspects::COLOR); + if !capabilities.supported_usage_flags.contains(vk_usage) { + log::error!( + "Surface usages are incompatible: {:?}", + capabilities.supported_usage_flags + ); + } + + let mut full_screen_exclusive_info = vk::SurfaceFullScreenExclusiveInfoEXT { + full_screen_exclusive: if config.allow_exclusive_full_screen { + vk::FullScreenExclusiveEXT::ALLOWED + } else { + vk::FullScreenExclusiveEXT::DISALLOWED + }, + ..Default::default() + }; + + let mut create_info = vk::SwapchainCreateInfoKHR { surface: surface.raw, min_image_count: effective_frame_count, - image_format: vk_format, + image_format: surface_format.format, + image_color_space: surface_format.color_space, image_extent: vk::Extent2D { width: config.size.width, height: config.size.height, }, image_array_layers: 1, - image_usage: super::resource::map_texture_usage( - config.usage, - crate::TexelAspects::COLOR, - ), + image_usage: vk_usage, pre_transform: vk::SurfaceTransformFlagsKHR::IDENTITY, - composite_alpha: vk::CompositeAlphaFlagsKHR::OPAQUE, + composite_alpha, present_mode, old_swapchain: surface.swapchain, ..Default::default() } .queue_family_indices(&queue_families); + + if self.device.full_screen_exclusive.is_some() { + create_info = create_info.push_next(&mut full_screen_exclusive_info); + } else if !config.allow_exclusive_full_screen { + log::warn!("Unable to forbid exclusive full screen"); + } let new_swapchain = unsafe { surface .extension @@ -773,7 +873,7 @@ impl super::Context { let view_create_info = vk::ImageViewCreateInfo { image, view_type: vk::ImageViewType::TYPE_2D, - format: vk_format, + format: surface_format.format, subresource_range, ..Default::default() }; @@ -800,7 +900,8 @@ impl super::Context { }); } surface.swapchain = new_swapchain; - format + + crate::SurfaceInfo { format, alpha } } pub fn acquire_frame(&self) -> super::Frame { diff --git a/blade-graphics/src/vulkan/mod.rs b/blade-graphics/src/vulkan/mod.rs index 4f814285..bbbd3af4 100644 --- a/blade-graphics/src/vulkan/mod.rs +++ b/blade-graphics/src/vulkan/mod.rs @@ -33,6 +33,7 @@ struct Device { ray_tracing: Option, buffer_marker: Option, shader_info: Option, + full_screen_exclusive: Option, workarounds: Workarounds, } diff --git a/blade-render/code/blur.wgsl b/blade-render/code/blur.wgsl index 6c977e2d..6f01c59e 100644 --- a/blade-render/code/blur.wgsl +++ b/blade-render/code/blur.wgsl @@ -104,7 +104,7 @@ fn temporal_accum(@builtin(global_invocation_id) global_id: vec3) { let cur_luminocity = dot(cur_illumination, LUMA); var mixed_ilm = vec4(cur_illumination, cur_luminocity * cur_luminocity); if (sum_weight > MIN_WEIGHT) { - let prev_ilm = sum_ilm / w4(sum_weight); + let prev_ilm = sum_ilm / vec4(vec3(sum_weight), max(0.001, sum_weight*sum_weight)); mixed_ilm = mix(mixed_ilm, prev_ilm, sum_weight * (1.0 - params.temporal_weight)); } textureStore(output, global_id.xy, mixed_ilm); diff --git a/blade-render/src/render/debug.rs b/blade-render/src/render/debug.rs index 1bee72f0..510970df 100644 --- a/blade-render/src/render/debug.rs +++ b/blade-render/src/render/debug.rs @@ -142,13 +142,13 @@ impl DebugRender { shader_draw: &blade_graphics::Shader, shader_blit: &blade_graphics::Shader, capacity: u32, - surface_format: blade_graphics::TextureFormat, + surface_info: blade_graphics::SurfaceInfo, ) -> Self { let line_size = shader_draw.get_struct_size("DebugLine"); let buffer_size = shader_draw.get_struct_size("DebugBuffer"); let this = Self { capacity, - surface_format, + surface_format: surface_info.format, buffer: gpu.create_buffer(blade_graphics::BufferDesc { name: "debug", size: (buffer_size + capacity.saturating_sub(1) * line_size) as u64, @@ -170,8 +170,8 @@ impl DebugRender { memory: blade_graphics::Memory::Shared, }), cpu_lines_offset: Cell::new(0), - draw_pipeline: create_draw_pipeline(shader_draw, surface_format, gpu), - blit_pipeline: create_blit_pipeline(shader_blit, surface_format, gpu), + draw_pipeline: create_draw_pipeline(shader_draw, surface_info.format, gpu), + blit_pipeline: create_blit_pipeline(shader_blit, surface_info.format, gpu), line_size, buffer_size, }; diff --git a/blade-render/src/render/mod.rs b/blade-render/src/render/mod.rs index e5a9398d..18f3e273 100644 --- a/blade-render/src/render/mod.rs +++ b/blade-render/src/render/mod.rs @@ -33,8 +33,8 @@ fn mat3_transform(t_orig: &blade_graphics::Transform) -> glam::Mat3 { #[derive(Clone, Copy, Debug)] pub struct RenderConfig { - pub screen_size: blade_graphics::Extent, - pub surface_format: blade_graphics::TextureFormat, + pub surface_size: blade_graphics::Extent, + pub surface_info: blade_graphics::SurfaceInfo, pub max_debug_lines: u32, } @@ -318,8 +318,8 @@ pub struct Renderer { samplers: Samplers, reservoir_size: u32, debug: DebugRender, - screen_size: blade_graphics::Extent, - screen_format: blade_graphics::TextureFormat, + surface_size: blade_graphics::Extent, + surface_info: blade_graphics::SurfaceInfo, frame_index: usize, frame_scene_built: usize, //TODO: refactor `ResourceArray` to not carry the freelist logic @@ -570,7 +570,7 @@ impl ShaderPipelines { fn create_post_proc( shader: &blade_graphics::Shader, - format: blade_graphics::TextureFormat, + info: blade_graphics::SurfaceInfo, gpu: &blade_graphics::Context, ) -> blade_graphics::RenderPipeline { let layout = ::layout(); @@ -584,7 +584,7 @@ impl ShaderPipelines { vertex: shader.at("blit_vs"), vertex_fetches: &[], fragment: shader.at("blit_fs"), - color_targets: &[format.into()], + color_targets: &[info.format.into()], depth_stencil: None, }) } @@ -604,7 +604,7 @@ impl ShaderPipelines { atrous: Self::create_atrous(sh_blur, gpu), post_proc: Self::create_post_proc( shader_man[shaders.post_proc].raw.as_ref().unwrap(), - config.surface_format, + config.surface_info, gpu, ), env_prepare: EnvironmentMap::init_pipeline( @@ -651,11 +651,11 @@ impl Renderer { sh_draw, sh_blit, config.max_debug_lines, - config.surface_format, + config.surface_info, ) }; - let targets = RestirTargets::new(config.screen_size, sp.reservoir_size, encoder, gpu); + let targets = RestirTargets::new(config.surface_size, sp.reservoir_size, encoder, gpu); let dummy = DummyResources::new(encoder, gpu); let samplers = Samplers { @@ -698,8 +698,8 @@ impl Renderer { samplers, reservoir_size: sp.reservoir_size, debug, - screen_size: config.screen_size, - screen_format: config.surface_format, + surface_size: config.surface_size, + surface_info: config.surface_info, frame_index: 0, frame_scene_built: 0, texture_resource_lookup: HashMap::default(), @@ -774,7 +774,7 @@ impl Renderer { if self.shaders.post_proc != old.post_proc { if let Ok(ref shader) = asset_hub.shaders[self.shaders.post_proc].raw { self.post_proc_pipeline = - ShaderPipelines::create_post_proc(shader, self.screen_format, gpu); + ShaderPipelines::create_post_proc(shader, self.surface_info, gpu); } } if self.shaders.debug_draw != old.debug_draw { @@ -791,8 +791,8 @@ impl Renderer { true } - pub fn get_screen_size(&self) -> blade_graphics::Extent { - self.screen_size + pub fn get_surface_size(&self) -> blade_graphics::Extent { + self.surface_size } pub fn view_dummy_white(&self) -> blade_graphics::TextureView { @@ -812,7 +812,7 @@ impl Renderer { encoder: &mut blade_graphics::CommandEncoder, gpu: &blade_graphics::Context, ) { - self.screen_size = size; + self.surface_size = size; self.targets.destroy(gpu); self.targets = RestirTargets::new(size, self.reservoir_size, encoder, gpu); } @@ -1007,7 +1007,7 @@ impl Renderer { texture_flags: config.texture_flags.bits(), unused: 0, mouse_pos: match config.mouse_pos { - Some(p) => [p[0], self.screen_size.height as i32 - p[1]], + Some(p) => [p[0], self.surface_size.height as i32 - p[1]], None => [-1; 2], }, } @@ -1015,15 +1015,15 @@ impl Renderer { fn make_camera_params(&self, camera: &super::Camera) -> CameraParams { let fov_x = 2.0 - * ((camera.fov_y * 0.5).tan() * self.screen_size.width as f32 - / self.screen_size.height as f32) + * ((camera.fov_y * 0.5).tan() * self.surface_size.width as f32 + / self.surface_size.height as f32) .atan(); CameraParams { position: camera.pos.into(), depth: camera.depth, orientation: camera.rot.into(), fov: [fov_x, camera.fov_y], - target_size: [self.screen_size.width, self.screen_size.height], + target_size: [self.surface_size.width, self.surface_size.height], } } @@ -1057,7 +1057,7 @@ impl Renderer { if !enable_debug_draw { self.debug.reset_lines(&mut transfer); } - let total_reservoirs = self.screen_size.width as u64 * self.screen_size.height as u64; + let total_reservoirs = self.surface_size.width as u64 * self.surface_size.height as u64; let prev_reservoir_buf = self.targets.reservoir_buf[self.frame_index % 2]; transfer.fill_buffer( prev_reservoir_buf.into(), @@ -1087,7 +1087,7 @@ impl Renderer { if let mut pass = command_encoder.compute() { let mut pc = pass.with(&self.fill_pipeline); - let groups = self.fill_pipeline.get_dispatch_for(self.screen_size); + let groups = self.fill_pipeline.get_dispatch_for(self.surface_size); pc.bind( 0, &FillData { @@ -1114,7 +1114,7 @@ impl Renderer { if let mut pass = command_encoder.compute() { let mut pc = pass.with(&self.main_pipeline); - let groups = self.main_pipeline.get_dispatch_for(self.screen_size); + let groups = self.main_pipeline.get_dispatch_for(self.surface_size); pc.bind( 0, &MainData { @@ -1163,7 +1163,7 @@ impl Renderer { denoiser_config: DenoiserConfig, ) { let mut params = BlurParams { - extent: [self.screen_size.width, self.screen_size.height], + extent: [self.surface_size.width, self.surface_size.height], temporal_weight: denoiser_config.temporal_weight, iteration: 0, use_motion_vectors: (self.frame_scene_built == self.frame_index) as u32, @@ -1176,7 +1176,10 @@ impl Renderer { if denoiser_config.temporal_weight < 1.0 { let mut pass = command_encoder.compute(); let mut pc = pass.with(&self.blur.temporal_accum_pipeline); - let groups = self.blur.atrous_pipeline.get_dispatch_for(self.screen_size); + let groups = self + .blur + .atrous_pipeline + .get_dispatch_for(self.surface_size); pc.bind( 0, &TemporalAccumData { @@ -1202,7 +1205,10 @@ impl Renderer { for _ in 0..denoiser_config.num_passes { let mut pass = command_encoder.compute(); let mut pc = pass.with(&self.blur.atrous_pipeline); - let groups = self.blur.atrous_pipeline.get_dispatch_for(self.screen_size); + let groups = self + .blur + .atrous_pipeline + .get_dispatch_for(self.surface_size); pc.bind( 0, &AtrousData { @@ -1258,7 +1264,7 @@ impl Renderer { pass, ); self.debug - .render_blits(debug_blits, self.samplers.linear, self.screen_size, pass); + .render_blits(debug_blits, self.samplers.linear, self.surface_size, pass); } #[profiling::function] diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 48d1b44a..39ca6cbf 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -3,7 +3,10 @@ Changelog for Blade ## blade-graphics-0.5, blade-macros-0.3, blade-egui-0.4 (TBD) - vertex buffers support -- configuration for disabling exclusive fullscreen +- surface configuration: + - transparency support + - option to disable exclusive fullscreen + - VK: using linear sRGB color space if available - window API switched to raw-window-handle-0.6 - GLES: support for storage buffer and compute - GLES: scissor rects, able to run "particle" example diff --git a/examples/bunnymark/main.rs b/examples/bunnymark/main.rs index d49cbc3c..2d2898c3 100644 --- a/examples/bunnymark/main.rs +++ b/examples/bunnymark/main.rs @@ -74,7 +74,7 @@ impl Example { .unwrap() }; - let surface_format = context.resize(gpu::SurfaceConfig { + let surface_info = context.resize(gpu::SurfaceConfig { size: gpu::Extent { width: window_size.width, height: window_size.height, @@ -82,7 +82,7 @@ impl Example { }, usage: gpu::TextureUsage::TARGET, display_sync: gpu::DisplaySync::Recent, - color_space: gpu::ColorSpace::Linear, + ..Default::default() }); let global_layout = ::layout(); @@ -110,7 +110,7 @@ impl Example { depth_stencil: None, fragment: shader.at("fs_main"), color_targets: &[gpu::ColorTargetState { - format: surface_format, + format: surface_info.format, blend: Some(gpu::BlendState::ALPHA_BLENDING), write_mask: gpu::ColorWrites::default(), }], diff --git a/examples/particle/main.rs b/examples/particle/main.rs index aae331ee..b808d7d2 100644 --- a/examples/particle/main.rs +++ b/examples/particle/main.rs @@ -27,7 +27,7 @@ impl Example { .unwrap() }; - let surface_format = context.resize(gpu::SurfaceConfig { + let surface_info = context.resize(gpu::SurfaceConfig { size: gpu::Extent { width: window_size.width, height: window_size.height, @@ -35,15 +35,15 @@ impl Example { }, usage: gpu::TextureUsage::TARGET, display_sync: gpu::DisplaySync::Block, - color_space: gpu::ColorSpace::Linear, + ..Default::default() }); - let gui_painter = blade_egui::GuiPainter::new(surface_format, &context); + let gui_painter = blade_egui::GuiPainter::new(surface_info, &context); let particle_system = particle::System::new( &context, particle::SystemDesc { name: "particle system", capacity: 100_000, - draw_format: surface_format, + draw_format: surface_info.format, }, ); diff --git a/examples/ray-query/main.rs b/examples/ray-query/main.rs index 7188c19d..4b74e595 100644 --- a/examples/ray-query/main.rs +++ b/examples/ray-query/main.rs @@ -85,11 +85,11 @@ impl Example { subresources: &gpu::TextureSubresources::default(), }); - let surface_format = context.resize(gpu::SurfaceConfig { + let surface_info = context.resize(gpu::SurfaceConfig { size: screen_size, usage: gpu::TextureUsage::TARGET, - display_sync: gpu::DisplaySync::Block, - color_space: gpu::ColorSpace::Linear, + transparent: true, + ..Default::default() }); let source = std::fs::read_to_string("examples/ray-query/shader.wgsl").unwrap(); @@ -111,7 +111,7 @@ impl Example { vertex: shader.at("draw_vs"), vertex_fetches: &[], fragment: shader.at("draw_fs"), - color_targets: &[surface_format.into()], + color_targets: &[surface_info.format.into()], depth_stencil: None, }); @@ -327,6 +327,7 @@ fn main() { let event_loop = winit::event_loop::EventLoop::new().unwrap(); let window = winit::window::WindowBuilder::new() .with_title("blade-ray-query") + .with_transparent(true) .build(&event_loop) .unwrap(); diff --git a/examples/scene/main.rs b/examples/scene/main.rs index 1b99c276..870ccac4 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -162,7 +162,7 @@ impl Example { }, usage: gpu::TextureUsage::TARGET, display_sync: gpu::DisplaySync::Block, - color_space: gpu::ColorSpace::Linear, + ..Default::default() } } @@ -183,8 +183,8 @@ impl Example { }); let surface_config = Self::make_surface_config(window.inner_size()); - let screen_size = surface_config.size; - let surface_format = context.resize(surface_config); + let surface_size = surface_config.size; + let surface_info = context.resize(surface_config); let num_workers = num_cpus::get_physical().max((num_cpus::get() * 3 + 2) / 4); log::info!("Initializing Choir with {} workers", num_workers); @@ -202,8 +202,8 @@ impl Example { let mut pacer = blade_render::util::FramePacer::new(&context); let (command_encoder, _) = pacer.begin_frame(); let render_config = blade_render::RenderConfig { - screen_size, - surface_format, + surface_size, + surface_info, max_debug_lines: 1000, }; let renderer = blade_render::Renderer::new( @@ -214,7 +214,7 @@ impl Example { &render_config, ); pacer.end_frame(&context); - let gui_painter = blade_egui::GuiPainter::new(surface_format, &context); + let gui_painter = blade_egui::GuiPainter::new(surface_info, &context); Self { scene_path: PathBuf::new(), @@ -413,14 +413,14 @@ impl Example { // wants to borrow `self` mutably, and `command_encoder` blocks that. let surface_config = Self::make_surface_config(physical_size); let new_render_size = surface_config.size; - if new_render_size != self.renderer.get_screen_size() { + if new_render_size != self.renderer.get_surface_size() { log::info!("Resizing to {}", new_render_size); self.pacer.wait_for_previous_frame(&self.context); self.context.resize(surface_config); } let (command_encoder, temp) = self.pacer.begin_frame(); - if new_render_size != self.renderer.get_screen_size() { + if new_render_size != self.renderer.get_surface_size() { self.renderer .resize_screen(new_render_size, command_encoder, &self.context); self.need_accumulation_reset = true; @@ -525,7 +525,7 @@ impl Example { let view_matrix = glam::Mat4::from_rotation_translation(self.camera.rot.into(), self.camera.pos.into()) .inverse(); - let extent = self.renderer.get_screen_size(); + let extent = self.renderer.get_surface_size(); let aspect = extent.width as f32 / extent.height as f32; let projection_matrix = glam::Mat4::perspective_rh(self.camera.fov_y, aspect, 1.0, self.camera.depth); diff --git a/src/lib.rs b/src/lib.rs index e9cbe6dc..b9541d99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -384,6 +384,8 @@ impl Engine { //TODO: make it `Recent` display_sync: gpu::DisplaySync::Block, color_space: gpu::ColorSpace::Linear, + transparent: false, + allow_exclusive_full_screen: true, } } @@ -405,8 +407,8 @@ impl Engine { }); let surface_config = Self::make_surface_config(window.inner_size()); - let screen_size = surface_config.size; - let surface_format = gpu_context.resize(surface_config); + let surface_size = surface_config.size; + let surface_info = gpu_context.resize(surface_config); let num_workers = num_cpus::get_physical().max((num_cpus::get() * 3 + 2) / 4); log::info!("Initializing Choir with {} workers", num_workers); @@ -425,8 +427,8 @@ impl Engine { let (command_encoder, _) = pacer.begin_frame(); let render_config = blade_render::RenderConfig { - screen_size, - surface_format, + surface_size, + surface_info, max_debug_lines: 1 << 14, }; let renderer = blade_render::Renderer::new( @@ -439,7 +441,7 @@ impl Engine { pacer.end_frame(&gpu_context); - let gui_painter = blade_egui::GuiPainter::new(surface_format, &gpu_context); + let gui_painter = blade_egui::GuiPainter::new(surface_info, &gpu_context); let mut physics = Physics::default(); physics.debug_pipeline.mode = rapier3d::pipeline::DebugRenderMode::empty(); physics.integration_params.dt = config.time_step; @@ -525,14 +527,14 @@ impl Engine { // wants to borrow `self` mutably, and `command_encoder` blocks that. let surface_config = Self::make_surface_config(physical_size); let new_render_size = surface_config.size; - if new_render_size != self.renderer.get_screen_size() { + if new_render_size != self.renderer.get_surface_size() { log::info!("Resizing to {}", new_render_size); self.pacer.wait_for_previous_frame(&self.gpu_context); self.gpu_context.resize(surface_config); } let (command_encoder, temp) = self.pacer.begin_frame(); - if new_render_size != self.renderer.get_screen_size() { + if new_render_size != self.renderer.get_surface_size() { self.renderer .resize_screen(new_render_size, command_encoder, &self.gpu_context); self.need_accumulation_reset = true; @@ -829,7 +831,7 @@ impl Engine { } pub fn screen_aspect(&self) -> f32 { - let size = self.renderer.get_screen_size(); + let size = self.renderer.get_surface_size(); size.width as f32 / size.height.max(1) as f32 }