use crate::device;
use crate::format::Format;
use crate::image;
use crate::queue::CommandQueue;
use crate::Backend;
use std::any::Any;
use std::borrow::Borrow;
use std::cmp::{max, min};
use std::fmt;
use std::iter;
use std::ops::RangeInclusive;
pub const DEFAULT_USAGE: image::Usage = image::Usage::COLOR_ATTACHMENT;
pub const DEFAULT_IMAGE_COUNT: SwapImageIndex = 3;
#[derive(Clone, Debug, PartialEq)]
pub enum CreationError {
OutOfMemory(device::OutOfMemory),
DeviceLost(device::DeviceLost),
SurfaceLost(device::SurfaceLost),
WindowInUse(device::WindowInUse),
}
impl From<device::OutOfMemory> for CreationError {
fn from(error: device::OutOfMemory) -> Self {
CreationError::OutOfMemory(error)
}
}
impl From<device::DeviceLost> for CreationError {
fn from(error: device::DeviceLost) -> Self {
CreationError::DeviceLost(error)
}
}
impl From<device::SurfaceLost> for CreationError {
fn from(error: device::SurfaceLost) -> Self {
CreationError::SurfaceLost(error)
}
}
impl From<device::WindowInUse> for CreationError {
fn from(error: device::WindowInUse) -> Self {
CreationError::WindowInUse(error)
}
}
impl std::fmt::Display for CreationError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CreationError::OutOfMemory(err) => {
write!(fmt, "Failed to create or configure swapchain: {}", err)
}
CreationError::DeviceLost(err) => {
write!(fmt, "Failed to create or configure swapchain: {}", err)
}
CreationError::SurfaceLost(err) => {
write!(fmt, "Failed to create or configure swapchain: {}", err)
}
CreationError::WindowInUse(err) => {
write!(fmt, "Failed to create or configure swapchain: {}", err)
}
}
}
}
impl std::error::Error for CreationError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
CreationError::OutOfMemory(err) => Some(err),
CreationError::DeviceLost(err) => Some(err),
CreationError::SurfaceLost(err) => Some(err),
CreationError::WindowInUse(err) => Some(err),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Extent2D {
pub width: image::Size,
pub height: image::Size,
}
impl From<image::Extent> for Extent2D {
fn from(ex: image::Extent) -> Self {
Extent2D {
width: ex.width,
height: ex.height,
}
}
}
impl Extent2D {
pub fn to_extent(&self) -> image::Extent {
image::Extent {
width: self.width,
height: self.height,
depth: 1,
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SurfaceCapabilities {
pub image_count: RangeInclusive<SwapImageIndex>,
pub current_extent: Option<Extent2D>,
pub extents: RangeInclusive<Extent2D>,
pub max_image_layers: image::Layer,
pub usage: image::Usage,
pub present_modes: PresentMode,
pub composite_alpha_modes: CompositeAlphaMode,
}
impl SurfaceCapabilities {
fn clamped_extent(&self, default_extent: Extent2D) -> Extent2D {
match self.current_extent {
Some(current) => current,
None => {
let (min_width, max_width) = (self.extents.start().width, self.extents.end().width);
let (min_height, max_height) =
(self.extents.start().height, self.extents.end().height);
let width = min(max_width, max(default_extent.width, min_width));
let height = min(max_height, max(default_extent.height, min_height));
Extent2D { width, height }
}
}
}
}
pub trait Surface<B: Backend>: fmt::Debug + Any + Send + Sync {
fn supports_queue_family(&self, family: &B::QueueFamily) -> bool;
fn capabilities(&self, physical_device: &B::PhysicalDevice) -> SurfaceCapabilities;
fn supported_formats(&self, physical_device: &B::PhysicalDevice) -> Option<Vec<Format>>;
}
pub trait PresentationSurface<B: Backend>: Surface<B> {
type SwapchainImage: Borrow<B::ImageView> + fmt::Debug + Send + Sync;
unsafe fn configure_swapchain(
&mut self,
device: &B::Device,
config: SwapchainConfig,
) -> Result<(), CreationError>;
unsafe fn unconfigure_swapchain(&mut self, device: &B::Device);
unsafe fn acquire_image(
&mut self,
timeout_ns: u64,
) -> Result<(Self::SwapchainImage, Option<Suboptimal>), AcquireError>;
}
pub type SwapImageIndex = u32;
bitflags!(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PresentMode: u32 {
const IMMEDIATE = 0x1;
const MAILBOX = 0x2;
const FIFO = 0x4;
const RELAXED = 0x8;
}
);
bitflags!(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CompositeAlphaMode: u32 {
const OPAQUE = 0x1;
const PREMULTIPLIED = 0x2;
const POSTMULTIPLIED = 0x4;
const INHERIT = 0x8;
}
);
#[derive(Debug, Clone)]
pub struct SwapchainConfig {
pub present_mode: PresentMode,
pub composite_alpha_mode: CompositeAlphaMode,
pub format: Format,
pub extent: Extent2D,
pub image_count: SwapImageIndex,
pub image_layers: image::Layer,
pub image_usage: image::Usage,
}
impl SwapchainConfig {
pub fn new(width: u32, height: u32, format: Format, image_count: SwapImageIndex) -> Self {
SwapchainConfig {
present_mode: PresentMode::FIFO,
composite_alpha_mode: CompositeAlphaMode::OPAQUE,
format,
extent: Extent2D { width, height },
image_count,
image_layers: 1,
image_usage: DEFAULT_USAGE,
}
}
pub fn from_caps(caps: &SurfaceCapabilities, format: Format, default_extent: Extent2D) -> Self {
let composite_alpha_mode = if caps
.composite_alpha_modes
.contains(CompositeAlphaMode::INHERIT)
{
CompositeAlphaMode::INHERIT
} else if caps
.composite_alpha_modes
.contains(CompositeAlphaMode::OPAQUE)
{
CompositeAlphaMode::OPAQUE
} else {
panic!("neither INHERIT or OPAQUE CompositeAlphaMode(s) are supported")
};
let present_mode = if caps.present_modes.contains(PresentMode::MAILBOX) {
PresentMode::MAILBOX
} else if caps.present_modes.contains(PresentMode::FIFO) {
PresentMode::FIFO
} else {
panic!("FIFO PresentMode is not supported")
};
SwapchainConfig {
present_mode,
composite_alpha_mode,
format,
extent: caps.clamped_extent(default_extent),
image_count: DEFAULT_IMAGE_COUNT
.max(*caps.image_count.start())
.min(*caps.image_count.end()),
image_layers: 1,
image_usage: DEFAULT_USAGE,
}
}
pub fn with_present_mode(mut self, mode: PresentMode) -> Self {
self.present_mode = mode;
self
}
pub fn with_composite_alpha_mode(mut self, mode: CompositeAlphaMode) -> Self {
self.composite_alpha_mode = mode;
self
}
pub fn with_image_usage(mut self, usage: image::Usage) -> Self {
self.image_usage = usage;
self
}
pub fn with_image_count(mut self, count: SwapImageIndex) -> Self {
self.image_count = count;
self
}
}
#[derive(Debug)]
pub struct Suboptimal;
#[derive(Clone, Debug, PartialEq)]
pub enum AcquireError {
OutOfMemory(device::OutOfMemory),
NotReady,
Timeout,
OutOfDate,
SurfaceLost(device::SurfaceLost),
DeviceLost(device::DeviceLost),
}
impl std::fmt::Display for AcquireError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AcquireError::OutOfMemory(err) => write!(fmt, "Failed to acqure image: {}", err),
AcquireError::NotReady => write!(
fmt,
"Failed to acqure image: No image ready (timeout wasn't specified)"
),
AcquireError::Timeout => {
write!(fmt, "Failed to acqure image: No image ready (timeout)")
}
AcquireError::OutOfDate => write!(
fmt,
"Failed to acqure image: Swapchain is out of date and needs to be re-created"
),
AcquireError::SurfaceLost(err) => write!(fmt, "Failed to acqure image: {}", err),
AcquireError::DeviceLost(err) => write!(fmt, "Failed to acqure image: {}", err),
}
}
}
impl std::error::Error for AcquireError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
AcquireError::OutOfMemory(err) => Some(err),
AcquireError::SurfaceLost(err) => Some(err),
AcquireError::DeviceLost(err) => Some(err),
_ => None,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum PresentError {
OutOfMemory(device::OutOfMemory),
OutOfDate,
SurfaceLost(device::SurfaceLost),
DeviceLost(device::DeviceLost),
}
impl std::fmt::Display for PresentError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PresentError::OutOfMemory(err) => write!(fmt, "Failed to present image: {}", err),
PresentError::OutOfDate => write!(
fmt,
"Failed to present image: Swapchain is out of date and needs to be re-created"
),
PresentError::SurfaceLost(err) => write!(fmt, "Failed to present image: {}", err),
PresentError::DeviceLost(err) => write!(fmt, "Failed to present image: {}", err),
}
}
}
impl std::error::Error for PresentError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
PresentError::OutOfMemory(err) => Some(err),
PresentError::SurfaceLost(err) => Some(err),
PresentError::DeviceLost(err) => Some(err),
_ => None,
}
}
}
pub trait Swapchain<B: Backend>: fmt::Debug + Any + Send + Sync {
unsafe fn acquire_image(
&mut self,
timeout_ns: u64,
semaphore: Option<&B::Semaphore>,
fence: Option<&B::Fence>,
) -> Result<(SwapImageIndex, Option<Suboptimal>), AcquireError>;
unsafe fn present<'a, S, Iw>(
&'a self,
present_queue: &mut B::CommandQueue,
image_index: SwapImageIndex,
wait_semaphores: Iw,
) -> Result<Option<Suboptimal>, PresentError>
where
Self: 'a + Sized + Borrow<B::Swapchain>,
S: 'a + Borrow<B::Semaphore>,
Iw: IntoIterator<Item = &'a S>,
{
present_queue.present(iter::once((self, image_index)), wait_semaphores)
}
unsafe fn present_without_semaphores<'a>(
&'a self,
present_queue: &mut B::CommandQueue,
image_index: SwapImageIndex,
) -> Result<Option<Suboptimal>, PresentError>
where
Self: 'a + Sized + Borrow<B::Swapchain>,
{
self.present::<B::Semaphore, _>(present_queue, image_index, iter::empty())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum InitError {
UnsupportedWindowHandle,
}
impl std::fmt::Display for InitError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InitError::UnsupportedWindowHandle => write!(
fmt,
"Failed to create surface: Specified window handle is unsupported"
),
}
}
}
impl std::error::Error for InitError {}