packages feed

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

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables, RankNTypes, TypeApplications #-}
{-# LANGUAGE GADTs, TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.QueryPool (

	-- * CREATE

	create, Q, CreateInfo(..),

	-- * GET RESULTS

	getResults, QueryType, PipelineStatistics(..), Timestamp(..),

	M.Availability(..)

	) where

import Foreign.Storable
import Foreign.Storable.PeekPoke
import Control.Exception
import Data.TypeLevel.Maybe qualified as TMaybe
import Data.TypeLevel.ParMaybe qualified as TPMaybe
import Data.TypeLevel.Tuple.Uncurry
import Data.Kind
import Data.Word

import Gpu.Vulkan.AllocationCallbacks qualified as AllocationCallbacks
import Gpu.Vulkan.AllocationCallbacks.Type qualified as AllocationCallbacks
import Gpu.Vulkan.PhysicalDevice qualified as PhysicalDevice
import Gpu.Vulkan.PhysicalDevice.Struct qualified as PhysicalDevice
import Gpu.Vulkan.Device.Type qualified as Device
import Gpu.Vulkan.Query qualified as Q
import Gpu.Vulkan.QueryPool.Type
import Gpu.Vulkan.QueryPool.Middle qualified as M

-- CREATE

create :: (
	WithPoked (TMaybe.M mn), QueryType tp,
	AllocationCallbacks.ToMiddle mac ) =>
	Device.D sd -> CreateInfo mn tp ->
	TPMaybe.M (U2 AllocationCallbacks.A) mac ->
	(forall s . Q s tp -> IO a) -> IO a
create (Device.D dv) ci
	(AllocationCallbacks.toMiddle -> macc) f = bracket
	(M.create dv (createInfoToMiddle ci) macc)
	(\qp -> M.destroy dv qp macc) (f . Q)

data CreateInfo mn (tp :: Bool -> Type) = CreateInfo {
	createInfoNext :: TMaybe.M mn,
	createInfoFlags :: M.CreateFlags,
	createInfoQueryCount :: Q.Count,
	createInfoPipelineStatistics :: Q.PipelineStatisticFlags }

deriving instance Show (TMaybe.M mn) => Show (CreateInfo mn tp)

createInfoToMiddle ::
	forall n tp . QueryType tp => CreateInfo n tp -> M.CreateInfo n
createInfoToMiddle CreateInfo {
	createInfoNext = mnxt,
	createInfoFlags = flgs,
	createInfoQueryCount = qc,
	createInfoPipelineStatistics = ps } = M.CreateInfo {
	M.createInfoNext = mnxt,
	M.createInfoFlags = flgs,
	M.createInfoQueryType = queryType @tp,
	M.createInfoQueryCount = qc,
	M.createInfoPipelineStatistics = ps }

-- GET RESULTS

getResults :: forall sd sq av tp w64 . (
	QueryType tp,
	Storable (M.W32W64 w64), M.W32W64Tools w64,
	M.AvailabilityTools av (M.W32W64 w64) ) =>
	PhysicalDevice.P ->
	Device.D sd -> Q sq tp -> Q.First -> Q.Count -> Q.ResultFlags ->
	IO [M.Availability av (tp w64)]
getResults pd (Device.D dv) (Q qp) fq qc flgs = do
	a <- getQueryArg @tp pd
	((fromWord a <$>) <$>) <$> M.getResults dv qp fq qc flgs

class QueryType (qt :: Bool -> Type) where
	type QueryArg qt
	queryType :: Q.Type
	fromWord :: QueryArg qt -> M.W32W64 w64 -> qt w64
	getQueryArg :: PhysicalDevice.P -> IO (QueryArg qt)

-- Pipeline Statistics

instance QueryType PipelineStatistics where
	type QueryArg PipelineStatistics = ()
	queryType = Q.TypePipelineStatistics
	fromWord () = pipelineStatisticsFromWord
	getQueryArg _ = pure ()

data PipelineStatistics (w64 :: Bool) where
	PipelineStatistics32 :: Word32 -> PipelineStatistics 'False
	PipelineStatistics64 :: Word64 -> PipelineStatistics 'True

deriving instance Show (PipelineStatistics w64)

pipelineStatisticsFromWord :: M.W32W64 w64 -> PipelineStatistics w64
pipelineStatisticsFromWord = \case
	M.W32 w -> PipelineStatistics32 w; M.W64 w -> PipelineStatistics64 w

-- Timestamp

data Timestamp w64 where
	Timestamp32 :: {
		timestampPeriod32 :: Float,
		timestampW32 :: Word32 } -> Timestamp 'False
	Timestamp64 :: {
		timestampPeriod64 :: Float,
		timestampW64 :: Word64 } -> Timestamp 'True

instance Show (Timestamp w64) where
	show = \case
		Timestamp32 p w ->
			show @Double (realToFrac p * fromIntegral w) ++ "ns"
		Timestamp64 p w ->
			show @Double (realToFrac p * fromIntegral w) ++ "ns"

instance QueryType Timestamp where
	type QueryArg Timestamp = Float
	queryType = Q.TypeTimestamp
	fromWord p = \case
		M.W32 w -> Timestamp32 p w; M.W64 w -> Timestamp64 p w
	getQueryArg pd = do
		lmts <- PhysicalDevice.propertiesLimits
			<$> PhysicalDevice.getProperties pd
		pure $ PhysicalDevice.limitsTimestampPeriod lmts