packages feed

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

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
{-# LANGUAGE GADTs, TypeFamilies #-}
{-# LANGUAGE DataKinds, PolyKinds #-}
{-# LANGUAGE KindSignatures, TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.Pipeline.Graphics.Middle.Internal (
	CreateInfo(..), CreateInfoListToCore,
	createGs, recreateGs,

	destroyGs,

	G, gNull, gToCore,
	) where

import Prelude hiding (length)
import Prelude qualified as P

import Foreign.Ptr
import Foreign.Marshal.Array
import Foreign.Storable.PeekPoke
import Control.Monad
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.TypeLevel.ParMaybe qualified as TPMaybe
import Data.TypeLevel.Tuple.Uncurry
import Data.TypeLevel.List
import Data.IORef
import qualified Data.HeteroParList as HeteroParList
import Data.HeteroParList (pattern (:**))
import Data.Word
import Data.Int

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

import qualified Gpu.Vulkan.Pipeline.Core as Pipeline.C
import qualified Gpu.Vulkan.Pipeline.ShaderStage.Middle.Internal as ShaderStage
import qualified Gpu.Vulkan.Pipeline.VertexInputState.Middle.Internal as VertexInputState.M
import Gpu.Vulkan.Pipeline.InputAssemblyState.Middle.Internal
	qualified as InputAssemblyState
import Gpu.Vulkan.Pipeline.TessellationState.Middle.Internal
	qualified as TessellationState
import qualified Gpu.Vulkan.Pipeline.ViewportState.Middle.Internal as ViewportState
import qualified Gpu.Vulkan.Pipeline.RasterizationState.Middle.Internal as RasterizationState
import qualified Gpu.Vulkan.Pipeline.MultisampleState.Middle.Internal as MultisampleState
import qualified Gpu.Vulkan.Pipeline.DepthStencilState.Middle.Internal
	as DepthStencilState
import qualified Gpu.Vulkan.Pipeline.ColorBlendState.Middle.Internal
	as ColorBlendState
import qualified Gpu.Vulkan.Pipeline.DynamicState.Middle.Internal
	as DynamicState
import qualified Gpu.Vulkan.PipelineLayout.Middle.Internal as Layout
import qualified Gpu.Vulkan.RenderPass.Middle.Internal as RenderPass
import qualified Gpu.Vulkan.Pipeline.Graphics.Core as C

import Gpu.Vulkan.AllocationCallbacks.Middle.Internal
	qualified as AllocationCallbacks
import qualified Gpu.Vulkan.Device.Middle.Internal as Device
import qualified Gpu.Vulkan.PipelineCache.Middle.Internal as Cache

data CreateInfo mn stg vis ias ts vs rs ms dss cbs ds = CreateInfo {
	createInfoNext :: TMaybe.M mn,
	createInfoFlags :: CreateFlags,
	createInfoStages :: HeteroParList.PL (U3 ShaderStage.CreateInfo) stg,
	createInfoVertexInputState :: Maybe (VertexInputState.M.CreateInfo vis),
	createInfoInputAssemblyState ::
		Maybe (InputAssemblyState.CreateInfo ias),
	createInfoTessellationState :: Maybe (TessellationState.CreateInfo ts),
	createInfoViewportState :: Maybe (ViewportState.CreateInfo vs),
	createInfoRasterizationState ::
		Maybe (RasterizationState.CreateInfo rs),
	createInfoMultisampleState :: Maybe (MultisampleState.CreateInfo ms),
	createInfoDepthStencilState :: Maybe (DepthStencilState.CreateInfo dss),
	createInfoColorBlendState :: Maybe (ColorBlendState.CreateInfo cbs),
	createInfoDynamicState :: Maybe (DynamicState.CreateInfo ds),
	createInfoLayout :: Layout.P,
	createInfoRenderPass :: RenderPass.R,
	createInfoSubpass :: Word32,
	createInfoBasePipelineHandle :: G,
	createInfoBasePipelineIndex :: Int32 }

createInfoToCore :: (
	WithPoked (TMaybe.M mn),
	ShaderStage.CreateInfoListToCore stg,
	WithPoked (TMaybe.M n2), WithPoked (TMaybe.M n3),
	WithPoked (TMaybe.M n4), WithPoked (TMaybe.M n5),
	WithPoked (TMaybe.M n6), WithPoked (TMaybe.M n7),
	WithPoked (TMaybe.M n8), WithPoked (TMaybe.M n9),
	WithPoked (TMaybe.M n10) ) =>
	CreateInfo mn stg n2 n3 n4 n5 n6 n7 n8 n9 n10 ->
	(C.CreateInfo -> IO a) -> IO ()
createInfoToCore CreateInfo {
	createInfoNext = mnxt,
	createInfoFlags = CreateFlagBits flgs,
	createInfoStages = ss,
	createInfoVertexInputState = mvist,
	createInfoInputAssemblyState = miast,
	createInfoTessellationState = mtst,
	createInfoViewportState = mvst,
	createInfoRasterizationState = mrst,
	createInfoMultisampleState = mmst,
	createInfoDepthStencilState = mdsst,
	createInfoColorBlendState = mcbst,
	createInfoDynamicState = mdst,
	createInfoLayout = Layout.P lyt,
	createInfoRenderPass = RenderPass.R rp,
	createInfoSubpass = sp,
	createInfoBasePipelineHandle = bph,
	createInfoBasePipelineIndex = bpi } f =
	withPoked' mnxt \pnxt -> withPtrS pnxt \(castPtr -> pnxt') ->
	ShaderStage.createInfoListToCore ss \css ->
	let sc = P.length css in
	allocaArray sc \pss ->
	pokeArray pss css >>
	maybeToCore VertexInputState.M.createInfoToCore mvist \pvist ->
	maybeToCore InputAssemblyState.createInfoToCore miast \piast ->
	maybeToCore TessellationState.createInfoToCore mtst \ptst ->
	maybeToCore ViewportState.createInfoToCore mvst \pvst ->
	maybeToCore RasterizationState.createInfoToCore mrst \prst ->
	maybeToCore MultisampleState.createInfoToCore mmst \pmst ->
	maybeToCore DepthStencilState.createInfoToCore mdsst \pdsst ->
	maybeToCore ColorBlendState.createInfoToCore mcbst \pcbst ->
	maybeToCore' DynamicState.createInfoToCore mdst \pdst ->
	gToCore bph >>= \bph' ->
	f C.CreateInfo {
		C.createInfoSType = (),
		C.createInfoPNext = pnxt',
		C.createInfoFlags = flgs,
		C.createInfoStageCount = fromIntegral sc,
		C.createInfoPStages = pss,
		C.createInfoPVertexInputState = pvist,
		C.createInfoPInputAssemblyState = piast,
		C.createInfoPTessellationState = ptst,
		C.createInfoPViewportState = pvst,
		C.createInfoPRasterizationState = prst,
		C.createInfoPMultisampleState = pmst,
		C.createInfoPDepthStencilState = pdsst,
		C.createInfoPColorBlendState = pcbst,
		C.createInfoPDynamicState = pdst,
		C.createInfoLayout = lyt,
		C.createInfoRenderPass = rp,
		C.createInfoSubpass = sp,
		C.createInfoBasePipelineHandle = bph',
		C.createInfoBasePipelineIndex = bpi }

maybeToCore :: (a -> (Ptr b -> IO r) -> IO r) -> Maybe a -> (Ptr b -> IO r) -> IO r
maybeToCore f mx g = case mx of Nothing -> g NullPtr; Just x -> f x g

maybeToCore' :: (a -> (Ptr b -> IO r) -> IO ()) -> Maybe a -> (Ptr b -> IO r) -> IO ()
maybeToCore' f mx g = case mx of Nothing -> () <$ g NullPtr; Just x -> f x g

class Length cias => CreateInfoListToCore cias where
	createInfoListToCore ::
		HeteroParList.PL (U11 CreateInfo) cias ->
		([C.CreateInfo] -> IO r) -> IO ()

instance CreateInfoListToCore '[] where createInfoListToCore HeteroParList.Nil f = () <$ f []

instance (
	WithPoked (TMaybe.M mn), ShaderStage.CreateInfoListToCore stg,
	WithPoked (TMaybe.M vis), WithPoked (TMaybe.M ias),
	WithPoked (TMaybe.M ts), WithPoked (TMaybe.M vs),
	WithPoked (TMaybe.M rs), WithPoked (TMaybe.M ms),
	WithPoked (TMaybe.M dss), WithPoked (TMaybe.M cbs),
	WithPoked (TMaybe.M ds), CreateInfoListToCore cias ) =>
	CreateInfoListToCore ('(
		mn, stg, vis, ias, ts, vs, rs, ms, dss, cbs, ds ) ': cias) where
	createInfoListToCore (U11 ci :** cis) f =
		createInfoToCore ci \cci ->
		createInfoListToCore cis \ccis -> f $ cci : ccis

gNull :: IO G
gNull = G <$> newIORef NullHandle

newtype G = G (IORef Pipeline.C.P)

gToCore :: G -> IO Pipeline.C.P
gToCore (G rp) = readIORef rp

gFromCore :: Pipeline.C.P -> IO G
gFromCore p = G <$> newIORef p

gListFromCore :: [Pipeline.C.P] -> IO [G]
gListFromCore [] = pure []
gListFromCore (cp : cps) = (:) <$> gFromCore cp <*> gListFromCore cps

gListToIORefs :: [G] -> [IORef Pipeline.C.P]
gListToIORefs [] = []
gListToIORefs (G cp : cps) = cp : gListToIORefs cps

gListToCore :: [G] -> IO [Pipeline.C.P]
gListToCore cps = readIORef `mapM` gListToIORefs cps

createGs :: CreateInfoListToCore cias =>
	Device.D -> Maybe Cache.P -> HeteroParList.PL (U11 CreateInfo) cias ->
	TPMaybe.M AllocationCallbacks.A mc -> IO [G]
createGs dvc mc cis mac = gListFromCore =<< createRaw dvc mc cis mac

recreateGs :: CreateInfoListToCore cias =>
	Device.D -> Maybe Cache.P ->
	HeteroParList.PL (U11 CreateInfo) cias ->
	TPMaybe.M AllocationCallbacks.A mc ->
	[G] -> IO ()
recreateGs dvc mc cis macc gs =
	recreateRaw dvc mc cis macc $ gListToIORefs gs

createRaw :: forall ss mn' . CreateInfoListToCore ss =>
	Device.D -> Maybe Cache.P ->
	HeteroParList.PL (U11 CreateInfo) ss ->
	TPMaybe.M AllocationCallbacks.A mn' -> IO [Pipeline.C.P]
createRaw (Device.D dvc) mc cis mac = let
	cc = case mc of Nothing -> NullPtr; Just (Cache.P c) -> c
	cic = length @_ @ss in
	allocaArray cic \pps -> do
		createInfoListToCore cis \ccis -> allocaArray cic \pcis ->
			pokeArray pcis ccis >>
			AllocationCallbacks.mToCore mac \pac -> do
				r <- C.create dvc cc (fromIntegral cic) pcis pac pps
				throwUnlessSuccess $ Result r
		peekArray cic pps

recreateRaw :: CreateInfoListToCore ss =>
	Device.D -> Maybe Cache.P ->
	HeteroParList.PL (U11 CreateInfo) ss ->
	TPMaybe.M AllocationCallbacks.A mc ->
	[IORef Pipeline.C.P] -> IO ()
recreateRaw dvc mc cis macc rs = do
	os <- readIORef `mapM` rs
	ns <- createRaw dvc mc cis macc
	zipWithM_ writeIORef rs ns
	(\o -> destroyRaw dvc o macc) `mapM_` os

destroyGs :: Device.D -> [G] -> TPMaybe.M AllocationCallbacks.A md -> IO ()
destroyGs dvc gs mac = ((\g -> gFromCore g >>= \g' -> destroy dvc g' mac) `mapM_`) =<< gListToCore gs

destroy :: Device.D -> G -> TPMaybe.M AllocationCallbacks.A mn -> IO ()
destroy (Device.D dvc) g mac = gToCore g >>= \p ->
	AllocationCallbacks.mToCore mac $ Pipeline.C.destroy dvc p

destroyRaw ::
	Device.D -> Pipeline.C.P -> TPMaybe.M AllocationCallbacks.A md -> IO ()
destroyRaw (Device.D dvc) p macd =
	AllocationCallbacks.mToCore macd $ Pipeline.C.destroy dvc p