packages feed

gpu-vulkan-middle-0.1.0.54: src/Gpu/Vulkan/DescriptorSet/Middle/Internal.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, LambdaCase, TupleSections #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.DescriptorSet.Middle.Internal (
	D(..), AllocateInfo(..), allocateDs, freeDs,
	Write(..), WriteSources(..), Copy(..),
	updateDs, WriteListToCore, CopyListToCore ) where

import Foreign.Ptr
import Foreign.Marshal.Array
import Foreign.Storable
import Foreign.Storable.PeekPoke (
	WithPoked, withPoked, withPoked', withPtrS, pattern NullPtr )
import Control.Arrow
import Control.Monad.Trans
import Control.Monad.Cont
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.List (genericLength)
import Data.HeteroParList (pattern (:**))
import Data.HeteroParList qualified as HeteroParList
import Data.Word

import Gpu.Vulkan.Exception.Middle.Internal
import Gpu.Vulkan.Exception.Enum

import qualified Gpu.Vulkan.Device.Middle.Internal as Device
import qualified Gpu.Vulkan.BufferView.Middle.Internal as BufferView
import qualified Gpu.Vulkan.Descriptor.Enum as Descriptor
import qualified Gpu.Vulkan.Descriptor.Middle.Internal as Descriptor
import qualified Gpu.Vulkan.DescriptorPool.Middle.Internal as Pool
import qualified Gpu.Vulkan.DescriptorSetLayout.Middle.Internal as Layout
import qualified Gpu.Vulkan.DescriptorSet.Core as C

import qualified Gpu.Vulkan.Descriptor.Core as Descriptor.C
import qualified Gpu.Vulkan.BufferView.Core as BufferView.C

data AllocateInfo mn = AllocateInfo {
	allocateInfoNext :: TMaybe.M mn,
	allocateInfoDescriptorPool :: Pool.D,
	allocateInfoSetLayouts :: [Layout.D] }

deriving instance Show (TMaybe.M mn) => Show (AllocateInfo mn)

allocateInfoToCore :: WithPoked (TMaybe.M mn) =>
	AllocateInfo mn -> (C.AllocateInfo -> IO a) -> IO ()
allocateInfoToCore AllocateInfo {
	allocateInfoNext = mnxt,
	allocateInfoDescriptorPool = Pool.D pl,
	allocateInfoSetLayouts =
		(((id &&& fromIntegral) `first`) . (length &&& id)) ->
		((dsci, dscw), sls) } f =
	withPoked' mnxt \pnxt -> withPtrS pnxt \(castPtr -> pnxt') -> do
	psls <- allocaArray dsci \p ->
		p <$ (pokeArray p $ (\(Layout.D l) -> l) <$> sls)
	f C.AllocateInfo {
		C.allocateInfoSType = (),
		C.allocateInfoPNext = pnxt',
		C.allocateInfoDescriptorPool = pl,
		C.allocateInfoDescriptorSetCount = dscw,
		C.allocateInfoPSetLayouts = psls }

newtype D = D C.D deriving Show

allocateDs :: WithPoked (TMaybe.M mn) => Device.D -> AllocateInfo mn -> IO [D]
allocateDs (Device.D dvc) ai = ((D <$>) <$>) . ($ pure) $ runContT do
	let	dsc = length $ allocateInfoSetLayouts ai
	pss <- ContT $ allocaArray dsc
	lift $ allocateInfoToCore ai \fai ->
		withPoked fai \pai -> do
			r <- C.allocateDs dvc pai pss
			throwUnlessSuccess $ Result r
	lift $ peekArray dsc pss

freeDs :: Device.D -> Pool.D -> [D] -> IO ()
freeDs (Device.D dvc) (Pool.D pl) ds = allocaArray ln \pds -> do
	pokeArray pds $ (\(D d) -> d) <$> ds
	r <- C.freeDs dvc pl ln pds
	throwUnlessSuccess $ Result r
	where
	ln :: Integral n => n
	ln = genericLength ds

data Copy mn = Copy {
	copyNext :: TMaybe.M mn,
	copySrcSet :: D,
	copySrcBinding :: Word32,
	copySrcArrayElement :: Word32,
	copyDstSet :: D,
	copyDstBinding :: Word32,
	copyDstArrayElement :: Word32,
	copyDescriptorCount :: Word32 }

deriving instance Show (TMaybe.M mn) => Show (Copy mn)

class CopyListToCore cs where
	copyListToCore ::
		HeteroParList.PL Copy cs -> ([C.Copy] -> IO a) -> IO ()

instance CopyListToCore '[] where
	copyListToCore HeteroParList.Nil f = () <$ f []

instance (WithPoked (TMaybe.M c), CopyListToCore cs) =>
	CopyListToCore (c ': cs) where
	copyListToCore (c :** cs) f =
		copyToCore c \cc -> copyListToCore cs \ccs -> f $ cc : ccs

copyToCore :: WithPoked (TMaybe.M mn) => Copy mn -> (C.Copy -> IO a) -> IO ()
copyToCore Copy {
	copyNext = mnxt,
	copySrcSet = D ss,
	copySrcBinding = sb,
	copySrcArrayElement = sae,
	copyDstSet = D ds,
	copyDstBinding = db,
	copyDstArrayElement = dae,
	copyDescriptorCount = dc } f =
	withPoked' mnxt \pnxt ->
	withPtrS pnxt \(castPtr -> pnxt') -> f C.Copy {
		C.copySType = (),
		C.copyPNext = pnxt',
		C.copySrcSet = ss,
		C.copySrcBinding = sb,
		C.copySrcArrayElement = sae,
		C.copyDstSet = ds,
		C.copyDstBinding = db,
		C.copyDstArrayElement = dae,
		C.copyDescriptorCount = dc }

data Write mn = Write {
	writeNext :: TMaybe.M mn,
	writeDstSet :: D,
	writeDstBinding :: Word32,
	writeDstArrayElement :: Word32,
	writeDescriptorType :: Descriptor.Type,
	writeSources :: WriteSources }

deriving instance Show (TMaybe.M mn) => Show (Write mn)

data WriteSources
	= WriteSourcesInNext Word32
	| WriteSourcesImageInfo [Descriptor.ImageInfo]
	| WriteSourcesBufferInfo [Descriptor.BufferInfo]
	| WriteSourcesBufferView [BufferView.B]
	deriving Show

class WriteListToCore ws where
	writeListToCore ::
		HeteroParList.PL Write ws -> ([C.Write] -> IO a) -> IO ()

instance WriteListToCore '[] where
	writeListToCore HeteroParList.Nil f = () <$ f []

instance (WithPoked (TMaybe.M w), WriteListToCore ws) => WriteListToCore (w ': ws) where
	writeListToCore (w :** ws) f =
		writeToCore w \cw -> writeListToCore ws \cws -> f $ cw : cws

writeToCore :: WithPoked (TMaybe.M mn) => Write mn -> (C.Write -> IO a) -> IO ()
writeToCore Write {
	writeNext = mnxt,
	writeDstSet = D s,
	writeDstBinding = bdg,
	writeDstArrayElement = ae,
	writeDescriptorType = Descriptor.Type tp,
	writeSources = srcs } f =
	withPoked' mnxt \pnxt -> withPtrS pnxt \(castPtr -> pnxt') ->
	writeSourcesToCore srcs \(cnt, pii, pbi, ptbv) ->
	f C.Write {
		C.writeSType = (),
		C.writePNext = pnxt',
		C.writeDstSet = s,
		C.writeDstBinding = bdg,
		C.writeDstArrayElement = ae,
		C.writeDescriptorCount = cnt,
		C.writeDescriptorType = tp,
		C.writePImageInfo = pii,
		C.writePBufferInfo = pbi,
		C.writePTexelBufferView = ptbv }

writeSourcesToCore :: WriteSources -> ((
	Word32, Ptr Descriptor.C.ImageInfo,
	Ptr Descriptor.C.BufferInfo, Ptr BufferView.C.B ) -> IO a) -> IO a
writeSourcesToCore ws f = case ws of
	WriteSourcesInNext c -> f (c, NullPtr, NullPtr, NullPtr)
	WriteSourcesImageInfo (length &&& id -> (ln, iis)) ->
		allocaArray ln \piis ->
		Descriptor.imageInfoToCore `mapM` iis >>= \iis' ->
		pokeArray piis iis' >>
		f (fromIntegral ln, piis, NullPtr, NullPtr)
	WriteSourcesBufferInfo
		(length &&& (Descriptor.bufferInfoToCore <$>) -> (ln, bis)) ->
		allocaArray ln \pbis ->
		pokeArray pbis bis >>
		f (fromIntegral ln, NullPtr, pbis, NullPtr)
	WriteSourcesBufferView
		(length &&& ((\(BufferView.B b) -> b) <$>) -> (ln, bvs)) ->
		allocaArray ln \pbvs ->
		pokeArray pbvs bvs >>
		f (fromIntegral ln, NullPtr, NullPtr, pbvs)

updateDs :: (WriteListToCore ws, CopyListToCore cs) =>
	Device.D ->
	HeteroParList.PL Write ws -> HeteroParList.PL Copy cs ->
	IO ()
updateDs (Device.D dvc) ws cs =
	writeListToCore ws \cws ->
	allocaAndPokeArray cws \(fromIntegral -> wc, pws) ->
	copyListToCore cs \ccs ->
	allocaAndPokeArray ccs \(fromIntegral -> cc, pcs) ->
	C.updateDs dvc wc pws cc pcs

allocaAndPokeArray :: Storable a => [a] -> ((Int, Ptr a) -> IO b) -> IO b
allocaAndPokeArray (length &&& id -> (xc, xs)) f
	= allocaArray xc \p -> pokeArray p xs >> f (xc, p)