packages feed

gpu-vulkan-middle-0.1.0.60: src/Gpu/Vulkan/Device/Middle/Internal.hsc

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE RankNTypes, TypeApplications #-}
{-# LANGUAGE GADTs, TypeFamilies #-}
{-# LANGUAGE DataKinds, PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.Device.Middle.Internal (

	-- * CREATE AND DESTROY

	create, destroy, D(..), CreateInfo(..), CreateFlags, CreateFlagBits,
	QueueCreateInfo(..),

	-- * GET QUEUE AND WAIT IDLE

	getQueue, waitIdle,

	-- * SIZE

	Size(..)

	) where

import Foreign.Ptr
import Foreign.Marshal
import Foreign.Storable
import Foreign.Storable.PeekPoke (
	WithPoked, withPoked', withPtrS, pattern NullPtr )
import Foreign.Storable.HeteroList
import Foreign.C.Enum
import Control.Arrow
import Control.Monad.Cont
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.TypeLevel.ParMaybe qualified as TPMaybe
import Data.Default
import Data.Bits
import Data.List (genericLength)
import Data.HeteroParList qualified as HeteroParList
import Data.Word
import Data.Ix

import Data.Text qualified as T
import Data.Text.Foreign.MiscYj

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

import Gpu.Vulkan.AllocationCallbacks.Middle.Internal
	qualified as AllocationCallbacks
import qualified Gpu.Vulkan.PhysicalDevice.Middle.Internal as PhysicalDevice
import qualified Gpu.Vulkan.PhysicalDevice.Struct as PhysicalDevice
import qualified Gpu.Vulkan.Device.Core as C
import {-# SOURCE #-} qualified Gpu.Vulkan.Queue.Middle.Internal as Queue

import qualified Gpu.Vulkan.QueueFamily.EnumManual as QueueFamily

import Gpu.Vulkan.Device.Middle.Types

#include <vulkan/vulkan.h>

enum "CreateFlagBits" ''#{type VkDeviceCreateFlags}
	[''Eq, ''Show, ''Storable, ''Bits] [("CreateFlagsZero", 0)]

type CreateFlags = CreateFlagBits

instance Default CreateFlags where def = CreateFlagsZero

data CreateInfo mn qcis = CreateInfo {
	createInfoNext :: TMaybe.M mn,
	createInfoFlags :: CreateFlags,
	createInfoQueueCreateInfos :: HeteroParList.PL QueueCreateInfo qcis,
	createInfoEnabledLayerNames :: [T.Text],
	createInfoEnabledExtensionNames :: [T.Text],
	createInfoEnabledFeatures :: Maybe PhysicalDevice.Features }

deriving instance (Show (TMaybe.M mn), Show (HeteroParList.PL QueueCreateInfo qcis)) =>
	Show (CreateInfo mn qcis)

type family Map (f :: j -> k) xs where
	Map _f '[] = '[]
	Map f (x ': xs) = f x ': Map f xs

createInfoToCore :: (
	WithPoked (TMaybe.M mn), HeteroParList.ToListWithCM' WithPoked TMaybe.M qcis) =>
	CreateInfo mn qcis -> (Ptr C.CreateInfo -> IO a) -> IO ()
createInfoToCore CreateInfo {
	createInfoNext = mnxt,
	createInfoFlags = CreateFlagBits flgs,
	createInfoQueueCreateInfos = qcis,
	createInfoEnabledLayerNames = (id &&& length) -> (elns, elnc),
	createInfoEnabledExtensionNames = (id &&& length) -> (eens, eenc),
	createInfoEnabledFeatures = mef } f =
	withPoked' mnxt \pnxt -> withPtrS pnxt \(castPtr -> pnxt') ->
	alloca \pci ->
		runContT (HeteroParList.toListWithCM' @_ @_ @WithPoked @TMaybe.M (ContT . queueCreateInfoToCore) qcis) \cqcis ->
		let	qcic = length cqcis in
		allocaArray qcic \pcqcis ->
		pokeArray pcqcis cqcis >>
		textListToCStringArray elns \pcelns ->
		textListToCStringArray eens \pceens -> do
		let mk pef = C.CreateInfo {
			C.createInfoSType = (),
			C.createInfoPNext = pnxt',
			C.createInfoFlags = flgs,
			C.createInfoQueueCreateInfoCount = fromIntegral qcic,
			C.createInfoPQueueCreateInfos = pcqcis,
			C.createInfoEnabledLayerCount = fromIntegral elnc,
			C.createInfoPpEnabledLayerNames = pcelns,
			C.createInfoEnabledExtensionCount = fromIntegral eenc,
			C.createInfoPpEnabledExtensionNames = pceens,
			C.createInfoPEnabledFeatures = pef }
		case mef of
			Nothing -> poke pci (mk NullPtr)
			Just ef -> alloca \p -> do
				poke p $ PhysicalDevice.featuresToCore ef
				poke pci (mk p)
		() <$ f pci

create :: (WithPoked (TMaybe.M mn), HeteroParList.ToListWithCM' WithPoked TMaybe.M qcis) =>
	PhysicalDevice.P -> CreateInfo mn qcis -> TPMaybe.M AllocationCallbacks.A mc ->
	IO D
create (PhysicalDevice.P phdvc) ci mac = D <$> alloca \pdvc -> do
	createInfoToCore ci \pcci ->
		AllocationCallbacks.mToCore mac \pac -> do
			r <- C.create phdvc pcci pac pdvc
			throwUnlessSuccess $ Result r
	peek pdvc

destroy :: D -> TPMaybe.M AllocationCallbacks.A md -> IO ()
destroy (D cdvc) mac = AllocationCallbacks.mToCore mac $ C.destroy cdvc

getQueue :: D -> Word32 -> Word32 -> IO Queue.Q
getQueue (D cdvc) qfi qi = Queue.Q <$> alloca \pQueue -> do
	C.getQueue cdvc qfi qi pQueue
	peek pQueue

waitIdle :: D -> IO ()
waitIdle (D d) = throwUnlessSuccess . Result =<< C.waitIdle d

data QueueCreateInfo mn = QueueCreateInfo {
	queueCreateInfoNext :: TMaybe.M mn,
	queueCreateInfoFlags :: QueueCreateFlags,
	queueCreateInfoQueueFamilyIndex :: QueueFamily.Index,
	queueCreateInfoQueuePriorities :: [Float] }

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

queueCreateInfoToCore :: WithPoked (TMaybe.M mn) =>
	QueueCreateInfo mn -> (C.QueueCreateInfo -> IO a) -> IO ()
queueCreateInfoToCore QueueCreateInfo {
	queueCreateInfoNext = mnxt,
	queueCreateInfoFlags = QueueCreateFlagBits flgs,
	queueCreateInfoQueueFamilyIndex = QueueFamily.Index qfi,
	queueCreateInfoQueuePriorities = qps
	} f = allocaArray (length qps) \pqps -> do
	pokeArray pqps qps
	withPoked' mnxt \pnxt -> withPtrS pnxt \(castPtr -> pnxt') ->
		() <$ f C.QueueCreateInfo {
			C.queueCreateInfoSType = (),
			C.queueCreateInfoPNext = pnxt',
			C.queueCreateInfoFlags = flgs,
			C.queueCreateInfoQueueFamilyIndex = qfi,
			C.queueCreateInfoQueueCount = genericLength qps,
			C.queueCreateInfoPQueuePriorities = pqps }