Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support transparency and forbidden full screen #113

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading