packages feed

gpu-vulkan-0.1.0.137: src/Gpu/Vulkan/Cmd.hs

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

module Gpu.Vulkan.Cmd (

-- * BEGIN RENDER PASS

beginRenderPass,

-- * DRAW AND DISPATCH

-- ** Draw

bindPipelineGraphics,
bindVertexBuffers, bindIndexBuffer, IsIndex,
draw, drawIndexed,
VertexCount, IndexCount, InstanceCount,
FirstVertex, FirstIndex, FirstInstance,
VertexOffset,

-- ** Dispatch

bindPipelineCompute, dispatch, GroupCountX, GroupCountY, GroupCountZ,

-- * PUSH CONSTANTS AND BIND DESCRIPTOR SETS

pushConstantsGraphics, pushConstantsCompute,
bindDescriptorSetsGraphics, bindDescriptorSetsCompute,
DynamicIndex(..), GetDynamicLength,

-- * COPY BUFFER AND IMAGES

copyBuffer, copyBufferToImage, copyImageToBuffer, blitImage,

-- * MEMORY DEPENDENCY

pipelineBarrier,

-- * QUERY

resetQueryPool,
beginQuery,
writeTimestamp,

-- * OTHERS

LayoutArgListOnlyDynamics

) where

import GHC.TypeNats
import Foreign.Storable.PeekPoke
import Foreign.Storable.HeteroList
import Control.Exception
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.TypeLevel.List
import Data.TypeLevel.Tuple.Uncurry
import Data.TypeLevel.Tuple.Index qualified as TIndex
import Data.TypeLevel.Tuple.MapIndex qualified as TMapIndex
import qualified Data.HeteroParList as HeteroParList
import Data.HeteroParList (pattern (:**))
import Data.Word
import Data.Int

import Gpu.Vulkan
import Gpu.Vulkan.TypeEnum qualified as T

import qualified Gpu.Vulkan.CommandBuffer as CommandBuffer
import qualified Gpu.Vulkan.CommandBuffer.Type as CommandBuffer.T
import qualified Gpu.Vulkan.Pipeline.Graphics.Type as Pipeline
import qualified Gpu.Vulkan.Pipeline.Compute as Pipeline.Compute
import qualified Gpu.Vulkan.Pipeline.Enum as Pipeline
import qualified Gpu.Vulkan.PipelineLayout.Type as PipelineLayout
import qualified Gpu.Vulkan.DescriptorSet as DescriptorSet
import qualified Gpu.Vulkan.DescriptorSet.Type as DescriptorSet
import qualified Gpu.Vulkan.DescriptorSetLayout.Type as Layout
import qualified Gpu.Vulkan.Buffer.Type as Bffr
import qualified Gpu.Vulkan.Buffer as Bffr
import qualified Gpu.Vulkan.Buffer.Internal as Bffr.I
import qualified Gpu.Vulkan.Image as Image
import qualified Gpu.Vulkan.Image.Internal as Image.I
import qualified Gpu.Vulkan.Image.Type as Image
import qualified Gpu.Vulkan.Image.Middle as Image.M

import qualified Gpu.Vulkan.RenderPass.Internal as RenderPass
import qualified Gpu.Vulkan.Subpass.Enum as Subpass
import qualified Gpu.Vulkan.Cmd.Middle as M

import qualified Gpu.Vulkan.Memory as Memory

import Data.IORef -- for debug

import Gpu.Vulkan.Query.Enum qualified as Query
import Gpu.Vulkan.QueryPool qualified as QueryPool
import Gpu.Vulkan.QueryPool.Type qualified as QueryPool
import Gpu.Vulkan.Query qualified as Query
import Gpu.Vulkan.Object.Base qualified as KObj

beginRenderPass :: (WithPoked (TMaybe.M mn), ClearValueListToCore cts) =>
	CommandBuffer.C scb -> RenderPass.BeginInfo mn sr sf cts ->
	Subpass.Contents -> IO a -> IO a
beginRenderPass (CommandBuffer.T.C cb) bi cnt f = bracket_
	(M.beginRenderPass cb (RenderPass.beginInfoToMiddle bi) cnt)
	(M.endRenderPass cb) f

bindPipelineGraphics :: CommandBuffer.C scb ->
	Pipeline.BindPoint -> Pipeline.G sg vibs vias slbtss ->
	(forall sgb . CommandBuffer.GBinded sgb vibs slbtss -> IO a) -> IO a
bindPipelineGraphics (CommandBuffer.T.C c) bp (Pipeline.G g) f =
	M.bindPipelineGraphics c bp g >> f (CommandBuffer.T.GBinded c)

bindPipelineCompute :: CommandBuffer.C scmdb -> Pipeline.BindPoint ->
	Pipeline.Compute.C scp slbtss ->
	(forall scbnd . CommandBuffer.CBinded scbnd slbtss -> IO a) -> IO a
bindPipelineCompute (CommandBuffer.T.C cb) bp (Pipeline.Compute.C g) f =
	M.bindPipelineCompute cb bp g >> f (CommandBuffer.T.CBinded cb)

draw :: CommandBuffer.GBinded sc vibs slbtss ->
	VertexCount -> InstanceCount -> FirstVertex -> FirstInstance -> IO ()
draw (CommandBuffer.T.GBinded cb) vc ic fv fi = M.draw cb vc ic fv fi

type VertexCount = Word32
type InstanceCount = Word32
type FirstVertex = Word32
type FirstInstance = Word32

drawIndexed :: CommandBuffer.GBinded sc vibs slbtss ->
	IndexCount -> InstanceCount ->
	FirstIndex -> VertexOffset -> FirstInstance -> IO ()
drawIndexed (CommandBuffer.T.GBinded cb) idxc istc fidx vo fist =
	M.drawIndexed cb idxc istc fidx vo fist

type IndexCount = Word32
type FirstIndex = Word32
type VertexOffset = Int32

dispatch :: CommandBuffer.CBinded sc slbtss ->
	GroupCountX -> GroupCountY -> GroupCountZ -> IO ()
dispatch (CommandBuffer.T.CBinded cb) = M.dispatch cb

type GroupCountX = Word32
type GroupCountY = Word32
type GroupCountZ = Word32

bindDescriptorSetsGraphics :: forall sgbnd vibs sl dsls pcs dss dsls' dyns . (
	TMapIndex.M1_2 dss ~ dsls',
	LayoutArgListOnlyDynamics dsls' ~ dyns,
	InfixIndex dsls' dsls, GetDynamicLength dss,
	HeteroParList.ZipListWithC3 KObj.SizeAlignment dyns ) =>
	CommandBuffer.GBinded sgbnd vibs '(sl, dsls, pcs) ->
	Pipeline.BindPoint -> PipelineLayout.P sl dsls pcs ->
	HeteroParList.PL (U2 DescriptorSet.D) dss ->
	HeteroParList.PL3 DynamicIndex dyns -> IO ()
bindDescriptorSetsGraphics
	(CommandBuffer.T.GBinded c) bp (PipelineLayout.P l) dss idxs = do
	lns <- getDynamicLength dss
	let	dosts = concat $ concat <$> getOffsetListNew lns idxs
	M.bindDescriptorSets c bp l
		(fromIntegral $ infixIndex @_ @dsls' @dsls)
		(HeteroParList.toList
			(\(U2 (DescriptorSet.D _ s)) -> s)
			dss)
		dosts

bindDescriptorSetsCompute :: forall scbnd sl dsls pcs dss dsls' dyns . (
	TMapIndex.M1_2 dss ~ dsls',
	LayoutArgListOnlyDynamics dsls' ~ dyns,
	InfixIndex dsls' dsls, GetDynamicLength dss,
	HeteroParList.ZipListWithC3 KObj.SizeAlignment dyns ) =>
	CommandBuffer.CBinded scbnd '(sl, dsls, pcs) ->
	PipelineLayout.P sl dsls pcs ->
	HeteroParList.PL (U2 DescriptorSet.D) dss ->
	HeteroParList.PL3 DynamicIndex dyns -> IO ()
bindDescriptorSetsCompute
	(CommandBuffer.T.CBinded c) (PipelineLayout.P l) dss idxs = do
	lns <- getDynamicLength dss
	let	dosts = concat $ concat <$> getOffsetListNew lns idxs
	M.bindDescriptorSets c Pipeline.BindPointCompute l
		(fromIntegral $ infixIndex @_ @dsls' @dsls)
		(HeteroParList.toList (\(U2 (DescriptorSet.D _ s)) -> s)
			dss)
		dosts

newtype DynamicIndex (obj :: KObj.O) = DynamicIndex Word32 deriving Show
newtype DynamicOffset (obj :: KObj.O) = DynamicOffset Word32 deriving Show

getOffset' :: forall obj . KObj.SizeAlignment obj =>
	KObj.Length obj -> DynamicIndex obj -> Word32
getOffset' ln (DynamicIndex i) = fromIntegral sz * i
	where
	sz = ((KObj.size ln - 1) `div` algn + 1) * algn
	algn = KObj.alignment @obj

getOffsetListNew :: HeteroParList.ZipListWithC3 KObj.SizeAlignment osss =>
		HeteroParList.PL3 KObj.Length osss ->
		HeteroParList.PL3 DynamicIndex osss -> [[[Word32]]]
getOffsetListNew = HeteroParList.zipListWithC3 @KObj.SizeAlignment getOffset'

class GetDynamicLength sspslbtss where
	getDynamicLength ::
		HeteroParList.PL (U2 DescriptorSet.D) sspslbtss ->
		IO (HeteroParList.PL3 KObj.Length
			(LayoutArgListOnlyDynamics (TMapIndex.M1_2 sspslbtss)))

type family LayoutArgListOnlyDynamics las where
	LayoutArgListOnlyDynamics '[] = '[]
	LayoutArgListOnlyDynamics (la ': las) =
		Layout.BindingTypeListBufferOnlyDynamics (TIndex.I1_2 la) ':
			LayoutArgListOnlyDynamics las

instance GetDynamicLength '[] where
	getDynamicLength HeteroParList.Nil = pure HeteroParList.Nil

instance GetDynamicLength spslbtss =>
	GetDynamicLength (slbts ': spslbtss) where
	getDynamicLength (U2 ds :** dss) =
		(:**) <$> getDscSetLengthsNew ds <*> getDynamicLength dss

getDscSetLengthsNew :: DescriptorSet.D s slbts ->
	IO (HeteroParList.PL2 KObj.Length
		(Layout.BindingTypeListBufferOnlyDynamics (TIndex.I1_2 slbts)))
getDscSetLengthsNew (DescriptorSet.D lns _) = readIORef lns

bindVertexBuffers :: forall sg vibs slbtss smsbnmts .
	InfixIndex (TMapIndex.M3_5 smsbnmts) (TMapIndex.M0_2 vibs) =>
	CommandBuffer.GBinded sg vibs slbtss ->
	HeteroParList.PL (U5 Bffr.IndexedForList) smsbnmts -> IO ()
bindVertexBuffers (CommandBuffer.T.GBinded cb) bils = M.bindVertexBuffers
	cb (fromIntegral fb) (Bffr.I.indexedListToMiddles bils)
	where fb = infixIndex @_ @(TMapIndex.M3_5 smsbnmts) @(TMapIndex.M0_2 vibs)

bindIndexBuffer :: forall sg vibs slbtss sm sb nm i onm . IsIndex i =>
	CommandBuffer.GBinded sg vibs slbtss ->
	Bffr.IndexedForList sm sb nm i onm -> IO ()
bindIndexBuffer (CommandBuffer.T.GBinded cb) ib =
	uncurry (M.bindIndexBuffer cb) (Bffr.I.indexedListToMiddle ib) (indexType @i)

class IsIndex a where indexType :: IndexType
instance IsIndex Word16 where indexType = IndexTypeUint16
instance IsIndex Word32 where indexType = IndexTypeUint32

copyBuffer :: forall cpobjss scb sms sbs nms objss smd sbd nmd objsd .
	Bffr.MakeCopies cpobjss objss objsd => CommandBuffer.C scb ->
	Bffr.Binded sms sbs nms objss -> Bffr.Binded smd sbd nmd objsd -> IO ()
copyBuffer (CommandBuffer.T.C cb) (Bffr.Binded lnss s) (Bffr.Binded lnsd d) =
	M.copyBuffer cb s d (Bffr.I.makeCopies @cpobjss lnss lnsd)

pushConstantsGraphics :: forall sss sc vibs sl sbtss pcs ts . (
	T.ShaderStageFlagBitsListToValue sss,
	PokableList ts, InfixOffsetSize ts pcs ) =>
	CommandBuffer.GBinded sc vibs '(sl, sbtss, pcs) ->
	PipelineLayout.P sl sbtss pcs -> HeteroParList.L ts -> IO ()
pushConstantsGraphics (CommandBuffer.T.GBinded cb) (PipelineLayout.P lyt) xs =
	M.pushConstants
		cb lyt (T.shaderStageFlagBitsListToValue @sss) offt xs
		where (fromIntegral -> offt, _) = infixOffsetSize @ts @pcs

pushConstantsCompute :: forall sss sc sl sbtss pcs ts . (
	T.ShaderStageFlagBitsListToValue sss,
	PokableList ts, InfixOffsetSize ts pcs ) =>
	CommandBuffer.CBinded sc '(sl, sbtss, pcs) ->
	PipelineLayout.P sl sbtss pcs -> HeteroParList.L ts -> IO ()
pushConstantsCompute (CommandBuffer.T.CBinded cb) (PipelineLayout.P lyt) xs =
	M.pushConstants
		cb lyt (T.shaderStageFlagBitsListToValue @sss) offt xs
		where (fromIntegral -> offt, _) = infixOffsetSize @ts @pcs

pipelineBarrier :: (
	HeteroParList.ToListWithCCpsM' WithPoked TMaybe.M mbargs,
	HeteroParList.ToListWithCCpsM' WithPoked TMaybe.M
		(TMapIndex.M0_5 bmbargss),
	HeteroParList.ToListWithCCpsM' WithPoked TMaybe.M
		(TMapIndex.M0_5 imbargss),
	Bffr.MemoryBarrierListToMiddle bmbargss,
	Image.MemoryBarrierListToMiddle imbargss ) =>
	CommandBuffer.C scb -> Pipeline.StageFlags -> Pipeline.StageFlags ->
	DependencyFlags -> HeteroParList.PL Memory.Barrier mbargs ->
	HeteroParList.PL (U5 Bffr.MemoryBarrier) bmbargss ->
	HeteroParList.PL (U5 Image.MemoryBarrier) imbargss -> IO ()
pipelineBarrier (CommandBuffer.T.C cb) ssm dsm dfs mbs bmbs imbs =
	M.pipelineBarrier cb ssm dsm dfs mbs
		(Bffr.I.memoryBarrierListToMiddle bmbs)
		(Image.I.memoryBarrierListToMiddle imbs)

copyBufferToImage ::
	forall (algn :: Nat) img inms scb smb sbb bnm objs smi si inm .
	(Bffr.ImageCopyListToMiddle algn objs img inms) =>
	CommandBuffer.C scb -> Bffr.Binded smb sbb bnm objs ->
	Image.Binded smi si inm (KObj.ImageFormat img) -> Image.Layout ->
	HeteroParList.PL (Bffr.ImageCopy img) inms -> IO ()
copyBufferToImage (CommandBuffer.T.C cb)
	bf@(Bffr.Binded _ mbf) (Image.Binded mim) imlyt ics =
	M.copyBufferToImage cb mbf mim imlyt mics
	where mics = Bffr.I.imageCopyListToMiddle @algn bf ics

copyImageToBuffer ::
	forall (algn :: Nat) img inms scb smi si inm smb sbb bnm objs .
	(Bffr.ImageCopyListToMiddle algn objs img inms) =>
	CommandBuffer.C scb  ->
	Image.Binded smi si inm (KObj.ImageFormat img) -> Image.Layout ->
	Bffr.Binded smb sbb bnm objs ->
	HeteroParList.PL (Bffr.ImageCopy img) inms -> IO ()
copyImageToBuffer (CommandBuffer.T.C cb)
	(Image.Binded mim) imlyt bf@(Bffr.Binded _ mbf) ics =
	M.copyImageToBuffer cb mim imlyt mbf mics
	where mics = Bffr.I.imageCopyListToMiddle @algn bf ics

blitImage :: CommandBuffer.C scb ->
	Image.Binded sms sis nms fmts -> Image.Layout ->
	Image.Binded smd sid nmd fmtd -> Image.Layout ->
	[Image.M.Blit] -> Filter -> IO ()
blitImage (CommandBuffer.T.C cb)
	(Image.Binded src) slyt (Image.Binded dst) dlyt blts fltr =
	M.blitImage cb src slyt dst dlyt blts fltr

resetQueryPool :: CommandBuffer.C sc ->
	QueryPool.Q sq tp -> Query.First -> Query.Count -> IO ()
resetQueryPool (CommandBuffer.T.C cb) (QueryPool.Q qp) fq qc =
	M.resetQueryPool cb qp fq qc

beginQuery :: CommandBuffer.C sc ->
	QueryPool.Q sq tp -> Query.Q -> Query.ControlFlags -> IO a -> IO ()
beginQuery (CommandBuffer.T.C cb) (QueryPool.Q qp) i flgs act =
	M.beginQuery cb qp i flgs >> act >> M.endQuery cb qp i

writeTimestamp :: CommandBuffer.C sc -> Pipeline.StageFlagBits ->
	QueryPool.Q sq QueryPool.Timestamp -> Query.Q -> IO ()
writeTimestamp (CommandBuffer.T.C cb) sflgs (QueryPool.Q qp) i =
	M.writeTimestamp cb sflgs qp i