gpu-vulkan-0.1.0.137: src/Gpu/Vulkan/DescriptorSet.hs
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables, RankNTypes, TypeApplications #-}
{-# LANGUAGE GADTs, TypeFamilies #-}
{-# LANGUAGE DataKinds, ConstraintKinds #-}
{-# LANGUAGE KindSignatures, TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
module Gpu.Vulkan.DescriptorSet (
-- * ALLOCATE
allocateDs, D, AllocateInfo(..), DListFromMiddle, DefaultDynamicLengths,
-- ** Descriptor Set Group
Group, group, allocateDs', unsafeFreeDs, lookup,
-- * UPDATE
updateDs,
-- ** Write
W.Write(..), W.WriteListToMiddle,
W.WriteListUpdateDynamicLengths, W.UpdateDynamicLength,
W.WriteSources(..), W.WriteSourcesArg(..),
W.WriteSourcesToMiddle,
-- ** Copy
Copy(..), CopyListToMiddle,
-- ** BindingAndArrayElem
BindingAndArrayElem, W.BindingAndArrayElemImage,
W.BindingAndArrayElemImageWithImmutableSampler,
W.BindingAndArrayElemBuffer, W.BindingAndArrayElemBufferView
) where
import Prelude hiding (lookup)
import Foreign.Storable.PeekPoke
import Data.Default
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.TypeLevel.Tuple.Uncurry
import Data.TypeLevel.Tuple.Index qualified as TIndex
import qualified Data.HeteroParList as HeteroParList
import Data.HeteroParList (pattern (:**))
import Gpu.Vulkan.DescriptorSet.Type
import qualified Gpu.Vulkan.Device.Type as Device
import qualified Gpu.Vulkan.DescriptorPool.Type as Descriptor.Pool
import qualified Gpu.Vulkan.DescriptorSetLayout.Type as Layout
import qualified Gpu.Vulkan.DescriptorSetLayout.Middle as Layout.M
import qualified Gpu.Vulkan.DescriptorSet.Write as W
import qualified Gpu.Vulkan.DescriptorSet.Middle as M
import Gpu.Vulkan.DescriptorSet.Copy
import Gpu.Vulkan.Object.Base qualified as KObj
import Control.Concurrent.STM
import Control.Concurrent.STM.TSem
import Data.Map qualified as Map
import Data.IORef.ToolsYj
import Data.TypeLevel.Tuple.MapIndex qualified
import Control.Monad
import Debug
layoutToMiddle :: U2 Layout.D slbts -> Layout.M.D
layoutToMiddle (U2 (Layout.D l)) = l
data AllocateInfo mn sp slbtss = AllocateInfo {
allocateInfoNext :: TMaybe.M mn,
allocateInfoDescriptorPool :: Descriptor.Pool.P sp,
allocateInfoSetLayouts :: HeteroParList.PL (U2 Layout.D) slbtss }
deriving instance (Show (TMaybe.M n), Show (HeteroParList.PL (U2 Layout.D) slbtss)) =>
Show (AllocateInfo n sp slbtss)
allocateInfoToMiddle :: AllocateInfo n sp slbtss -> M.AllocateInfo n
allocateInfoToMiddle AllocateInfo {
allocateInfoNext = mnxt,
allocateInfoDescriptorPool = Descriptor.Pool.P dp,
allocateInfoSetLayouts = dscsls
} = M.AllocateInfo {
M.allocateInfoNext = mnxt,
M.allocateInfoDescriptorPool = dp,
M.allocateInfoSetLayouts =
HeteroParList.toList layoutToMiddle dscsls }
class DListFromMiddle slbtss where
dListFromMiddle :: [M.D] -> IO (HeteroParList.PL (D s) slbtss)
instance DListFromMiddle '[] where
dListFromMiddle = \case [] -> pure HeteroParList.Nil; _ -> error "bad"
instance (
DefaultDynamicLengths slbts,
DListFromMiddle slbtss ) =>
DListFromMiddle (slbts ': slbtss) where
dListFromMiddle = \case
(d : ds) -> (:**)
<$> ((`D` d) <$> newDefaultIORef)
<*> dListFromMiddle @slbtss ds
_ -> error "bad"
type DefaultDynamicLengths slbts = Default
(HeteroParList.PL
(HeteroParList.PL KObj.Length)
(Layout.BindingTypeListBufferOnlyDynamics (TIndex.I1_2 slbts)))
allocateDs :: (WithPoked (TMaybe.M mn), DListFromMiddle slbtss) =>
Device.D sd -> AllocateInfo mn sp slbtss ->
(forall s . HeteroParList.PL (D s) slbtss -> IO a) -> IO a
allocateDs (Device.D dvc) ai f = do
dsm <- M.allocateDs dvc (allocateInfoToMiddle ai)
ds <- dListFromMiddle dsm
f ds <* M.freeDs dvc
((\(Descriptor.Pool.P p) -> p) $ allocateInfoDescriptorPool ai)
dsm
data Group sd s k sp slbtss = Group (Device.D sd) TSem
(TVar (Map.Map k (Descriptor.Pool.P sp, HeteroParList.PL (D s) slbtss)))
group :: Device.D sd -> (forall s . Group sd s k sp slbtss -> IO a) -> IO a
group dv@(Device.D mdvc) f = do
(sem, dsss) <- atomically $ (,) <$> newTSem 1 <*> newTVar Map.empty
rtn <- f $ Group dv sem dsss
((\(Descriptor.Pool.P dsp, dss) -> M.freeDs mdvc dsp $ dListToMiddle dss) `mapM_`) =<<
(Map.elems <$> atomically (readTVar dsss))
pure rtn
allocateDs' :: (Ord k, WithPoked (TMaybe.M mn), DListFromMiddle slbtss) =>
Group sd sg k sp slbtss -> k -> AllocateInfo mn sp slbtss ->
IO (Either String (HeteroParList.PL (D sg) slbtss))
allocateDs' (Group (Device.D dvc) sem mp) k ai = do
ok <- atomically do
mx <- (Map.lookup k) <$> readTVar mp
case mx of
Nothing -> waitTSem sem >> pure True
Just _ -> pure False
if ok
then do dsm <- M.allocateDs dvc (allocateInfoToMiddle ai)
ds <- dListFromMiddle dsm
atomically do
modifyTVar mp (Map.insert k (sp, ds))
signalTSem sem
pure $ Right ds
else pure . Left
$ "Gpu.Vulkan.DescriptorSet.allocateDs': The key already exist"
-- where Descriptor.Pool.P sp = allocateInfoDescriptorPool ai
where sp = allocateInfoDescriptorPool ai
unsafeFreeDs :: Ord k => Group sd sg k sp slbtss -> k -> IO (Either String ())
unsafeFreeDs (Group (Device.D mdvc) sem mp) k = do
md <- atomically do
mx <- Map.lookup k <$> readTVar mp
case mx of
Nothing -> pure Nothing
Just _ -> waitTSem sem >> pure mx
case md of
Nothing -> pure $ Left "Gpu.Vulkan.DescriptorSet.unsafeFreeDs"
Just (Descriptor.Pool.P p, ds) -> do
M.freeDs mdvc p (dListToMiddle ds)
atomically do
modifyTVar mp (Map.delete k)
signalTSem sem
pure $ Right ()
lookup :: Ord k =>
Group sd s k sp slbtss -> k -> IO (Maybe (HeteroParList.PL (D s) slbtss))
lookup (Group _ _sem mp) k = atomically $ (snd <$>) . Map.lookup k <$> readTVar mp
dListToMiddle :: HeteroParList.PL (D s) slbtss -> [M.D]
dListToMiddle = HeteroParList.toList \(D _ md) -> md
updateDs :: (
Show (HeteroParList.PL M.Write (Data.TypeLevel.Tuple.MapIndex.M0_5 writeArgs)),
W.WriteListToMiddle writeArgs,
W.WriteListUpdateDynamicLengths writeArgs,
CopyListToMiddle copyArgs) =>
Device.D sd ->
HeteroParList.PL (U5 W.Write) writeArgs ->
HeteroParList.PL (U8 Copy) copyArgs -> IO ()
updateDs (Device.D dvc) ws cs = when debug (print ws') >>
W.writeListUpdateDynamicLength ws >> M.updateDs dvc ws' cs'
where ws' = W.writeListToMiddle ws; cs' = copyListToMiddle cs