{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC -Wno-missing-signatures #-}
module Vulkan.Utils.Swapchain
( Swapchain (..)
, SwapchainConfig (..)
, defaultSwapchainConfig
, allocateSwapchain
, recreateSwapchain
, threwSwapchainError
) where
import Control.Exception (throwIO, tryJust)
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Resource
import Data.Bits
import Data.Either (isLeft)
import Data.Foldable (for_, traverse_)
import Data.Vector (Vector)
import qualified Data.Vector as V
import GHC.Generics (Generic)
import Vulkan.CStruct.Extends (pattern (:&), pattern (::&))
import qualified Vulkan.Core10 as Vk
import Vulkan.Core12.Promoted_From_VK_KHR_timeline_semaphore (SemaphoreTypeCreateInfo (..), pattern SEMAPHORE_TYPE_BINARY)
import Vulkan.Exception (VulkanException (..))
import Vulkan.Extensions.VK_KHR_surface as SurfaceCapabilitiesKHR (SurfaceCapabilitiesKHR (..))
import Vulkan.Extensions.VK_KHR_surface as SurfaceFormatKHR (SurfaceFormatKHR (..))
import qualified Vulkan.Extensions.VK_KHR_surface as KHR
import qualified Vulkan.Extensions.VK_KHR_swapchain as KHR
import Vulkan.Utils.Misc ((.&&.))
import Vulkan.Utils.RefCounted (RefCounted, newRefCounted, releaseRefCounted)
import Vulkan.Zero (zero)
data SwapchainConfig = SwapchainConfig
{ SwapchainConfig -> [ImageUsageFlagBits]
scRequiredUsageFlags :: [Vk.ImageUsageFlagBits]
, SwapchainConfig -> [FormatFeatureFlagBits]
scRequiredFormatFeatures :: [Vk.FormatFeatureFlagBits]
, SwapchainConfig -> [PresentModeKHR]
scDesiredPresentModes :: [KHR.PresentModeKHR]
, SwapchainConfig -> [SurfaceFormatKHR -> Bool]
scSurfaceFormatPreferences :: [KHR.SurfaceFormatKHR -> Bool]
}
deriving ((forall x. SwapchainConfig -> Rep SwapchainConfig x)
-> (forall x. Rep SwapchainConfig x -> SwapchainConfig)
-> Generic SwapchainConfig
forall x. Rep SwapchainConfig x -> SwapchainConfig
forall x. SwapchainConfig -> Rep SwapchainConfig x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. SwapchainConfig -> Rep SwapchainConfig x
from :: forall x. SwapchainConfig -> Rep SwapchainConfig x
$cto :: forall x. Rep SwapchainConfig x -> SwapchainConfig
to :: forall x. Rep SwapchainConfig x -> SwapchainConfig
Generic)
defaultSwapchainConfig :: SwapchainConfig
defaultSwapchainConfig :: SwapchainConfig
defaultSwapchainConfig =
SwapchainConfig
{ scRequiredUsageFlags :: [ImageUsageFlagBits]
scRequiredUsageFlags = [ImageUsageFlagBits
Vk.IMAGE_USAGE_COLOR_ATTACHMENT_BIT]
, scRequiredFormatFeatures :: [FormatFeatureFlagBits]
scRequiredFormatFeatures = []
, scDesiredPresentModes :: [PresentModeKHR]
scDesiredPresentModes =
[ PresentModeKHR
KHR.PRESENT_MODE_FIFO_RELAXED_KHR
, PresentModeKHR
KHR.PRESENT_MODE_FIFO_KHR
]
, scSurfaceFormatPreferences :: [SurfaceFormatKHR -> Bool]
scSurfaceFormatPreferences = []
}
data Swapchain = Swapchain
{ Swapchain -> SwapchainKHR
sSwapchain :: KHR.SwapchainKHR
, Swapchain -> SurfaceKHR
sSurface :: KHR.SurfaceKHR
, Swapchain -> SurfaceFormatKHR
sFormat :: KHR.SurfaceFormatKHR
, Swapchain -> Extent2D
sExtent :: Vk.Extent2D
, Swapchain -> PresentModeKHR
sPresentMode :: KHR.PresentModeKHR
, Swapchain -> Vector Image
sImages :: Vector Vk.Image
, Swapchain -> Vector ImageView
sImageViews :: Vector Vk.ImageView
, Swapchain -> Vector Semaphore
sRenderFinished :: Vector Vk.Semaphore
, Swapchain -> RefCounted
sRelease :: RefCounted
, Swapchain -> SwapchainConfig
sConfig :: SwapchainConfig
}
deriving ((forall x. Swapchain -> Rep Swapchain x)
-> (forall x. Rep Swapchain x -> Swapchain) -> Generic Swapchain
forall x. Rep Swapchain x -> Swapchain
forall x. Swapchain -> Rep Swapchain x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Swapchain -> Rep Swapchain x
from :: forall x. Swapchain -> Rep Swapchain x
$cto :: forall x. Rep Swapchain x -> Swapchain
to :: forall x. Rep Swapchain x -> Swapchain
Generic)
allocateSwapchain
:: (MonadResource m)
=> Vk.PhysicalDevice
-> Vk.Device
-> SwapchainConfig
-> KHR.SwapchainKHR
-> Vk.Extent2D
-> KHR.SurfaceKHR
-> m Swapchain
allocateSwapchain :: forall (m :: * -> *).
MonadResource m =>
PhysicalDevice
-> Device
-> SwapchainConfig
-> SwapchainKHR
-> Extent2D
-> SurfaceKHR
-> m Swapchain
allocateSwapchain PhysicalDevice
phys Device
dev SwapchainConfig
cfg SwapchainKHR
oldSwapchain Extent2D
windowSize SurfaceKHR
surface = do
(sSwapchain, sFormat, sExtent, sPresentMode, swapchainKey) <-
PhysicalDevice
-> Device
-> SwapchainConfig
-> SwapchainKHR
-> Extent2D
-> SurfaceKHR
-> m (SwapchainKHR, SurfaceFormatKHR, Extent2D, PresentModeKHR,
ReleaseKey)
forall (m :: * -> *).
MonadResource m =>
PhysicalDevice
-> Device
-> SwapchainConfig
-> SwapchainKHR
-> Extent2D
-> SurfaceKHR
-> m (SwapchainKHR, SurfaceFormatKHR, Extent2D, PresentModeKHR,
ReleaseKey)
allocateSwapchainEx PhysicalDevice
phys Device
dev SwapchainConfig
cfg SwapchainKHR
oldSwapchain Extent2D
windowSize SurfaceKHR
surface
(_, sImages) <- KHR.getSwapchainImagesKHR dev sSwapchain
(imageViewKeys, sImageViews) <-
fmap V.unzip . V.forM sImages $ \Image
image ->
Device -> Format -> Image -> m (ReleaseKey, ImageView)
forall (m :: * -> *).
MonadResource m =>
Device -> Format -> Image -> m (ReleaseKey, ImageView)
allocateImageView Device
dev (SurfaceFormatKHR -> Format
SurfaceFormatKHR.format SurfaceFormatKHR
sFormat) Image
image
(renderFinishedKeys, sRenderFinished) <-
fmap V.unzip . V.forM sImages $ \Image
_image ->
Device
-> SemaphoreCreateInfo '[SemaphoreTypeCreateInfo]
-> Maybe AllocationCallbacks
-> (IO Semaphore
-> (Semaphore -> IO ()) -> m (ReleaseKey, Semaphore))
-> m (ReleaseKey, Semaphore)
forall (a :: [*]) (io :: * -> *) r.
(Extendss SemaphoreCreateInfo a, PokeChain a, MonadIO io) =>
Device
-> SemaphoreCreateInfo a
-> Maybe AllocationCallbacks
-> (io Semaphore -> (Semaphore -> io ()) -> r)
-> r
Vk.withSemaphore
Device
dev
(SemaphoreCreateInfo '[]
forall a. Zero a => a
zero SemaphoreCreateInfo '[]
-> Chain '[SemaphoreTypeCreateInfo]
-> SemaphoreCreateInfo '[SemaphoreTypeCreateInfo]
forall (a :: [*] -> *) (es :: [*]) (es' :: [*]).
Extensible a =>
a es' -> Chain es -> a es
::& SemaphoreType -> Word64 -> SemaphoreTypeCreateInfo
SemaphoreTypeCreateInfo SemaphoreType
SEMAPHORE_TYPE_BINARY Word64
0 SemaphoreTypeCreateInfo
-> Chain '[] -> Chain '[SemaphoreTypeCreateInfo]
forall e (es :: [*]). e -> Chain es -> Chain (e : es)
:& ())
Maybe AllocationCallbacks
forall a. Maybe a
Nothing
IO Semaphore -> (Semaphore -> IO ()) -> m (ReleaseKey, Semaphore)
forall (m :: * -> *) a.
MonadResource m =>
IO a -> (a -> IO ()) -> m (ReleaseKey, a)
allocate
sRelease <- newRefCounted $ do
traverse_ release renderFinishedKeys
traverse_ release imageViewKeys
release swapchainKey
pure Swapchain{sSurface = surface, sConfig = cfg, ..}
recreateSwapchain
:: (MonadResource m)
=> Vk.PhysicalDevice
-> Vk.Device
-> Vk.Extent2D
-> Swapchain
-> m Swapchain
recreateSwapchain :: forall (m :: * -> *).
MonadResource m =>
PhysicalDevice -> Device -> Extent2D -> Swapchain -> m Swapchain
recreateSwapchain PhysicalDevice
phys Device
dev Extent2D
newSize Swapchain
old = do
fresh <- PhysicalDevice
-> Device
-> SwapchainConfig
-> SwapchainKHR
-> Extent2D
-> SurfaceKHR
-> m Swapchain
forall (m :: * -> *).
MonadResource m =>
PhysicalDevice
-> Device
-> SwapchainConfig
-> SwapchainKHR
-> Extent2D
-> SurfaceKHR
-> m Swapchain
allocateSwapchain PhysicalDevice
phys Device
dev (Swapchain -> SwapchainConfig
sConfig Swapchain
old) (Swapchain -> SwapchainKHR
sSwapchain Swapchain
old) Extent2D
newSize (Swapchain -> SurfaceKHR
sSurface Swapchain
old)
releaseRefCounted (sRelease old)
pure fresh
allocateSwapchainEx
:: (MonadResource m)
=> Vk.PhysicalDevice
-> Vk.Device
-> SwapchainConfig
-> KHR.SwapchainKHR
-> Vk.Extent2D
-> KHR.SurfaceKHR
-> m (KHR.SwapchainKHR, SurfaceFormatKHR, Vk.Extent2D, KHR.PresentModeKHR, ReleaseKey)
allocateSwapchainEx :: forall (m :: * -> *).
MonadResource m =>
PhysicalDevice
-> Device
-> SwapchainConfig
-> SwapchainKHR
-> Extent2D
-> SurfaceKHR
-> m (SwapchainKHR, SurfaceFormatKHR, Extent2D, PresentModeKHR,
ReleaseKey)
allocateSwapchainEx PhysicalDevice
phys Device
dev SwapchainConfig
cfg SwapchainKHR
oldSwapchain Extent2D
explicitSize SurfaceKHR
surf = do
surfaceCaps <- PhysicalDevice -> SurfaceKHR -> m SurfaceCapabilitiesKHR
forall (io :: * -> *).
MonadIO io =>
PhysicalDevice -> SurfaceKHR -> io SurfaceCapabilitiesKHR
KHR.getPhysicalDeviceSurfaceCapabilitiesKHR PhysicalDevice
phys SurfaceKHR
surf
for_ (scRequiredUsageFlags cfg) $ \ImageUsageFlagBits
f ->
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (SurfaceCapabilitiesKHR -> ImageUsageFlagBits
supportedUsageFlags SurfaceCapabilitiesKHR
surfaceCaps ImageUsageFlagBits -> ImageUsageFlagBits -> Bool
forall a. Bits a => a -> a -> Bool
.&&. ImageUsageFlagBits
f) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (String -> IO ()) -> String -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IOError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (IOError -> IO ()) -> (String -> IOError) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IOError
userError (String -> m ()) -> String -> m ()
forall a b. (a -> b) -> a -> b
$
String
"Surface images do not support " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ImageUsageFlagBits -> String
forall a. Show a => a -> String
show ImageUsageFlagBits
f
(_, availablePresentModes) <- KHR.getPhysicalDeviceSurfacePresentModesKHR phys surf
presentMode <-
case filter (`V.elem` availablePresentModes) (scDesiredPresentModes cfg) of
[] -> IO PresentModeKHR -> m PresentModeKHR
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO PresentModeKHR -> m PresentModeKHR)
-> (String -> IO PresentModeKHR) -> String -> m PresentModeKHR
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IOError -> IO PresentModeKHR
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (IOError -> IO PresentModeKHR)
-> (String -> IOError) -> String -> IO PresentModeKHR
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IOError
userError (String -> m PresentModeKHR) -> String -> m PresentModeKHR
forall a b. (a -> b) -> a -> b
$ String
"Unable to find a suitable present mode for swapchain"
PresentModeKHR
x : [PresentModeKHR]
_ -> PresentModeKHR -> m PresentModeKHR
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure PresentModeKHR
x
(_, availableFormats) <- KHR.getPhysicalDeviceSurfaceFormatsKHR phys surf
surfaceFormat <- selectSurfaceFormat phys cfg availableFormats
let imageExtent =
case SurfaceCapabilitiesKHR -> Extent2D
currentExtent (SurfaceCapabilitiesKHR
surfaceCaps :: SurfaceCapabilitiesKHR) of
Vk.Extent2D Word32
w Word32
h | Word32
w Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
forall a. Bounded a => a
maxBound, Word32
h Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
forall a. Bounded a => a
maxBound -> Extent2D
explicitSize
Extent2D
e -> Extent2D
e
let imageCount =
let
limit :: Word32
limit = case SurfaceCapabilitiesKHR -> Word32
maxImageCount (SurfaceCapabilitiesKHR
surfaceCaps :: SurfaceCapabilitiesKHR) of
Word32
0 -> Word32
forall a. Bounded a => a
maxBound
Word32
n -> Word32
n
buffer :: a
buffer = a
1
desired :: Word32
desired = Word32
forall {a}. Num a => a
buffer Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ SurfaceCapabilitiesKHR -> Word32
SurfaceCapabilitiesKHR.minImageCount SurfaceCapabilitiesKHR
surfaceCaps
in
Word32 -> Word32 -> Word32
forall a. Ord a => a -> a -> a
min Word32
limit Word32
desired
compositeAlphaMode <-
if KHR.COMPOSITE_ALPHA_OPAQUE_BIT_KHR .&&. supportedCompositeAlpha surfaceCaps
then pure KHR.COMPOSITE_ALPHA_OPAQUE_BIT_KHR
else liftIO . throwIO . userError $ "Surface doesn't support COMPOSITE_ALPHA_OPAQUE_BIT_KHR"
let swapchainCreateInfo =
KHR.SwapchainCreateInfoKHR
{ surface :: SurfaceKHR
surface = SurfaceKHR
surf
, next :: Chain '[]
next = ()
, flags :: SwapchainCreateFlagsKHR
flags = SwapchainCreateFlagsKHR
forall a. Zero a => a
zero
, queueFamilyIndices :: Vector Word32
queueFamilyIndices = Vector Word32
forall a. Monoid a => a
mempty
, minImageCount :: Word32
minImageCount = Word32
imageCount
, imageFormat :: Format
imageFormat = SurfaceFormatKHR -> Format
SurfaceFormatKHR.format SurfaceFormatKHR
surfaceFormat
, imageColorSpace :: ColorSpaceKHR
imageColorSpace = SurfaceFormatKHR -> ColorSpaceKHR
colorSpace SurfaceFormatKHR
surfaceFormat
, imageExtent :: Extent2D
imageExtent = Extent2D
imageExtent
, imageArrayLayers :: Word32
imageArrayLayers = Word32
1
, imageUsage :: ImageUsageFlagBits
imageUsage = (ImageUsageFlagBits -> ImageUsageFlagBits -> ImageUsageFlagBits)
-> ImageUsageFlagBits -> [ImageUsageFlagBits] -> ImageUsageFlagBits
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ImageUsageFlagBits -> ImageUsageFlagBits -> ImageUsageFlagBits
forall a. Bits a => a -> a -> a
(.|.) ImageUsageFlagBits
forall a. Zero a => a
zero (SwapchainConfig -> [ImageUsageFlagBits]
scRequiredUsageFlags SwapchainConfig
cfg)
, imageSharingMode :: SharingMode
imageSharingMode = SharingMode
Vk.SHARING_MODE_EXCLUSIVE
, preTransform :: SurfaceTransformFlagBitsKHR
preTransform = SurfaceCapabilitiesKHR -> SurfaceTransformFlagBitsKHR
SurfaceCapabilitiesKHR.currentTransform SurfaceCapabilitiesKHR
surfaceCaps
, compositeAlpha :: CompositeAlphaFlagBitsKHR
compositeAlpha = CompositeAlphaFlagBitsKHR
compositeAlphaMode
, presentMode :: PresentModeKHR
presentMode = PresentModeKHR
presentMode
, clipped :: Bool
clipped = Bool
True
, oldSwapchain :: SwapchainKHR
oldSwapchain = SwapchainKHR
oldSwapchain
}
(key, swapchain) <- KHR.withSwapchainKHR dev swapchainCreateInfo Nothing allocate
pure (swapchain, surfaceFormat, imageExtent, presentMode, key)
allocateImageView
:: (MonadResource m)
=> Vk.Device
-> Vk.Format
-> Vk.Image
-> m (ReleaseKey, Vk.ImageView)
allocateImageView :: forall (m :: * -> *).
MonadResource m =>
Device -> Format -> Image -> m (ReleaseKey, ImageView)
allocateImageView Device
dev Format
format Image
image =
Device
-> ImageViewCreateInfo '[]
-> Maybe AllocationCallbacks
-> (IO ImageView
-> (ImageView -> IO ()) -> m (ReleaseKey, ImageView))
-> m (ReleaseKey, ImageView)
forall (a :: [*]) (io :: * -> *) r.
(Extendss ImageViewCreateInfo a, PokeChain a, MonadIO io) =>
Device
-> ImageViewCreateInfo a
-> Maybe AllocationCallbacks
-> (io ImageView -> (ImageView -> io ()) -> r)
-> r
Vk.withImageView Device
dev ImageViewCreateInfo '[]
imageViewCreateInfo Maybe AllocationCallbacks
forall a. Maybe a
Nothing IO ImageView -> (ImageView -> IO ()) -> m (ReleaseKey, ImageView)
forall (m :: * -> *) a.
MonadResource m =>
IO a -> (a -> IO ()) -> m (ReleaseKey, a)
allocate
where
imageViewCreateInfo :: ImageViewCreateInfo '[]
imageViewCreateInfo =
ImageViewCreateInfo '[]
forall a. Zero a => a
zero
{ Vk.image = image
, Vk.viewType = Vk.IMAGE_VIEW_TYPE_2D
, Vk.format = format
, Vk.components =
zero
{ Vk.r = Vk.COMPONENT_SWIZZLE_IDENTITY
, Vk.g = Vk.COMPONENT_SWIZZLE_IDENTITY
, Vk.b = Vk.COMPONENT_SWIZZLE_IDENTITY
, Vk.a = Vk.COMPONENT_SWIZZLE_IDENTITY
}
, Vk.subresourceRange =
zero
{ Vk.aspectMask = Vk.IMAGE_ASPECT_COLOR_BIT
, Vk.baseMipLevel = 0
, Vk.levelCount = 1
, Vk.baseArrayLayer = 0
, Vk.layerCount = 1
}
}
selectSurfaceFormat
:: (MonadIO m)
=> Vk.PhysicalDevice
-> SwapchainConfig
-> Vector SurfaceFormatKHR
-> m SurfaceFormatKHR
selectSurfaceFormat :: forall (m :: * -> *).
MonadIO m =>
PhysicalDevice
-> SwapchainConfig
-> ("surfaceFormats" ::: Vector SurfaceFormatKHR)
-> m SurfaceFormatKHR
selectSurfaceFormat PhysicalDevice
phys SwapchainConfig
cfg "surfaceFormats" ::: Vector SurfaceFormatKHR
fmts = do
good <- (SurfaceFormatKHR -> m Bool)
-> ("surfaceFormats" ::: Vector SurfaceFormatKHR)
-> m ("surfaceFormats" ::: Vector SurfaceFormatKHR)
forall (m :: * -> *) a.
Monad m =>
(a -> m Bool) -> Vector a -> m (Vector a)
V.filterM SurfaceFormatKHR -> m Bool
featuresOK "surfaceFormats" ::: Vector SurfaceFormatKHR
fmts
let fallback = if ("surfaceFormats" ::: Vector SurfaceFormatKHR) -> Bool
forall a. Vector a -> Bool
V.null "surfaceFormats" ::: Vector SurfaceFormatKHR
good then ("surfaceFormats" ::: Vector SurfaceFormatKHR) -> SurfaceFormatKHR
forall a. Vector a -> a
V.head "surfaceFormats" ::: Vector SurfaceFormatKHR
fmts else ("surfaceFormats" ::: Vector SurfaceFormatKHR) -> SurfaceFormatKHR
forall a. Vector a -> a
V.head "surfaceFormats" ::: Vector SurfaceFormatKHR
good
pure $ pickPreference (scSurfaceFormatPreferences cfg) good fallback
where
featuresOK :: SurfaceFormatKHR -> m Bool
featuresOK SurfaceFormatKHR
f = do
props <- PhysicalDevice -> Format -> m FormatProperties
forall (io :: * -> *).
MonadIO io =>
PhysicalDevice -> Format -> io FormatProperties
Vk.getPhysicalDeviceFormatProperties PhysicalDevice
phys (SurfaceFormatKHR -> Format
SurfaceFormatKHR.format SurfaceFormatKHR
f)
pure $ all (Vk.optimalTilingFeatures props .&&.) (scRequiredFormatFeatures cfg)
pickPreference :: [t -> Bool] -> Vector t -> t -> t
pickPreference [] Vector t
_ t
fallback = t
fallback
pickPreference (t -> Bool
p : [t -> Bool]
ps) Vector t
good t
fallback =
case (t -> Bool) -> Vector t -> Maybe t
forall a. (a -> Bool) -> Vector a -> Maybe a
V.find t -> Bool
p Vector t
good of
Just t
f -> t
f
Maybe t
Nothing -> [t -> Bool] -> Vector t -> t -> t
pickPreference [t -> Bool]
ps Vector t
good t
fallback
threwSwapchainError :: IO b -> IO Bool
threwSwapchainError :: forall b. IO b -> IO Bool
threwSwapchainError = (Either Result b -> Bool) -> IO (Either Result b) -> IO Bool
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Either Result b -> Bool
forall a b. Either a b -> Bool
isLeft (IO (Either Result b) -> IO Bool)
-> (IO b -> IO (Either Result b)) -> IO b -> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (VulkanException -> Maybe Result) -> IO b -> IO (Either Result b)
forall e b a.
Exception e =>
(e -> Maybe b) -> IO a -> IO (Either b a)
tryJust VulkanException -> Maybe Result
swapchainError
where
swapchainError :: VulkanException -> Maybe Result
swapchainError = \case
VulkanException e :: Result
e@Result
Vk.ERROR_OUT_OF_DATE_KHR -> Result -> Maybe Result
forall a. a -> Maybe a
Just Result
e
VulkanException Result
_ -> Maybe Result
forall a. Maybe a
Nothing