Skip to content

Commit

Permalink
Support transparency and forbidden full screen
Browse files Browse the repository at this point in the history
Extends SurfaceConfig with a few extra fields, adds Default derive,
and switches the resize() result type to the new SurfaceInfo struct.
  • Loading branch information
kvark committed Apr 22, 2024
1 parent a81f529 commit f958d41
Show file tree
Hide file tree
Showing 16 changed files with 237 additions and 96 deletions.
7 changes: 2 additions & 5 deletions blade-egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
Expand All @@ -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(),
}],
Expand Down
23 changes: 14 additions & 9 deletions blade-graphics/src/gles/egl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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![
Expand All @@ -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 {
Expand Down Expand Up @@ -489,7 +494,7 @@ impl Context {
};
inner.egl.unmake_current();

format
crate::SurfaceInfo { format, alpha }
}

pub fn acquire_frame(&self) -> super::Frame {
Expand Down
10 changes: 8 additions & 2 deletions blade-graphics/src/gles/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
18 changes: 17 additions & 1 deletion blade-graphics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ pub enum ColorSpace {
Srgb,
}

#[derive(Debug)]
#[derive(Debug, Default)]
pub struct SurfaceConfig {
pub size: Extent,
pub usage: TextureUsage,
Expand All @@ -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)]
Expand Down
11 changes: 7 additions & 4 deletions blade-graphics/src/metal/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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));
Expand All @@ -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)
}
Expand Down
131 changes: 116 additions & 15 deletions blade-graphics/src/vulkan/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct AdapterCapabilities {
ray_tracing: bool,
buffer_marker: bool,
shader_info: bool,
full_screen_exclusive: bool,
}

#[derive(Debug)]
Expand Down Expand Up @@ -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,
Expand All @@ -224,6 +226,7 @@ unsafe fn inspect_adapter(
ray_tracing,
buffer_marker,
shader_info,
full_screen_exclusive,
})
}

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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();

Expand All @@ -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 => (
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
};
Expand All @@ -800,7 +900,8 @@ impl super::Context {
});
}
surface.swapchain = new_swapchain;
format

crate::SurfaceInfo { format, alpha }
}

pub fn acquire_frame(&self) -> super::Frame {
Expand Down
Loading

0 comments on commit f958d41

Please sign in to comment.