fir-0.1.0.0: src/FIR/Pipeline.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-|
Module: FIR.Pipeline
This module encodes the Vulkan concept of graphics pipelines
as a sequence of shader programs.
See "FIR.Validation.Pipeline" for the validation of such pipelines.
-}
module FIR.Pipeline
( PipelineInfo(..)
, PipelineStages(..), pipelineStages
, ShaderPipeline(..), pipelineShaders
, ShaderGroup(..)
, PrimitiveConnectedness(..)
, PrimitiveTopology(..)
, BindingStrides
, VertexLocationDescriptions
, GetVertexInputInfo, GetTopologyInfo -- (re-exports)
)
where
-- base
import Data.Kind
( Type )
import Data.Word
( Word32 )
import GHC.TypeLits
( Symbol )
import GHC.TypeNats
( Nat, KnownNat )
-- fir
import Data.Type.Known
( Demotable(Demote), Known(known), knownValue )
import Data.Type.Map
( (:->) )
import FIR.Definition
( Variables )
import FIR.Module
( ShaderModule )
import FIR.ProgramState
( Definedness(Defined)
, EntryPointInfo(EntryPointInfo)
)
import FIR.Validation.Pipeline
( ValidPipelineInfo
, GetExecutionInfo
, GetVertexInputInfo
, GetTopologyInfo
)
import qualified SPIRV.Image as SPIRV
( ImageFormat )
import qualified SPIRV.Stage as SPIRV
--------------------------------------------------------------------------
-- * Primitive topologies
data PrimitiveConnectedness
= List
| Strip
| Fan
| AdjacencyList
| AdjacencyStrip
deriving stock ( Eq, Ord, Show, Enum, Bounded )
data PrimitiveTopology (n :: Type)
= Points
| Line PrimitiveConnectedness
| Triangle PrimitiveConnectedness
| PatchesOfSize n
deriving stock ( Eq, Show )
instance Demotable PrimitiveConnectedness where
type Demote PrimitiveConnectedness = PrimitiveConnectedness
instance Known PrimitiveConnectedness 'List where
known = List
instance Known PrimitiveConnectedness 'Strip where
known = Strip
instance Known PrimitiveConnectedness 'Fan where
known = Fan
instance Known PrimitiveConnectedness 'AdjacencyList where
known = AdjacencyList
instance Known PrimitiveConnectedness 'AdjacencyStrip where
known = AdjacencyStrip
instance Demotable (PrimitiveTopology Nat) where
type Demote (PrimitiveTopology Nat) = PrimitiveTopology Word32
instance Known (PrimitiveTopology Nat) 'Points where
known = Points
instance Known PrimitiveConnectedness conn
=> Known (PrimitiveTopology Nat) ('Line conn) where
known = Line ( knownValue @conn )
instance Known PrimitiveConnectedness conn
=> Known (PrimitiveTopology Nat) ('Triangle conn) where
known = Triangle ( knownValue @conn )
instance KnownNat n => Known (PrimitiveTopology Nat) ('PatchesOfSize n) where
known = PatchesOfSize ( knownValue @n )
-------------------------------------------------------
-- * Graphics pipelines
-- | For each location:
-- - a binding index,
-- - the offset (in bytes) within the buffer bound at that index,
-- - the image format of the location.
type VertexLocationDescriptions = [ Nat :-> ( Nat, Nat, SPIRV.ImageFormat Nat ) ]
-- | For each binding, the corresponding stride to use.
type BindingStrides = [ Nat :-> Nat ]
-- | Pipeline information data kind.
--
-- Records information about a pipeline which should be kept track of at the type level,
-- to be used for validation.
--
-- - Primitive topology used for the pipeline,
-- - layout information (vertex location descriptions, binding strides),
-- - type-level information associated to each shader in the pipeline,
-- such as the type of shader (vertex shader, geometry shader, ...)
-- and the input/output interfaces (for interface matching).
--
-- Represented as a snoc-list, beginning with vertex input information,
-- and then the sequence of shaders in order.
data PipelineInfo where
VertexInputInfo
:: PrimitiveTopology Nat
-> VertexLocationDescriptions
-> BindingStrides
-> PipelineInfo
Into
:: PipelineInfo
-> ( Symbol, EntryPointInfo )
-> PipelineInfo
-- | Value-level sequence of pipeline stages.
--
-- Specified as a snoc-list:
--
-- > VertexInput @top @descs @strides :>-> (shader_1, filepath_1) :>-> ... (shader_n, filepath_n)
--
-- Keeps track of type-level information necessary for validation.
data PipelineStages (info :: PipelineInfo) (stageData :: Type) where
VertexInput
:: forall
( top :: PrimitiveTopology Nat )
( descs :: VertexLocationDescriptions )
( strides :: BindingStrides )
( stageData :: Type )
. ( Known (PrimitiveTopology Nat) top
, Known VertexLocationDescriptions descs
, Known BindingStrides strides
)
=> PipelineStages (VertexInputInfo top descs strides) stageData
(:>->) :: ( Known SPIRV.Shader shader )
=> PipelineStages info stageData
-> ( ShaderModule name shader defs endState, stageData )
-> PipelineStages
( info `Into`
'( name
, 'EntryPointInfo
( GetExecutionInfo shader name endState )
( Variables defs )
'Defined
)
)
stageData
deriving stock instance Functor (PipelineStages info)
deriving stock instance Foldable (PipelineStages info)
deriving stock instance Traversable (PipelineStages info)
-- | Smart wrapper for a shader pipeline,
-- performing type-level validation on a sequence of pipeline stages.
data ShaderPipeline (stageData :: Type) where
ShaderPipeline
:: forall
( info :: PipelineInfo )
( top :: PrimitiveTopology Nat )
( descs :: VertexLocationDescriptions )
( strides :: BindingStrides )
( stageData :: Type )
. ( ValidPipelineInfo info
, '(top, descs, strides) ~ GetVertexInputInfo info
, Known (PrimitiveTopology Nat) top
, Known VertexLocationDescriptions descs
, Known BindingStrides strides
)
=> PipelineStages info stageData
-> ShaderPipeline stageData
deriving stock instance Functor ShaderPipeline
deriving stock instance Foldable ShaderPipeline
deriving stock instance Traversable ShaderPipeline
pipelineStages :: PipelineStages info stageData -> [(SPIRV.Shader, stageData)]
pipelineStages = reverse . go []
where
go :: [(SPIRV.Shader, stageData)] -> PipelineStages info2 stageData -> [(SPIRV.Shader, stageData)]
go shaders VertexInput = shaders
go shaders ( info :>-> ( (_ :: ShaderModule name shader defs endState) , stageData) )
= go ( (knownValue @shader, stageData) : shaders) info
pipelineShaders :: ShaderPipeline stageData -> [(SPIRV.Shader, stageData)]
pipelineShaders (ShaderPipeline stages) = pipelineStages stages
--------------------------------------------------------------------------
-- * Ray-tracing shader groups
-- | Utility datatype used to organise ray-tracing shaders into groups,
-- to facilitate creation of a Vulkan ray-tracing pipeline.
data ShaderGroup a
= RaygenGroup a
| MissGroup a
| CallableGroup a
| HitGroup
{ intersection :: Maybe a
, closestHit :: Maybe a
, anyHit :: Maybe a
}
deriving stock ( Show, Eq, Functor, Foldable, Traversable )