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;
#[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)
}
}
#[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: image::Usage::COLOR_ATTACHMENT,
}
}
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::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: *caps.image_count.start(),
image_layers: 1,
image_usage: image::Usage::COLOR_ATTACHMENT,
}
}
pub fn with_present_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
}
}
#[derive(Debug)]
pub struct Suboptimal;
#[derive(Clone, Debug, PartialEq)]
pub enum AcquireError {
OutOfMemory(device::OutOfMemory),
NotReady,
Timeout,
OutOfDate,
SurfaceLost(device::SurfaceLost),
DeviceLost(device::DeviceLost),
}
#[derive(Clone, Debug, PartialEq)]
pub enum PresentError {
OutOfMemory(device::OutOfMemory),
OutOfDate,
SurfaceLost(device::SurfaceLost),
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, 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,
}