fir-0.1.0.0: src/SPIRV/Stage.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-|
Module: SPIRV.Stage
This module enumerates the SPIR-V execution models / shader stages.
These are used both at the type-level and at the value-level.
See the SPIR-V specification, §3.3 __Execution Model__.
This module also keeps track of certain execution modes that need to be known
at the type-level to perform certain type-level checks for custom error messages,
e.g. which kind of tessellation is happening (triangles, quads, isolines).
This information is eventually computed using user "SPIRV.Decoration.Decoration"s,
but it proved useful to separate these decorations out.
-}
module SPIRV.Stage where
-- base
import Data.Kind
( Type )
import Data.Word
( Word32 )
import GHC.TypeLits
( Symbol, AppendSymbol )
import GHC.TypeNats
( Nat, KnownNat, CmpNat )
-- fir
import Data.Binary.Class.Put
( Put(..), PutWord32Enum(..) )
import Data.Type.Known
( Demotable(Demote), Known(known), knownValue )
import Data.Type.POrd
( POrd(Compare) )
-------------------------------------------------------
-- execution models / stages
data ExecutionModel
= Stage Stage
| Kernel -- OpenCL compute kernel
deriving stock ( Show, Eq, Ord )
data Stage
= ShaderStage Shader
| MeshStage MeshShader
| RayStage RayShader
deriving stock ( Show, Eq, Ord )
data Shader
= VertexShader
| TessellationControlShader
| TessellationEvaluationShader
| GeometryShader
| FragmentShader
| ComputeShader -- GLCompute in SPIR-V
deriving stock ( Show, Eq, Ord, Enum, Bounded )
deriving Put via (PutWord32Enum Shader)
data MeshShader
= TaskShader
| MeshShader
deriving stock ( Show, Eq, Ord, Enum, Bounded )
instance Put MeshShader where
put = put @Word32 . (+5267) . fromIntegral . fromEnum
wordCount _ = 1
data RayShader
= RayGenerationShader
| IntersectionShader
| AnyHitShader
| ClosestHitShader
| MissShader
| CallableShader
deriving stock ( Show, Eq, Ord, Enum, Bounded )
instance Put RayShader where
put = put @Word32 . (+5313) . fromIntegral . fromEnum
wordCount _ = 1
instance Put Stage where
put (ShaderStage s) = put s
put (MeshStage s) = put s
put (RayStage s) = put s
wordCount _ = 1
instance Put ExecutionModel where
put (Stage s) = put s
put Kernel = put @Word32 6
wordCount _ = 1
stageID :: Stage -> Word32
stageID (ShaderStage s) = fromIntegral ( fromEnum s )
stageID (MeshStage s) = fromIntegral ( fromEnum s + 5267 )
stageID (RayStage s) = fromIntegral ( fromEnum s + 5313 )
executionModelID :: ExecutionModel -> Word32
executionModelID (Stage s) = stageID s
executionModelID Kernel = 6
type Vertex = 'Stage ('ShaderStage 'VertexShader)
type TessellationControl = 'Stage ('ShaderStage 'TessellationControlShader)
type TessellationEvaluation = 'Stage ('ShaderStage 'TessellationEvaluationShader)
type Geometry = 'Stage ('ShaderStage 'GeometryShader)
type Fragment = 'Stage ('ShaderStage 'FragmentShader)
type Compute = 'Stage ('ShaderStage 'ComputeShader)
type Task = 'Stage ('MeshStage 'TaskShader)
type Mesh = 'Stage ('MeshStage 'MeshShader)
type RayGeneration = 'Stage ('RayStage 'RayGenerationShader)
type Intersection = 'Stage ('RayStage 'IntersectionShader)
type AnyHit = 'Stage ('RayStage 'AnyHitShader)
type ClosestHit = 'Stage ('RayStage 'ClosestHitShader)
type Miss = 'Stage ('RayStage 'MissShader)
type Callable = 'Stage ('RayStage 'CallableShader)
instance Demotable Shader where
type Demote Shader = Shader
instance Known Shader VertexShader where
known = VertexShader
instance Known Shader TessellationControlShader where
known = TessellationControlShader
instance Known Shader TessellationEvaluationShader where
known = TessellationEvaluationShader
instance Known Shader GeometryShader where
known = GeometryShader
instance Known Shader FragmentShader where
known = FragmentShader
instance Known Shader ComputeShader where
known = ComputeShader
instance Demotable MeshShader where
type Demote MeshShader = MeshShader
instance Known MeshShader 'TaskShader where
known = TaskShader
instance Known MeshShader 'MeshShader where
known = MeshShader
instance Demotable RayShader where
type Demote RayShader = RayShader
instance Known RayShader RayGenerationShader where
known = RayGenerationShader
instance Known RayShader IntersectionShader where
known = IntersectionShader
instance Known RayShader AnyHitShader where
known = AnyHitShader
instance Known RayShader ClosestHitShader where
known = ClosestHitShader
instance Known RayShader MissShader where
known = MissShader
instance Known RayShader CallableShader where
known = CallableShader
instance Demotable Stage where
type Demote Stage = Stage
instance Known Shader shader => Known Stage (ShaderStage shader) where
known = ShaderStage ( knownValue @shader )
instance Known MeshShader meshShader => Known Stage (MeshStage meshShader) where
known = MeshStage ( knownValue @meshShader )
instance Known RayShader rayShader => Known Stage (RayStage rayShader) where
known = RayStage ( knownValue @rayShader )
instance Demotable ExecutionModel where
type Demote ExecutionModel = ExecutionModel
instance Known Stage stage => Known ExecutionModel ('Stage stage) where
known = Stage ( knownValue @stage )
instance Known ExecutionModel Kernel where
known = Kernel
type family FromEnumShader (s :: Shader) :: Nat where
FromEnumShader VertexShader = 0
FromEnumShader TessellationControlShader = 1
FromEnumShader TessellationEvaluationShader = 2
FromEnumShader GeometryShader = 3
FromEnumShader FragmentShader = 4
FromEnumShader ComputeShader = 5
type family FromEnumMeshShader (s :: MeshShader) :: Nat where
FromEnumMeshShader 'TaskShader = 5267
FromEnumMeshShader 'MeshShader = 5268
type family FromEnumRayShader (s :: RayShader) :: Nat where
FromEnumRayShader RayGenerationShader = 5313
FromEnumRayShader IntersectionShader = 5314
FromEnumRayShader AnyHitShader = 5315
FromEnumRayShader ClosestHitShader = 5316
FromEnumRayShader MissShader = 5317
FromEnumRayShader CallableShader = 5318
type family FromEnumStage (s :: Stage) :: Nat where
FromEnumStage (ShaderStage s) = FromEnumShader s
FromEnumStage (MeshStage s) = FromEnumMeshShader s
FromEnumStage (RayStage s) = FromEnumRayShader s
type family FromEnumExecutionModel (em :: ExecutionModel) :: Nat where
FromEnumExecutionModel ('Stage s) = FromEnumStage s
FromEnumExecutionModel Kernel = 6
instance POrd ExecutionModel where
type Compare s1 s2 = FromEnumExecutionModel s1 `CmpNat` FromEnumExecutionModel s2
type family ShaderName (s :: Shader) :: Symbol where
ShaderName VertexShader = "Vertex shader"
ShaderName TessellationControlShader = "Tessellation Control shader"
ShaderName TessellationEvaluationShader = "Tessellation Evaluation shader"
ShaderName GeometryShader = "Geometry shader"
ShaderName FragmentShader = "Fragment shader"
ShaderName ComputeShader = "Compute shader"
type family StageName (s :: Stage) :: Symbol where
StageName (ShaderStage s) = ShaderName s
StageName (MeshStage 'TaskShader) = "Task shader"
StageName (MeshStage 'MeshShader) = "Mesh shader"
StageName (RayStage RayGenerationShader) = "Ray Generation shader"
StageName (RayStage IntersectionShader) = "Ray Intersection shader"
StageName (RayStage AnyHitShader) = "Any Hit ray shader"
StageName (RayStage ClosestHitShader) = "Closest Hit ray shader"
StageName (RayStage MissShader) = "Ray Miss shader"
StageName (RayStage CallableShader) = "Ray Callable shader"
type family ExecutionModelName (em :: ExecutionModel) :: Symbol where
ExecutionModelName ('Stage s) = StageName s
ExecutionModelName Kernel = "Compute kernel"
type family NamedShader (k :: Symbol) (s :: Shader) :: Symbol where
NamedShader k s = ShaderName s `AppendSymbol` " named \"" `AppendSymbol` k `AppendSymbol` "\""
type family NamedStage (k :: Symbol) (s :: Stage) :: Symbol where
NamedStage k s = StageName s `AppendSymbol` " named \"" `AppendSymbol` k `AppendSymbol` "\""
type family NamedExecutionModel (k :: Symbol) (em :: ExecutionModel) :: Symbol where
NamedExecutionModel k em = ExecutionModelName em `AppendSymbol` " named \"" `AppendSymbol` k `AppendSymbol` "\""
--------------------------------------------------------------------------
-- execution backends: whether Vulkan or OpenCL
data Backend = Vulkan | OpenCL
deriving stock ( Eq, Show )
type family OtherBackend ( bk :: Backend ) :: Backend where
OtherBackend Vulkan = OpenCL
OtherBackend OpenCL = Vulkan
instance Demotable Backend where
type Demote Backend = Backend
instance Known Backend Vulkan where
known = Vulkan
instance Known Backend OpenCL where
known = OpenCL
type family BackendOf ( model :: ExecutionModel ) :: Backend where
BackendOf ( 'Stage _ ) = Vulkan
BackendOf Kernel = OpenCL
backendOf :: ExecutionModel -> Backend
backendOf ( Stage _ ) = Vulkan
backendOf Kernel = OpenCL
--------------------------------------------------------------------------
-- additional execution model information that needs to be known at the type-level
data TessellationMode
= ModeTriangles
| ModeQuads
| ModeIsolines
| ModePoints
deriving stock (Show, Eq, Ord, Enum, Bounded)
type family ShowTessellationMode (mode :: TessellationMode) :: Symbol where
ShowTessellationMode ModeTriangles = "Triangles"
ShowTessellationMode ModeQuads = "Quads"
ShowTessellationMode ModeIsolines = "Isolines"
ShowTessellationMode ModePoints = "Points"
data GeometryInputMode
= InputModePoints
| InputModeLines
| InputModeLinesAdjacency
| InputModeTriangles
| InputModeTrianglesAdjacency
deriving stock (Show, Eq, Ord, Enum, Bounded)
type family ShowGeometryInputMode (mode :: GeometryInputMode) :: Symbol where
ShowGeometryInputMode InputModePoints
= "InputPoints"
ShowGeometryInputMode InputModeLines
= "InputLines"
ShowGeometryInputMode InputModeLinesAdjacency
= "InputLinesAdjacency"
ShowGeometryInputMode InputModeTriangles
= "(Input)Triangles"
ShowGeometryInputMode InputModeTrianglesAdjacency
= "InputTrianglesAdjacency"
instance Demotable TessellationMode where
type Demote TessellationMode = TessellationMode
instance Demotable GeometryInputMode where
type Demote GeometryInputMode = GeometryInputMode
instance Known TessellationMode 'ModeTriangles where
known = ModeTriangles
instance Known TessellationMode 'ModeQuads where
known = ModeQuads
instance Known TessellationMode 'ModeIsolines where
known = ModeIsolines
instance Known TessellationMode 'ModePoints where
known = ModePoints
instance Known GeometryInputMode 'InputModePoints where
known = InputModePoints
instance Known GeometryInputMode 'InputModeLines where
known = InputModeLines
instance Known GeometryInputMode 'InputModeLinesAdjacency where
known = InputModeLinesAdjacency
instance Known GeometryInputMode 'InputModeTriangles where
known = InputModeTriangles
instance Known GeometryInputMode 'InputModeTrianglesAdjacency where
known = InputModeTrianglesAdjacency
data ShaderInfo (n :: Type) (s :: Shader) where
VertexShaderInfo
:: ShaderInfo n VertexShader
TessellationControlShaderInfo
:: n -- input size
-> n -- output size
-> Maybe TessellationMode
-> ShaderInfo n TessellationControlShader
TessellationEvaluationShaderInfo
:: n -- input size
-> TessellationMode
-> ShaderInfo n TessellationEvaluationShader
GeometryShaderInfo
:: n -- input size
-> GeometryInputMode
-> ShaderInfo n GeometryShader
FragmentShaderInfo
:: ShaderInfo n FragmentShader
ComputeShaderInfo
:: (n,n,n) -- shader local size
-> ShaderInfo n ComputeShader
deriving stock instance Show n => Show (ShaderInfo n s)
deriving stock instance Eq n => Eq (ShaderInfo n s)
deriving stock instance Ord n => Ord (ShaderInfo n s)
data RayShaderInfo (s :: RayShader) where
RayGenerationShaderInfo :: RayShaderInfo RayGenerationShader
IntersectionShaderInfo :: RayShaderInfo IntersectionShader
AnyHitShaderInfo :: RayShaderInfo AnyHitShader
ClosestHitShaderInfo :: RayShaderInfo ClosestHitShader
MissShaderInfo :: RayShaderInfo MissShader
CallableShaderInfo :: RayShaderInfo CallableShader
type family MkRayShaderInfo ( s :: RayShader ) :: RayShaderInfo s where
MkRayShaderInfo RayGenerationShader = RayGenerationShaderInfo
MkRayShaderInfo IntersectionShader = IntersectionShaderInfo
MkRayShaderInfo AnyHitShader = AnyHitShaderInfo
MkRayShaderInfo ClosestHitShader = ClosestHitShaderInfo
MkRayShaderInfo MissShader = MissShaderInfo
MkRayShaderInfo CallableShader = CallableShaderInfo
deriving stock instance Show (RayShaderInfo s)
deriving stock instance Eq (RayShaderInfo s)
deriving stock instance Ord (RayShaderInfo s)
data ExecutionInfo (n :: Type) (em :: ExecutionModel) where
ShaderExecutionInfo :: ShaderInfo n s -> ExecutionInfo n ('Stage ('ShaderStage s))
KernelInfo
:: (n,n,n) -- kernel local size
-> ExecutionInfo n Kernel
-- ray shaders don't need extra info (at least at the moment)
RayShaderInfo :: RayShaderInfo s -> ExecutionInfo n ('Stage ('RayStage s))
type VertexInfo = 'ShaderExecutionInfo 'VertexShaderInfo
type TessellationControlInfo i j m = 'ShaderExecutionInfo ( 'TessellationControlShaderInfo i j m)
type TessellationEvaluationInfo i m = 'ShaderExecutionInfo ( 'TessellationEvaluationShaderInfo i m)
type GeometryInfo i m = 'ShaderExecutionInfo ('GeometryShaderInfo i m)
type FragmentInfo = 'ShaderExecutionInfo 'FragmentShaderInfo
type ComputeInfo ijk = 'ShaderExecutionInfo ('ComputeShaderInfo ijk)
deriving stock instance Show n => Show (ExecutionInfo n s)
deriving stock instance Eq n => Eq (ExecutionInfo n s)
deriving stock instance Ord n => Ord (ExecutionInfo n s)
modelOf :: ExecutionInfo n em -> ExecutionModel
modelOf (ShaderExecutionInfo VertexShaderInfo)
= Stage (ShaderStage VertexShader)
modelOf (ShaderExecutionInfo (TessellationControlShaderInfo {}))
= Stage (ShaderStage TessellationControlShader)
modelOf (ShaderExecutionInfo (TessellationEvaluationShaderInfo {}))
= Stage (ShaderStage TessellationEvaluationShader)
modelOf (ShaderExecutionInfo (GeometryShaderInfo {}))
= Stage (ShaderStage GeometryShader)
modelOf (ShaderExecutionInfo FragmentShaderInfo)
= Stage (ShaderStage FragmentShader)
modelOf (ShaderExecutionInfo (ComputeShaderInfo {}))
= Stage (ShaderStage ComputeShader)
modelOf (KernelInfo {})
= Kernel
modelOf (RayShaderInfo RayGenerationShaderInfo)
= Stage (RayStage RayGenerationShader)
modelOf (RayShaderInfo IntersectionShaderInfo )
= Stage (RayStage IntersectionShader)
modelOf (RayShaderInfo AnyHitShaderInfo)
= Stage (RayStage AnyHitShader)
modelOf (RayShaderInfo ClosestHitShaderInfo)
= Stage (RayStage ClosestHitShader)
modelOf (RayShaderInfo MissShaderInfo)
= Stage (RayStage MissShader)
modelOf (RayShaderInfo CallableShaderInfo)
= Stage (RayStage CallableShader)
instance Demotable (ShaderInfo Nat s) where
type Demote (ShaderInfo Nat s) = ShaderInfo Word32 s
instance Known (ShaderInfo Nat VertexShader) VertexShaderInfo where
known = VertexShaderInfo
instance ( KnownNat inputSize
, KnownNat outputSize
, Known (Maybe TessellationMode) mbMode
)
=> Known
(ShaderInfo Nat TessellationControlShader)
(TessellationControlShaderInfo inputSize outputSize mbMode) where
known = TessellationControlShaderInfo
( knownValue @inputSize )
( knownValue @outputSize )
( knownValue @mbMode )
instance (KnownNat inputSize, Known TessellationMode mode)
=> Known
(ShaderInfo Nat TessellationEvaluationShader)
(TessellationEvaluationShaderInfo inputSize mode) where
known = TessellationEvaluationShaderInfo
( knownValue @inputSize )
( knownValue @mode )
instance (KnownNat inputSize, Known GeometryInputMode mode)
=> Known (ShaderInfo Nat GeometryShader)
(GeometryShaderInfo inputSize mode) where
known = GeometryShaderInfo
( knownValue @inputSize )
( knownValue @mode )
instance Known (ShaderInfo Nat FragmentShader) FragmentShaderInfo where
known = FragmentShaderInfo
instance ( Known (Nat,Nat,Nat) ijk )
=> Known (ShaderInfo Nat ComputeShader) (ComputeShaderInfo ijk) where
known = ComputeShaderInfo ( knownValue @ijk )
instance Demotable (RayShaderInfo s) where
type Demote (RayShaderInfo s) = RayShaderInfo s
instance Known ( RayShaderInfo RayGenerationShader ) RayGenerationShaderInfo where
known = RayGenerationShaderInfo
instance Known ( RayShaderInfo IntersectionShader ) IntersectionShaderInfo where
known = IntersectionShaderInfo
instance Known ( RayShaderInfo AnyHitShader ) AnyHitShaderInfo where
known = AnyHitShaderInfo
instance Known ( RayShaderInfo ClosestHitShader ) ClosestHitShaderInfo where
known = ClosestHitShaderInfo
instance Known ( RayShaderInfo MissShader ) MissShaderInfo where
known = MissShaderInfo
instance Known ( RayShaderInfo CallableShader ) CallableShaderInfo where
known = CallableShaderInfo
instance Demotable (ExecutionInfo Nat s) where
type Demote (ExecutionInfo Nat s) = ExecutionInfo Word32 s
instance Known (ShaderInfo Nat s) info
=> Known (ExecutionInfo Nat ('Stage ('ShaderStage s)))
(ShaderExecutionInfo info)
where
known = ShaderExecutionInfo ( knownValue @info )
instance ( Known (Nat,Nat,Nat) ijk )
=> Known (ExecutionInfo Nat 'Kernel) (KernelInfo ijk) where
known = KernelInfo ( knownValue @ijk)
instance Known (RayShaderInfo s) info
=> Known (ExecutionInfo Nat ('Stage ('RayStage s)))
('RayShaderInfo info)
where
known = RayShaderInfo ( knownValue @info )