use {
super::{DriverError, Instance, device::Device},
ash::vk,
ash_window::create_surface,
log::warn,
raw_window_handle::{HasDisplayHandle, HasWindowHandle},
std::{
fmt::{Debug, Formatter},
ops::Deref,
sync::Arc,
thread::panicking,
},
};
pub struct Surface {
device: Arc<Device>,
surface: vk::SurfaceKHR,
}
impl Surface {
pub fn capabilities(this: &Self) -> Result<vk::SurfaceCapabilitiesKHR, DriverError> {
let surface_ext = Device::expect_surface_ext(&this.device);
unsafe {
surface_ext.get_physical_device_surface_capabilities(
*this.device.physical_device,
this.surface,
)
}
.inspect_err(|err| warn!("unable to get surface capabilities: {err}"))
.or(Err(DriverError::Unsupported))
}
#[profiling::function]
pub fn create(
device: &Arc<Device>,
window: &(impl HasDisplayHandle + HasWindowHandle),
) -> Result<Self, DriverError> {
let device = Arc::clone(device);
let instance = Device::instance(&device);
let display_handle = window.display_handle().map_err(|err| {
warn!("{err}");
DriverError::Unsupported
})?;
let window_handle = window.window_handle().map_err(|err| {
warn!("{err}");
DriverError::Unsupported
})?;
let surface = unsafe {
create_surface(
Instance::entry(instance),
instance,
display_handle.as_raw(),
window_handle.as_raw(),
None,
)
}
.map_err(|err| {
warn!("Unable to create surface: {err}");
DriverError::Unsupported
})?;
Ok(Self { device, surface })
}
#[profiling::function]
pub fn formats(this: &Self) -> Result<Vec<vk::SurfaceFormatKHR>, DriverError> {
unsafe {
this.device
.surface_ext
.as_ref()
.unwrap()
.get_physical_device_surface_formats(*this.device.physical_device, this.surface)
.map_err(|err| {
warn!("Unable to get surface formats: {err}");
DriverError::Unsupported
})
}
}
#[profiling::function]
pub fn linear(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
formats
.iter()
.find(|&&vk::SurfaceFormatKHR { format, .. }| {
matches!(
format,
vk::Format::R8G8B8A8_UNORM | vk::Format::B8G8R8A8_UNORM
)
})
.copied()
}
pub fn linear_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
Self::linear(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
}
pub fn present_modes(this: &Self) -> Result<Vec<vk::PresentModeKHR>, DriverError> {
let surface_ext = Device::expect_surface_ext(&this.device);
unsafe {
surface_ext.get_physical_device_surface_present_modes(
*this.device.physical_device,
this.surface,
)
}
.inspect_err(|err| warn!("unable to get surface present modes: {err}"))
.or(Err(DriverError::Unsupported))
}
#[profiling::function]
pub fn srgb(formats: &[vk::SurfaceFormatKHR]) -> Option<vk::SurfaceFormatKHR> {
formats
.iter()
.find(
|&&vk::SurfaceFormatKHR {
color_space,
format,
}| {
matches!(color_space, vk::ColorSpaceKHR::SRGB_NONLINEAR)
&& matches!(
format,
vk::Format::R8G8B8A8_SRGB | vk::Format::B8G8R8A8_SRGB
)
},
)
.copied()
}
pub fn srgb_or_default(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
Self::srgb(formats).unwrap_or_else(|| formats.first().copied().unwrap_or_default())
}
}
impl Debug for Surface {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Surface")
}
}
impl Deref for Surface {
type Target = vk::SurfaceKHR;
fn deref(&self) -> &Self::Target {
&self.surface
}
}
impl Drop for Surface {
#[profiling::function]
fn drop(&mut self) {
if panicking() {
return;
}
let surface_ext = Device::expect_surface_ext(&self.device);
unsafe {
surface_ext.destroy_surface(self.surface, None);
}
}
}