use crate::device;
use crate::format::Format;
use crate::image;
use crate::queue::{Capability, CommandQueue};
use crate::Backend;
use std::any::Any;
use std::borrow::Borrow;
use std::cmp::{max, min};
use std::iter;
use std::fmt;
use std::ops::Range;
#[derive(Clone, Copy, Debug, Fail, PartialEq, Eq)]
pub enum CreationError {
#[fail(display = "{}", _0)]
OutOfMemory(device::OutOfMemory),
#[fail(display = "{}", _0)]
DeviceLost(device::DeviceLost),
#[fail(display = "{}", _0)]
SurfaceLost(device::SurfaceLost),
#[fail(display = "{}", _0)]
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)
}
}
#[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: Range<SwapImageIndex>,
pub current_extent: Option<Extent2D>,
pub extents: Range<Extent2D>,
pub max_image_layers: image::Layer,
pub usage: image::Usage,
pub composite_alpha: CompositeAlpha,
}
pub trait Surface<B: Backend>: fmt::Debug + Any + Send + Sync {
fn kind(&self) -> image::Kind;
fn supports_queue_family(&self, family: &B::QueueFamily) -> bool;
fn compatibility(
&self,
physical_device: &B::PhysicalDevice,
) -> (SurfaceCapabilities, Option<Vec<Format>>, Vec<PresentMode>);
}
pub type SwapImageIndex = u32;
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum PresentMode {
Immediate = 0,
Mailbox = 1,
Fifo = 2,
Relaxed = 3,
}
bitflags!(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CompositeAlpha: 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: CompositeAlpha,
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: CompositeAlpha::OPAQUE,
format,
extent: Extent2D { width, height },
image_count,
image_layers: 1,
image_usage: image::Usage::COLOR_ATTACHMENT,
}
}
pub fn from_caps(caps: &SurfaceCapabilities, format: Format, default_extent: Extent2D) -> Self {
let clamped_extent = match caps.current_extent {
Some(current) => current,
None => {
let (min_width, max_width) = (caps.extents.start.width, caps.extents.end.width - 1);
let (min_height, max_height) =
(caps.extents.start.height, caps.extents.end.height - 1);
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 }
}
};
let composite_alpha = if caps.composite_alpha.contains(CompositeAlpha::INHERIT) {
CompositeAlpha::INHERIT
} else if caps.composite_alpha.contains(CompositeAlpha::OPAQUE) {
CompositeAlpha::OPAQUE
} else {
unreachable!("neither INHERIT or OPAQUE CompositeAlpha modes are supported")
};
SwapchainConfig {
present_mode: PresentMode::Fifo,
composite_alpha,
format,
extent: clamped_extent,
image_count: caps.image_count.start,
image_layers: 1,
image_usage: image::Usage::COLOR_ATTACHMENT,
}
}
pub fn with_mode(mut self, mode: PresentMode) -> Self {
self.present_mode = mode;
self
}
pub fn with_image_usage(mut self, usage: image::Usage) -> Self {
self.image_usage = usage;
self
}
}
pub struct Suboptimal;
#[derive(Clone, Copy, Debug, Fail, PartialEq, Eq)]
pub enum AcquireError {
#[fail(display = "{}", _0)]
OutOfMemory(device::OutOfMemory),
#[fail(display = "No images ready")]
NotReady,
#[fail(display = "Swapchain is out of date")]
OutOfDate,
#[fail(display = "{}", _0)]
SurfaceLost(device::SurfaceLost),
#[fail(display = "{}", _0)]
DeviceLost(device::DeviceLost),
}
#[derive(Clone, Copy, Debug, Fail, PartialEq, Eq)]
pub enum PresentError {
#[fail(display = "{}", _0)]
OutOfMemory(device::OutOfMemory),
#[fail(display = "Swapchain is out of date")]
OutOfDate,
#[fail(display = "{}", _0)]
SurfaceLost(device::SurfaceLost),
#[fail(display = "{}", _0)]
DeviceLost(device::DeviceLost),
}
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, C, S, Iw>(
&'a self,
present_queue: &mut CommandQueue<B, C>,
image_index: SwapImageIndex,
wait_semaphores: Iw,
) -> Result<Option<Suboptimal>, PresentError>
where
Self: 'a + Sized + Borrow<B::Swapchain>,
C: Capability,
S: 'a + Borrow<B::Semaphore>,
Iw: IntoIterator<Item = &'a S>,
{
present_queue.present(iter::once((self, image_index)), wait_semaphores)
}
unsafe fn present_nosemaphores<'a, C>(
&'a self,
present_queue: &mut CommandQueue<B, C>,
image_index: SwapImageIndex,
) -> Result<Option<Suboptimal>, PresentError>
where
Self: 'a + Sized + Borrow<B::Swapchain>,
C: Capability,
{
self.present::<_, B::Semaphore, _>(present_queue, image_index, iter::empty())
}
}