gpu-vulkan-0.1.0.137: src/Gpu/Vulkan/Pipeline/Graphics.hs
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables, RankNTypes, TypeApplications #-}
{-# LANGUAGE GADTs, TypeFamilies #-}
{-# LANGUAGE DataKinds, PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
module Gpu.Vulkan.Pipeline.Graphics (
-- * CREATE AND RECREATE
createGs, unsafeRecreateGs, G, CreateInfo(..),
CreateInfoListArgsToGArgs, CreateInfoListToMiddle,
-- ** Group
group, Group, createGs', unsafeDestroyGs, lookup
) where
import Prelude hiding (lookup)
import Foreign.Storable.PeekPoke
import Control.Concurrent.STM
import Control.Concurrent.STM.TSem
import Control.Exception
import Data.Kind
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.TypeLevel.ParMaybe qualified as TPMaybe
import Data.TypeLevel.Tuple.Uncurry
import Data.TypeLevel.Tuple.Index qualified as TIndex
import Data.TypeLevel.Tuple.MapIndex qualified as TMapIndex
import Data.Map qualified as Map
import Data.HeteroParList qualified as HeteroParList
import Data.HeteroParList (pattern (:**))
import Data.HeteroParList.Tuple qualified as HeteroParList
import Data.Word
import Data.Int
import Language.SpirV.ShaderKind
import Gpu.Vulkan.Pipeline.Enum
import Gpu.Vulkan.Pipeline.Graphics.Type
import qualified Gpu.Vulkan.AllocationCallbacks as AllocationCallbacks
import qualified Gpu.Vulkan.AllocationCallbacks.Type as AllocationCallbacks
import qualified Gpu.Vulkan.Device.Type as Device
import qualified Gpu.Vulkan.Pipeline.Graphics.Middle as M
import qualified Gpu.Vulkan.PipelineCache.Type as Cache
import qualified Gpu.Vulkan.PipelineLayout.Type as Layout
import qualified Gpu.Vulkan.RenderPass.Type as RenderPass
import qualified Gpu.Vulkan.Pipeline.DynamicState as DynamicState
import qualified Gpu.Vulkan.Pipeline.ColorBlendState as ColorBlendState
import qualified Gpu.Vulkan.Pipeline.DepthStencilState as DepthStencilState
import qualified Gpu.Vulkan.Pipeline.MultisampleState as MultisampleState
import qualified Gpu.Vulkan.Pipeline.RasterizationState as RasterizationState
import qualified Gpu.Vulkan.Pipeline.ViewportState as ViewportState
import qualified Gpu.Vulkan.Pipeline.TessellationState as TessellationState
import qualified Gpu.Vulkan.Pipeline.InputAssemblyState as InputAssemblyState
import Gpu.Vulkan.Pipeline.VertexInputState.Internal
qualified as VertexInputState
import qualified Gpu.Vulkan.Pipeline.ShaderStage.Internal as ShaderStage
import Gpu.Vulkan.VertexInput qualified as VertexInput
import qualified Gpu.Vulkan.Pipeline.ShaderStage.Middle as ShaderStage.M
-- CREATE AND RECREATE
createGs :: (CreateInfoListToMiddle cias, AllocationCallbacks.ToMiddle mac) =>
Device.D sd -> Maybe (Cache.P sc) ->
HeteroParList.PL (U14 CreateInfo) cias ->
TPMaybe.M (U2 AllocationCallbacks.A) mac ->
(forall sg .
HeteroParList.PL
(U3 (G sg)) (CreateInfoListArgsToGArgs cias) ->
IO a) -> IO a
createGs d@(Device.D dvc) ((Cache.pToMiddle <$>) -> mc) cis
macc@(AllocationCallbacks.toMiddle -> macd) f = bracket
(createInfoListToMiddle d cis >>= \cis' -> M.createGs dvc mc cis'
(AllocationCallbacks.toMiddle macc)
<* destroyShaderStages' d cis' (allocationCallbacksListListFromCreateInfoList cis))
(\gs -> M.destroyGs dvc gs macd) (f . gListFromMiddle)
class GListFromMiddle ss where
gListFromMiddle :: [M.G] -> HeteroParList.PL (U3 (G sg)) ss
instance GListFromMiddle '[] where
gListFromMiddle = \case
[] -> HeteroParList.Nil
_ : _ -> error "Wrong number of elements"
instance GListFromMiddle ss => GListFromMiddle ('(s, t, foo) ': ss) where
gListFromMiddle = \case
g : gs -> U3 (G @_ @s @t g) :** gListFromMiddle @ss gs
[] -> error "Wrong number of elements"
unsafeRecreateGs :: (CreateInfoListToMiddle cias, AllocationCallbacks.ToMiddle mac) =>
Device.D sd -> Maybe (Cache.P s) -> HeteroParList.PL (U14 CreateInfo) cias ->
TPMaybe.M (U2 AllocationCallbacks.A) mac ->
HeteroParList.PL (U3 (G sg)) (CreateInfoListArgsToGArgs cias) -> IO ()
unsafeRecreateGs d@(Device.D dvc) ((Cache.pToMiddle <$>) -> mc) cis macc gpls = do
cis' <- createInfoListToMiddle d cis
M.recreateGs dvc mc cis'
(AllocationCallbacks.toMiddle macc) $ gListToMiddle gpls
destroyShaderStages' d cis' $ allocationCallbacksListListFromCreateInfoList cis
gListToMiddle :: HeteroParList.PL (U3 (G sg)) ss -> [M.G]
gListToMiddle = HeteroParList.toList $ \(U3 (G g)) -> g
-- CREATE INFO
data CreateInfo
mn ssas visa iasa tsssa vpsa rstsa mssa dssa cbsa dsa lyta rpa bpha =
CreateInfo {
createInfoNext :: TMaybe.M mn,
createInfoFlags :: CreateFlags,
createInfoStages ::
HeteroParList.PL (U5 ShaderStage.CreateInfo) ssas,
createInfoVertexInputState ::
Maybe (U3 VertexInputState.CreateInfo visa),
createInfoInputAssemblyState ::
Maybe (InputAssemblyState.CreateInfo iasa),
createInfoTessellationState ::
Maybe (TessellationState.CreateInfo tsssa),
createInfoViewportState :: Maybe (ViewportState.CreateInfo vpsa),
createInfoRasterizationState ::
Maybe (RasterizationState.CreateInfo rstsa),
createInfoMultisampleState ::
Maybe (MultisampleState.CreateInfo mssa),
createInfoDepthStencilState ::
Maybe (DepthStencilState.CreateInfo dssa),
createInfoColorBlendState ::
Maybe (ColorBlendState.CreateInfo cbsa),
createInfoDynamicState :: Maybe (DynamicState.CreateInfo dsa),
createInfoLayout :: U3 Layout.P lyta,
createInfoRenderPass :: RenderPass.R rpa,
createInfoSubpass :: Word32,
createInfoBasePipelineHandle :: Maybe (U4 G bpha),
createInfoBasePipelineIndex :: Int32 }
-- CREATE INFO LIST ARGS TO G ARGS
type family CreateInfoListArgsToGArgs cias where
CreateInfoListArgsToGArgs '[] = '[]
CreateInfoListArgsToGArgs (cia ': cias) =
CreateInfoArgsToGArgs cia ': CreateInfoListArgsToGArgs cias
type family CreateInfoArgsToGArgs cia where
CreateInfoArgsToGArgs '(
n, ssas, '(nv, vibs, vias), iasa, tsssa, vpsa, rstsa, mssa, dssa, cbsa, dsa,
slbtss, rpa, bpha ) = '(vibs, vias, slbtss)
-- CREATE INFO LIST TO MIDDLE
class ( GListFromMiddle (CreateInfoListArgsToGArgs cias),
DestroyShaderStages
(MiddleArgs cias) (TAllocationCallbacksListList cias),
AllocationCallbacksListListFromCreateInfoList cias,
M.CreateInfoListToCore (MiddleArgs cias) ) =>
CreateInfoListToMiddle cias where
type MiddleArgs cias :: [(
Maybe Type, [(Maybe Type, ShaderKind, [Type])], Maybe Type,
Maybe Type, Maybe Type, Maybe Type, Maybe Type, Maybe Type,
Maybe Type, Maybe Type, Maybe Type)]
createInfoListToMiddle ::
Device.D sd -> HeteroParList.PL (U14 CreateInfo) cias ->
IO (HeteroParList.PL (U11 M.CreateInfo) (MiddleArgs cias))
instance CreateInfoListToMiddle '[] where
type MiddleArgs '[] = '[]
createInfoListToMiddle _ HeteroParList.Nil = pure HeteroParList.Nil
instance (
HeteroParList.Map3_5 ssas,
ShaderStage.CreateInfoListToMiddle ssas,
ShaderStage.M.CreateInfoListToCore (ShaderStage.MiddleArgs ssas),
VertexInputState.BindingStrideList vibs VertexInput.Rate,
VertexInputState.AttributeDescriptions vibs vias,
WithPoked (TMaybe.M mn), WithPoked (TMaybe.M nvis),
WithPoked (TMaybe.M iasa), WithPoked (TMaybe.M tsssa),
WithPoked (TMaybe.M vpsa), WithPoked (TMaybe.M rstsa),
WithPoked (TMaybe.M mssa), WithPoked (TMaybe.M dssa),
WithPoked (TMaybe.M cbsa), WithPoked (TMaybe.M dsa),
CreateInfoListToMiddle ss ) =>
CreateInfoListToMiddle ('(
mn, ssas, '(nvis, vibs, vias), iasa, tsssa, vpsa, rstsa, mssa, dssa, cbsa, dsa,
'(sl, sbtss, pcl), rpa, '(sb, vibs', vias', slbtss') ) ': ss) where
type MiddleArgs ('(
mn, ssas, '(nvis, vibs, vias), iasa, tsssa, vpsa, rstsa, mssa, dssa, cbsa, dsa,
'(sl, sbtss, pcl), rpa, '(sb, vibs', vias', slbtss') ) ': ss) =
'(mn, ShaderStage.MiddleArgs ssas, nvis, iasa, tsssa, vpsa, rstsa,
mssa, dssa, cbsa, dsa) ': MiddleArgs ss
createInfoListToMiddle dvc (U14 ci :** cis) = (:**)
<$> (U11 <$> createInfoToMiddle dvc ci)
<*> createInfoListToMiddle dvc cis
createInfoToMiddle :: (
ShaderStage.CreateInfoListToMiddle ssas,
VertexInputState.BindingStrideList vibs VertexInput.Rate,
VertexInputState.AttributeDescriptions vibs vias ) =>
Device.D sd ->
CreateInfo n ssas '(nvis, vibs, vias)
iasa tsssa vpsa rstsa mssa dssa cbsa dsa sl rpa '(sb, vibs', vias', slbtss') ->
IO (M.CreateInfo n (ShaderStage.MiddleArgs ssas)
nvis iasa tsssa vpsa rstsa mssa dssa cbsa dsa)
createInfoToMiddle dvc CreateInfo {
createInfoNext = mnxt,
createInfoFlags = flgs,
createInfoStages = stgs,
createInfoVertexInputState = vis,
createInfoInputAssemblyState = ias,
createInfoTessellationState = ts,
createInfoViewportState = vs,
createInfoRasterizationState = rs,
createInfoMultisampleState = ms,
createInfoDepthStencilState = dss,
createInfoColorBlendState = cbs,
createInfoDynamicState = ds,
createInfoLayout = U3 (Layout.P lyt),
createInfoRenderPass = RenderPass.R rp,
createInfoSubpass = sp,
createInfoBasePipelineHandle = bph,
createInfoBasePipelineIndex = bpi } = do
stgs' <- ShaderStage.createInfoListToMiddle dvc stgs
bph' <- maybe M.gNull (\(U4 (G g)) -> pure g) bph
pure M.CreateInfo {
M.createInfoNext = mnxt,
M.createInfoFlags = flgs,
M.createInfoStages = stgs',
M.createInfoVertexInputState =
VertexInputState.createInfoToMiddle . unU3 <$> vis,
M.createInfoInputAssemblyState = ias,
M.createInfoTessellationState = ts,
M.createInfoViewportState = vs,
M.createInfoRasterizationState = rs,
M.createInfoMultisampleState = ms,
M.createInfoDepthStencilState = dss,
M.createInfoColorBlendState = cbs,
M.createInfoDynamicState = ds,
M.createInfoLayout = lyt,
M.createInfoRenderPass = rp,
M.createInfoSubpass = sp,
M.createInfoBasePipelineHandle = bph',
M.createInfoBasePipelineIndex = bpi }
-- DESTROY SHADER STAGES
class DestroyShaderStages mvs macs where
destroyShaderStages' :: Device.D sd ->
HeteroParList.PL (U11 M.CreateInfo) mvs ->
HeteroParList.PL2
(TPMaybe.M (U2 AllocationCallbacks.A)) macs -> IO ()
instance DestroyShaderStages '[] '[] where
destroyShaderStages' _ HeteroParList.Nil HeteroParList.Nil = pure ()
instance (ShaderStage.DestroyShaderModuleList a2 mac, DestroyShaderStages ss macs) =>
DestroyShaderStages ('(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) ': ss) (mac ': macs) where
destroyShaderStages' dvc (U11 cim :** cims) (mac :** macs) = do
ShaderStage.destroyShaderModuleList dvc (M.createInfoStages cim) mac
destroyShaderStages' dvc cims macs
class AllocationCallbacksListListFromCreateInfoList cias where
type TAllocationCallbacksListList cias :: [[Maybe (Type, Type)]]
allocationCallbacksListListFromCreateInfoList ::
HeteroParList.PL (U14 CreateInfo) cias ->
HeteroParList.PL2
(TPMaybe.M (U2 AllocationCallbacks.A))
(TAllocationCallbacksListList cias)
instance AllocationCallbacksListListFromCreateInfoList '[] where
type TAllocationCallbacksListList '[] = '[]
allocationCallbacksListListFromCreateInfoList
HeteroParList.Nil = HeteroParList.Nil
instance (
HeteroParList.Map3_5 (TIndex.I1_14 cia),
AllocationCallbacksListListFromCreateInfoList cias ) =>
AllocationCallbacksListListFromCreateInfoList (cia ': cias) where
type TAllocationCallbacksListList (cia ': cias) =
TMapIndex.M3_5 (TIndex.I1_14 cia) ':
TAllocationCallbacksListList cias
allocationCallbacksListListFromCreateInfoList (U14 ci :** cis) =
allocationCallbacksListFromCreateInfo ci :**
allocationCallbacksListListFromCreateInfoList cis
allocationCallbacksListFromCreateInfo :: HeteroParList.Map3_5 ssas =>
CreateInfo mn ssas visa iasa tsssa vpsa rstsa mssa dssa cbsa dsa lyta rpa bpha ->
HeteroParList.PL (TPMaybe.M (U2 AllocationCallbacks.A)) (TMapIndex.M3_5 ssas)
allocationCallbacksListFromCreateInfo =
ShaderStage.allocationCallbacksListFromCreateInfoList . createInfoStages
-- Group
data Group sd ma sg k gas = Group (Device.D sd)
(TPMaybe.M (U2 AllocationCallbacks.A) ma)
TSem (TVar (Map.Map k ( HeteroParList.PL (U3 (G sg)) gas)))
group :: AllocationCallbacks.ToMiddle ma =>
Device.D sd -> TPMaybe.M (U2 AllocationCallbacks.A) ma ->
(forall sg . Group sd ma sg k gas -> IO a) -> IO a
group dvc@(Device.D mdvc) mac@(AllocationCallbacks.toMiddle -> mmac) f = do
(sem, m) <- atomically $ (,) <$> newTSem 1 <*> newTVar Map.empty
rtn <- f $ Group dvc mac sem m
((\gs -> M.destroyGs mdvc (gListToMiddle gs) mmac) `mapM_`)
=<< atomically (readTVar m)
pure rtn
createGs' :: (
Ord k,
CreateInfoListToMiddle cias, AllocationCallbacks.ToMiddle mac ) =>
Group sd mac sg k (CreateInfoListArgsToGArgs cias) -> k ->
Maybe (Cache.P sc) ->
HeteroParList.PL (U14 CreateInfo) cias ->
IO (Either String
(HeteroParList.PL (U3 (G sg)) (CreateInfoListArgsToGArgs cias)))
createGs' (Group d@(Device.D dvc)
(AllocationCallbacks.toMiddle -> mmac) sem gss) k
((Cache.pToMiddle <$>) -> mc) cis = do
ok <- atomically do
mx <- Map.lookup k <$> readTVar gss
case mx of
Nothing -> waitTSem sem >> pure True
Just _ -> pure False
if ok
then do gs <- createInfoListToMiddle d cis >>= \cis' -> M.createGs dvc mc cis' mmac
<* destroyShaderStages' d cis'
(allocationCallbacksListListFromCreateInfoList cis)
let gs' = gListFromMiddle gs
atomically $ modifyTVar gss (Map.insert k gs') >> signalTSem sem
pure $ Right gs'
else pure . Left $
"Gpu.Vulkan.Pipeline.Graphics.create' :: The key already exist"
unsafeDestroyGs :: (Ord k, AllocationCallbacks.ToMiddle ma) =>
Group sd ma sg k gas -> k -> IO (Either String ())
unsafeDestroyGs (Group (Device.D mdvc)
(AllocationCallbacks.toMiddle -> mma) sem gss) k = do
mgs <- atomically do
mx <- Map.lookup k <$> readTVar gss
case mx of
Nothing -> pure Nothing
Just _ -> waitTSem sem >> pure mx
case mgs of
Nothing -> pure $ Left
"Gpu.Vulkan.Pipeline.Graphics.unsafeDestroyGs: No such key"
Just gs -> do
atomically . modifyTVar gss $ Map.delete k
M.destroyGs mdvc (gListToMiddle gs) mma
Right <$> atomically (signalTSem sem)
lookup :: Ord k =>
Group sd ma sg k gas -> k -> IO (Maybe (HeteroParList.PL (U3 (G sg)) gas))
lookup (Group _ _ _sem gss) k = atomically $ Map.lookup k <$> readTVar gss