packages feed

gpu-vulkan-middle-0.1.0.74: src/Gpu/Vulkan/PhysicalDevice/Middle/Internal.hsc

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving, GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.PhysicalDevice.Middle.Internal (

	-- * ENUMERATE, PROPERTIES AND FEATURES

	enumerate, P(..), getProperties, Properties(..), getFeatures,

	-- ** Get Properties 2

	getProperties2ExtensionName,
	getFeatures2, Features2(..),

	-- * OTHER PROPERTIES

	getQueueFamilyProperties,
	enumerateExtensionProperties,
	getFormatProperties,
	getMemoryProperties, MemoryProperties(..),

	-- * OTHER FEATURES

	ShaderDrawParametersFeatures(..),

	-- * OTHER EXTENSIONS

	maintenance3ExtensionName

	) where

import Foreign.Ptr
import Foreign.Marshal
import Foreign.Storable
import Foreign.Storable.PeekPoke
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.Maybe
import Data.List.Length
import Data.Word
import Data.UUID

import qualified Data.ByteString.Lazy as LBS

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

import Gpu.Vulkan.Enum
import Gpu.Vulkan.Middle.Internal
import Gpu.Vulkan.Base.Middle.Internal
import Gpu.Vulkan.Exception.Middle.Internal
import Gpu.Vulkan.Exception.Enum
import Gpu.Vulkan.PhysicalDevice.Enum
import Gpu.Vulkan.PhysicalDevice.Struct

import qualified Gpu.Vulkan.Instance.Middle.Internal as Instance.M
import qualified Gpu.Vulkan.PhysicalDevice.Core as C
import qualified Gpu.Vulkan.QueueFamily.Middle.Internal as QueueFamily
import qualified Gpu.Vulkan.QueueFamily.EnumManual as QueueFamily
import qualified Gpu.Vulkan.Memory.Middle.Internal as Memory.M

import Gpu.Vulkan.PNext.Middle.Internal

#include <vulkan/vulkan.h>

newtype P = P C.P deriving (Show, Storable)

enumerate :: Instance.M.I -> IO [P]
enumerate (Instance.M.I ist) = map P <$> alloca \pdvcc ->
	C.enumerate ist pdvcc NullPtr >>= \r ->
	throwUnlessSuccess (Result r) >>
	peek pdvcc >>= \(fromIntegral -> dvcc) ->
	allocaArray dvcc \pdvcs ->
	C.enumerate ist pdvcc pdvcs >>= \r' ->
	throwUnlessSuccess (Result r') >>
	peekArray dvcc pdvcs

data Properties = Properties {
	propertiesApiVersion :: ApiVersion,
	propertiesDriverVersion :: Word32,
	propertiesVendorId :: Word32,
	propertiesDeviceId :: Word32,
	propertiesDeviceType :: Type,
	propertiesDeviceName :: T.Text,
	propertiesPipelineCacheUuid :: UUID,
	propertiesLimits :: Limits,
	propertiesSparseProperties :: SparseProperties }
	deriving Show

propertiesFromCore :: C.Properties -> Properties
propertiesFromCore C.Properties {
	C.propertiesApiVersion = av,
	C.propertiesDriverVersion = dv,
	C.propertiesVendorId = vi,
	C.propertiesDeviceId = di,
	C.propertiesDeviceType = dt,
	C.propertiesDeviceName = dn,
	C.propertiesPipelineCacheUuid = pcu,
	C.propertiesLimits = l,
	C.propertiesSparseProperties = sp } = Properties {
	propertiesApiVersion = ApiVersion av,
	propertiesDriverVersion = dv,
	propertiesVendorId = vi,
	propertiesDeviceId = di,
	propertiesDeviceType = Type dt,
	propertiesDeviceName = dn,
	propertiesPipelineCacheUuid = word8listToUuid pcu,
	propertiesLimits = limitsFromCore l,
	propertiesSparseProperties = sparsePropertiesFromCore sp }

word8listToUuid :: [Word8] -> UUID
word8listToUuid ws = fromJust . fromByteString $ LBS.pack ws

data SparseProperties = SparseProperties {
	sparsePropertiesResidencyStandard2DBlockShape :: Bool,
	sparsePropertiesResidencyStandard2DMultisampleBlockShape :: Bool,
	sparsePropertiesResidencyStandard3DBlockShape :: Bool,
	sparsePropertiesResidencyAlignedMipSize :: Bool,
	sparsePropertiesResidencyNonResidentStrict :: Bool }
	deriving Show

sparsePropertiesFromCore :: C.SparseProperties -> SparseProperties
sparsePropertiesFromCore C.SparseProperties {
	C.sparsePropertiesResidencyStandard2DBlockShape = crs2bs,
	C.sparsePropertiesResidencyStandard2DMultisampleBlockShape = crs2mbs,
	C.sparsePropertiesResidencyStandard3DBlockShape = crs3bs,
	C.sparsePropertiesResidencyAlignedMipSize = crams,
	C.sparsePropertiesResidencyNonResidentStrict = cnrs } =
	SparseProperties {
		sparsePropertiesResidencyStandard2DBlockShape = rs2bs,
		sparsePropertiesResidencyStandard2DMultisampleBlockShape =
			rs2mbs,
		sparsePropertiesResidencyStandard3DBlockShape = rs3bs,
		sparsePropertiesResidencyAlignedMipSize = rams,
		sparsePropertiesResidencyNonResidentStrict = nrs }
	where
	(rs2bs :. rs2mbs :. rs3bs :. rams :. nrs :. NilL :: LengthL 5 Bool) =
		bool32ToBool <$>
			(crs2bs :. crs2mbs :. crs3bs :. crams :. cnrs :. NilL)

getProperties :: P -> IO Properties
getProperties (P pdvc) = propertiesFromCore <$> alloca \pppts -> do
	C.getProperties pdvc pppts
	peek pppts

getFeatures :: P -> IO Features
getFeatures (P pdvc) = featuresFromCore <$> alloca \pfts -> do
	C.getFeatures pdvc pfts
	peek pfts

getFeatures2 :: forall mn . ReadChain mn => P -> IO (Features2 mn)
getFeatures2 (P pdvc) = clearedChain @mn \pn ->
	features2FromCore =<< alloca \pfts -> do
		cfs <- C.getClearedFeatures
		poke pfts $ C.Features2 {
			C.features2SType = (),
			C.features2PNext = pn,
			C.features2Features = cfs }
		C.getFeatures2 pdvc pfts
		peek pfts

data Features2 mn = Features2 {
	features2Next :: TMaybe.M mn,
	features2Features :: Features }

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

instance WithPoked (TMaybe.M mn) => WithPoked (Features2 mn) where
	withPoked' (Features2 mn fs) f = alloca \pfs2 -> do
		withPoked' mn \spn -> withPtrS spn \pn ->
			poke pfs2 $ C.Features2 () (castPtr pn) (featuresToCore fs)
		f . ptrS $ castPtr pfs2

features2FromCore :: ReadChain mn => C.Features2 -> IO (Features2 mn)
features2FromCore C.Features2 {
	C.features2PNext = pnxt,
	C.features2Features = ftrs } = do
	nxts <- readChain pnxt
	let	ftrs' = featuresFromCore ftrs
	pure Features2 {
		features2Next = nxts, features2Features = ftrs' }

getQueueFamilyProperties :: P -> IO [(QueueFamily.Index, QueueFamily.Properties)]
getQueueFamilyProperties (P pdvc) =
	(QueueFamily.indices `zip`)
		. map QueueFamily.propertiesFromCore <$> alloca \ppptc ->
	C.getQueueFamilyProperties pdvc ppptc NullPtr >>
	peek ppptc >>= \(fromIntegral -> pptc) ->
	allocaArray pptc \pppts ->
	C.getQueueFamilyProperties pdvc ppptc pppts >>
	peekArray pptc pppts

enumerateExtensionProperties ::
	P -> Maybe T.Text -> IO [ExtensionProperties]
enumerateExtensionProperties (P pdvc) mlnm =
	map extensionPropertiesFromCore <$> case mlnm of
		Nothing -> go NullPtr
		Just lnm -> textToCString lnm go
	where
	go cmlnm = alloca \pExtensionCount ->
		C.enumerateExtensionProperties
			pdvc cmlnm pExtensionCount NullPtr >>= \r ->
		throwUnlessSuccess (Result r) >>
		peek pExtensionCount >>= \(fromIntegral -> extensionCount) ->
		allocaArray extensionCount \pAvailableExtensions -> do
			r' <- C.enumerateExtensionProperties pdvc cmlnm
				pExtensionCount pAvailableExtensions
			throwUnlessSuccess $ Result r'
			peekArray extensionCount pAvailableExtensions

data MemoryProperties = MemoryProperties {
	memoryPropertiesMemoryTypes :: [(Memory.M.TypeIndex, Memory.M.MType)],
	memoryPropertiesMemoryHeaps :: [Memory.M.Heap] }
	deriving Show

memoryPropertiesFromCore :: C.MemoryProperties -> MemoryProperties
memoryPropertiesFromCore C.MemoryProperties {
	C.memoryPropertiesMemoryTypeCount = fromIntegral -> mtc,
	C.memoryPropertiesMemoryTypes = (Memory.M.mTypeFromCore <$>) -> mts,
	C.memoryPropertiesMemoryHeapCount = fromIntegral -> mhc,
	C.memoryPropertiesMemoryHeaps = (Memory.M.heapFromCore <$>) -> mhs } =
	MemoryProperties {
		memoryPropertiesMemoryTypes = [0 ..] `zip` take mtc mts,
		memoryPropertiesMemoryHeaps = take mhc mhs }

getMemoryProperties :: P -> IO MemoryProperties
getMemoryProperties (P p) = memoryPropertiesFromCore <$> alloca \pmps -> do
	C.getMemoryProperties p pmps
	peek pmps

getFormatProperties :: P -> Format -> IO FormatProperties
getFormatProperties (P pdvc) (Format fmt) = formatPropertiesFromCore <$> alloca \pp -> do
	C.getFormatProperties pdvc fmt pp
	peek pp

data ShaderDrawParametersFeatures mn = ShaderDrawParametersFeatures {
	shaderDrawParametersFeaturesNext :: TMaybe.M mn,
	shaderDrawParametersFeaturesShaderDrawParameters :: Bool }

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

shaderDrawParametersFeaturesToCore :: WithPoked (TMaybe.M mn) =>
	ShaderDrawParametersFeatures mn ->
	(Ptr C.ShaderDrawParametersFeatures -> IO a) -> IO a
shaderDrawParametersFeaturesToCore ShaderDrawParametersFeatures {
	shaderDrawParametersFeaturesNext = mnxt,
	shaderDrawParametersFeaturesShaderDrawParameters = sdp } f =
	alloca \pfs -> withPoked' mnxt \pnxt -> do
		withPtrS pnxt \(castPtr -> pnxt') -> poke pfs
			C.ShaderDrawParametersFeatures {
				C.shaderDrawParametersFeaturesSType = (),
				C.shaderDrawParametersFeaturesPNext = pnxt',
				C.shaderDrawParametersFeaturesShaderDrawParameters =
					boolToBool32 sdp }
		f pfs

instance WithPoked (TMaybe.M mn) => WithPoked (ShaderDrawParametersFeatures mn) where
	withPoked' sdpfs f =
		shaderDrawParametersFeaturesToCore sdpfs $ f . ptrS . castPtr

maintenance3ExtensionName :: T.Text
maintenance3ExtensionName = #{const_str VK_KHR_MAINTENANCE_3_EXTENSION_NAME}

getProperties2ExtensionName :: T.Text
getProperties2ExtensionName =
	#{const_str VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME}