vulkan-tutorial/src/GraphicsPipeline.hs

362 lines
13 KiB
Haskell
Raw Normal View History

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DataKinds #-}
2023-01-05 22:07:21 +00:00
{-# LANGUAGE FlexibleContexts #-}
module GraphicsPipeline where
import Linear
2023-01-05 22:07:21 +00:00
import qualified Control.Concurrent.STM as STM
import Control.Monad.Reader
import Control.Monad.Trans.Resource
import Data.Bits
2022-07-14 09:02:12 +00:00
-- import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS
2023-01-05 22:07:21 +00:00
import qualified Data.Map.Strict as M
import qualified Data.Vector as V
2022-12-11 08:02:17 +00:00
import Foreign (sizeOf)
import Foreign.C.Types (CInt)
2022-12-03 00:44:06 +00:00
import qualified Vulkan as VK
2022-07-14 05:02:10 +00:00
import qualified Vulkan.Core10 as Vk
import qualified Vulkan.Zero as Vk
import qualified Vulkan.CStruct.Extends as Vk
2022-07-14 09:02:12 +00:00
import qualified Vulkan.Utils.ShaderQQ.GLSL.Shaderc as Vk
2022-07-16 19:50:22 +00:00
-- internal imports
import Types
loadShader
:: (MonadResource m)
=> Vk.Device
-> FilePath
2022-07-14 09:02:12 +00:00
-> String
-> m Vk.ShaderModule
2022-07-14 09:02:12 +00:00
loadShader logicalDevice shaderPath stage = do
shaderSource <- liftIO $ BS.readFile shaderPath
2022-07-14 09:02:12 +00:00
(warnings, eShader) <- Vk.compileShader Nothing Nothing stage (BS.unpack shaderSource)
unless (null warnings) $ liftIO $ do
putStrLn "loadShader: Shader compilation warnings:"
print warnings
shader <- either
(\errors -> do
error ("loadShader: Compilation errors:" <> "\n" <> show errors)
)
return
eShader
let createInfo = Vk.zero
2022-07-14 09:02:12 +00:00
{ Vk.code = shader
}
snd <$> allocate
(Vk.createShaderModule logicalDevice createInfo Nothing)
(\shaderModule -> do
putStrLn "destroying shader module"
Vk.destroyShaderModule logicalDevice shaderModule Nothing
)
2022-07-16 19:50:22 +00:00
createRenderPass
:: (MonadResource m)
=> Vk.Device
-> Vk.Format
2022-12-28 03:18:54 +00:00
-> Vk.Format
2022-07-16 19:50:22 +00:00
-> m Vk.RenderPass
createRenderPass
logicalDevice
swapchainImageFormat
2022-12-28 03:18:54 +00:00
depthFormat
2022-07-16 19:50:22 +00:00
= do
let colorAttachmentDescription = (Vk.zero :: Vk.AttachmentDescription)
{ Vk.format = swapchainImageFormat
, Vk.samples = Vk.SAMPLE_COUNT_1_BIT
, Vk.loadOp = Vk.ATTACHMENT_LOAD_OP_CLEAR
, Vk.storeOp = Vk.ATTACHMENT_STORE_OP_STORE
, Vk.stencilLoadOp = Vk.ATTACHMENT_LOAD_OP_DONT_CARE
, Vk.stencilStoreOp = Vk.ATTACHMENT_STORE_OP_DONT_CARE
, Vk.initialLayout = Vk.IMAGE_LAYOUT_UNDEFINED
, Vk.finalLayout = Vk.IMAGE_LAYOUT_PRESENT_SRC_KHR
}
colorAttachmentReference = (Vk.zero :: Vk.AttachmentReference)
{ Vk.attachment = 0
, Vk.layout = Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
}
2022-12-28 03:18:54 +00:00
depthAttachmentDescription = (Vk.zero :: Vk.AttachmentDescription)
{ Vk.flags = bit 0
, Vk.format = depthFormat
, Vk.samples = Vk.SAMPLE_COUNT_1_BIT
, Vk.loadOp = Vk.ATTACHMENT_LOAD_OP_CLEAR
, Vk.storeOp = Vk.ATTACHMENT_STORE_OP_STORE
, Vk.stencilLoadOp = Vk.ATTACHMENT_LOAD_OP_CLEAR
, Vk.stencilStoreOp = Vk.ATTACHMENT_STORE_OP_DONT_CARE
, Vk.initialLayout = Vk.IMAGE_LAYOUT_UNDEFINED
, Vk.finalLayout = Vk.IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
}
depthAttachmentReference = (Vk.zero :: Vk.AttachmentReference)
{ Vk.attachment = 1
, Vk.layout = Vk.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
}
2022-07-16 19:50:22 +00:00
subpassDescriptor = (Vk.zero :: Vk.SubpassDescription)
2022-12-28 03:18:54 +00:00
{ Vk.pipelineBindPoint = Vk.PIPELINE_BIND_POINT_GRAPHICS
, Vk.colorAttachments = V.singleton colorAttachmentReference
, Vk.depthStencilAttachment = Just depthAttachmentReference
2022-07-16 19:50:22 +00:00
}
subpassDependency = Vk.zero
{ Vk.srcSubpass = Vk.SUBPASS_EXTERNAL
, Vk.dstSubpass = 0
, Vk.srcStageMask = Vk.PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
, Vk.dstStageMask = Vk.PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
2022-12-28 03:31:18 +00:00
, Vk.srcAccessMask = Vk.ACCESS_MEMORY_READ_BIT
2022-12-28 03:18:54 +00:00
, Vk.dstAccessMask = Vk.ACCESS_COLOR_ATTACHMENT_WRITE_BIT
}
subpassDepthDependency = Vk.zero
{ Vk.srcSubpass = Vk.SUBPASS_EXTERNAL
, Vk.dstSubpass = 0
, Vk.srcStageMask =
Vk.PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT .|. Vk.PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
2022-12-28 03:31:18 +00:00
, Vk.srcAccessMask = Vk.ACCESS_MEMORY_READ_BIT
2022-12-28 03:18:54 +00:00
, Vk.dstStageMask =
Vk.PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT .|. Vk.PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
, Vk.dstAccessMask = Vk.ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
2022-07-16 19:50:22 +00:00
}
renderPassCreateInfo = Vk.zero
2022-12-28 03:18:54 +00:00
{ Vk.attachments = V.fromList [ colorAttachmentDescription, depthAttachmentDescription ]
2022-07-16 19:50:22 +00:00
, Vk.subpasses = V.singleton subpassDescriptor
2022-12-28 03:18:54 +00:00
, Vk.dependencies = V.fromList [ subpassDependency, subpassDepthDependency ]
2022-07-16 19:50:22 +00:00
} :: Vk.RenderPassCreateInfo '[]
snd <$> allocate
(Vk.createRenderPass logicalDevice renderPassCreateInfo Nothing)
(\renderPass -> do
putStrLn "destroying render pass"
Vk.destroyRenderPass logicalDevice renderPass Nothing
)
2022-07-21 21:12:54 +00:00
createShaderStageCreateInfo
:: Vk.ShaderStageFlagBits
-> Vk.ShaderModule
-> Vk.PipelineShaderStageCreateInfo '[]
createShaderStageCreateInfo stageBit shaderModule =
Vk.zero
{ Vk.stage = stageBit
, Vk.module' = shaderModule
, Vk.name = "main"
}
createVertexInputAssemblyStateCreateInfo
:: Vk.PrimitiveTopology
-> Vk.PipelineInputAssemblyStateCreateInfo
createVertexInputAssemblyStateCreateInfo topology =
Vk.zero
{ Vk.topology = topology
, Vk.primitiveRestartEnable = False
}
createRasterizationStateCreateInfo
:: Vk.PolygonMode
2022-12-03 00:44:06 +00:00
-> Vk.SomeStruct Vk.PipelineRasterizationStateCreateInfo
2022-07-21 21:12:54 +00:00
createRasterizationStateCreateInfo mode =
Vk.SomeStruct $ Vk.zero
{ Vk.depthClampEnable = False
, Vk.rasterizerDiscardEnable = False
, Vk.polygonMode = mode
, Vk.lineWidth = 1
, Vk.cullMode = Vk.CULL_MODE_NONE
, Vk.frontFace = Vk.FRONT_FACE_CLOCKWISE
, Vk.depthBiasEnable = False
, Vk.depthBiasConstantFactor = 0
, Vk.depthBiasClamp = 0
, Vk.depthBiasSlopeFactor = 0
}
2022-12-28 03:18:54 +00:00
createDepthStencilStateCreateInfo
:: Bool
-> Bool
-> Vk.CompareOp
-> Vk.PipelineDepthStencilStateCreateInfo
createDepthStencilStateCreateInfo depthTest depthWrite compareOperation =
Vk.zero
{ Vk.depthTestEnable = depthTest
, Vk.depthWriteEnable = depthWrite
, Vk.depthCompareOp = compareOperation
, Vk.depthBoundsTestEnable = False
, Vk.minDepthBounds = 0
, Vk.maxDepthBounds = 1
, Vk.stencilTestEnable = False
}
2022-07-21 21:12:54 +00:00
createMultisampleStateCreateInfo
:: Vk.SomeStruct Vk.PipelineMultisampleStateCreateInfo
createMultisampleStateCreateInfo =
Vk.SomeStruct $ Vk.zero
{ Vk.sampleShadingEnable = False
, Vk.rasterizationSamples = Vk.SAMPLE_COUNT_1_BIT
}
2022-07-16 19:50:22 +00:00
createGraphicsPipelines
2023-01-05 22:07:21 +00:00
:: (MonadResource m, MonadReader ReadState m)
2022-07-14 05:02:10 +00:00
=> Vk.Device
2022-07-16 19:50:22 +00:00
-> Vk.RenderPass
-> ShaderContainer
-> V2 CInt
2022-07-16 19:50:22 +00:00
-> Vk.PipelineLayout
2022-12-28 03:18:54 +00:00
-> Maybe Vk.PipelineDepthStencilStateCreateInfo
2023-01-05 22:07:21 +00:00
-> m ()
createGraphicsPipelines
2022-07-14 05:02:10 +00:00
logicalDevice
2022-07-16 19:50:22 +00:00
renderPass
shaderContainer
(V2 width height)
2022-07-16 19:50:22 +00:00
pipelineLayout
2022-12-28 03:18:54 +00:00
depthState
= do
2023-01-05 22:07:21 +00:00
meshLib <- (liftIO . STM.atomically . STM.readTMVar) =<< asks meshLibrary
2022-07-21 21:12:54 +00:00
let pipelineStagesCreateInfos =
V.fromList $ map Vk.SomeStruct
2022-12-02 19:02:01 +00:00
( maybe
[]
(\shader ->
[ createShaderStageCreateInfo
Vk.SHADER_STAGE_VERTEX_BIT
shader
]
)
2022-07-21 21:12:54 +00:00
(containedVertexShader shaderContainer)
2022-12-02 19:02:01 +00:00
++
maybe
[]
(\shader ->
[ createShaderStageCreateInfo
Vk.SHADER_STAGE_FRAGMENT_BIT
shader
]
)
2022-07-21 21:12:54 +00:00
(containedFragmentShader shaderContainer)
2022-12-02 19:02:01 +00:00
)
dynamicStates =
V.fromList
[ Vk.DYNAMIC_STATE_VIEWPORT
, Vk.DYNAMIC_STATE_SCISSOR
]
pipelineDynamicStateCreateInfo = Vk.zero
{ Vk.dynamicStates = dynamicStates
}
2023-01-05 22:07:21 +00:00
vertexDescription = getVertexDescription (V.head $ meshVertices $ meshLib M.! "mask")
pipelineVertexInputCreateInfo = Vk.zero
2022-12-03 00:44:06 +00:00
{ Vk.vertexBindingDescriptions = vidBindings vertexDescription
, Vk.vertexAttributeDescriptions = vidAttributes vertexDescription
}
viewport = Vk.Viewport
{ Vk.x = 0
, Vk.y = 0
, Vk.width = fromIntegral width
, Vk.height = fromIntegral height
, Vk.minDepth = 0
, Vk.maxDepth = 1
}
scissor = Vk.Rect2D
{ Vk.offset = Vk.Offset2D 0 0
, Vk.extent = Vk.Extent2D (fromIntegral width) (fromIntegral height)
}
pipelineViewportStateCreateInfo = Vk.zero
{ Vk.viewports = V.singleton viewport
, Vk.scissors = V.singleton scissor
}
colorBlendAttachment = Vk.zero
{ Vk.colorWriteMask =
Vk.COLOR_COMPONENT_R_BIT .|.
Vk.COLOR_COMPONENT_G_BIT .|.
Vk.COLOR_COMPONENT_B_BIT .|.
Vk.COLOR_COMPONENT_A_BIT
, Vk.blendEnable = True
, Vk.srcColorBlendFactor = Vk.BLEND_FACTOR_ONE
, Vk.dstColorBlendFactor = Vk.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
, Vk.colorBlendOp = Vk.BLEND_OP_ADD
, Vk.srcAlphaBlendFactor = Vk.BLEND_FACTOR_ONE
, Vk.dstAlphaBlendFactor = Vk.BLEND_FACTOR_ZERO
, Vk.alphaBlendOp = Vk.BLEND_OP_ADD
}
pipelineColorBlendStateCreateInfo = Vk.zero
{ Vk.logicOpEnable = False
, Vk.attachments = V.singleton colorBlendAttachment
}
2022-07-16 19:50:22 +00:00
pipelineCreateInfo = Vk.zero
2022-12-02 19:34:35 +00:00
{ Vk.stageCount = fromIntegral (V.length pipelineStagesCreateInfos)
, Vk.stages = pipelineStagesCreateInfos
2022-07-13 01:41:33 +00:00
, Vk.vertexInputState = Just $ Vk.SomeStruct pipelineVertexInputCreateInfo
2022-07-21 21:12:54 +00:00
, Vk.inputAssemblyState =
Just $ createVertexInputAssemblyStateCreateInfo VK.PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
, Vk.viewportState = Just $ Vk.SomeStruct pipelineViewportStateCreateInfo
2022-07-21 21:12:54 +00:00
, Vk.rasterizationState = Just $ createRasterizationStateCreateInfo Vk.POLYGON_MODE_FILL
2022-12-02 19:02:01 +00:00
, Vk.multisampleState = Just createMultisampleStateCreateInfo
, Vk.colorBlendState = Just $ Vk.SomeStruct pipelineColorBlendStateCreateInfo
, Vk.dynamicState = Just pipelineDynamicStateCreateInfo
2022-12-28 03:18:54 +00:00
, Vk.depthStencilState = depthState
, Vk.layout = pipelineLayout
2022-07-16 19:50:22 +00:00
, Vk.renderPass = renderPass
, Vk.subpass = 0
, Vk.basePipelineHandle = Vk.NULL_HANDLE
, Vk.basePipelineIndex = -1
}
2023-01-05 22:07:21 +00:00
pipeline <- snd <$> allocate
(do
(result, pipelines) <- Vk.createGraphicsPipelines
logicalDevice
Vk.NULL_HANDLE
2023-01-05 22:07:21 +00:00
(V.singleton (Vk.SomeStruct pipelineCreateInfo))
Nothing
unless (result == Vk.SUCCESS) $
2022-12-02 19:02:01 +00:00
error "createGraphicsPipelines: Failed creating pipelines"
return pipelines
)
(\pipelines -> do
V.mapM_
(\pipeline -> do
putStrLn "destroying pipeline"
Vk.destroyPipeline logicalDevice pipeline Nothing
)
pipelines
)
2023-01-05 22:07:21 +00:00
let material = Material (V.head pipeline) pipelineLayout
matLibraryTMVar <- asks materialLibrary
matLibrary <- liftIO $ STM.atomically $ STM.readTMVar matLibraryTMVar
let newMatLibrary = M.insert "defaultMesh" material matLibrary
void $ liftIO $ STM.atomically $ STM.swapTMVar matLibraryTMVar newMatLibrary
2022-07-16 19:50:22 +00:00
createPipelineLayout
:: MonadResource m
=> Vk.Device
-> m Vk.PipelineLayout
createPipelineLayout logicalDevice = do
let pipelineLayoutCreateInfo = Vk.zero
snd <$> allocate
(Vk.createPipelineLayout logicalDevice pipelineLayoutCreateInfo Nothing)
(\pipelineLayout -> do
putStrLn "destroying pipeline layout"
Vk.destroyPipelineLayout logicalDevice pipelineLayout Nothing
)
2022-12-11 08:02:17 +00:00
createMeshPipelineLayout
:: MonadResource m
=> Vk.Device
-> m Vk.PipelineLayout
createMeshPipelineLayout logicalDevice = do
let pushConstantRange = Vk.zero
{ Vk.offset = 0
, Vk.size = fromIntegral (sizeOf (undefined :: MeshPushConstants))
, Vk.stageFlags = Vk.SHADER_STAGE_VERTEX_BIT
}
pipelineLayoutCreateInfo = Vk.zero
{ Vk.pushConstantRanges = V.singleton pushConstantRange
}
snd <$> allocate
(Vk.createPipelineLayout logicalDevice pipelineLayoutCreateInfo Nothing)
(\pipelineLayout -> do
putStrLn "destroying pipeline layout"
Vk.destroyPipelineLayout logicalDevice pipelineLayout Nothing
)