2022-07-13 17:29:38 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
|
|
|
{-# LANGUAGE DataKinds #-}
|
2023-01-05 22:07:21 +00:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2022-07-13 17:29:38 +00:00
|
|
|
module CommandBuffer where
|
|
|
|
|
2023-01-05 22:07:21 +00:00
|
|
|
import qualified Control.Concurrent.STM as STM
|
2022-07-13 17:29:38 +00:00
|
|
|
import Control.Monad
|
2022-12-11 08:02:17 +00:00
|
|
|
import Control.Monad.IO.Class
|
2023-01-05 22:07:21 +00:00
|
|
|
import Control.Monad.Reader
|
2022-07-13 17:29:38 +00:00
|
|
|
import Control.Monad.Trans.Resource
|
2023-01-05 22:07:21 +00:00
|
|
|
import qualified Data.Map.Strict as M
|
2022-07-13 17:29:38 +00:00
|
|
|
import qualified Data.Vector as V
|
2023-04-12 11:41:00 +00:00
|
|
|
import Foreign hiding (void)
|
2022-07-13 17:29:38 +00:00
|
|
|
import Foreign.C.Types (CInt)
|
|
|
|
import Linear
|
|
|
|
import qualified Vulkan as Vk
|
|
|
|
import qualified Vulkan.Zero as Vk
|
2023-01-06 19:02:17 +00:00
|
|
|
import qualified VulkanMemoryAllocator as VMA
|
2022-07-13 17:29:38 +00:00
|
|
|
|
|
|
|
-- internal imports
|
|
|
|
|
2022-12-03 00:44:06 +00:00
|
|
|
import Types
|
2023-01-06 19:02:17 +00:00
|
|
|
import Memory
|
2023-04-02 08:46:02 +00:00
|
|
|
import Util
|
2023-05-16 09:14:46 +00:00
|
|
|
import Data.Maybe (fromMaybe)
|
2023-05-20 16:36:31 +00:00
|
|
|
import Mesh (compactDraws)
|
2022-07-13 17:29:38 +00:00
|
|
|
|
2023-01-06 15:54:30 +00:00
|
|
|
frameOverlap :: Int
|
|
|
|
frameOverlap = 2
|
|
|
|
|
2023-04-12 11:41:00 +00:00
|
|
|
maxObjects :: Int
|
|
|
|
maxObjects = 10000
|
|
|
|
|
2023-01-06 15:54:30 +00:00
|
|
|
createFrames
|
|
|
|
:: (MonadResource m, MonadFail m)
|
2023-05-15 10:10:02 +00:00
|
|
|
=> Vk.Device
|
2023-01-06 19:02:17 +00:00
|
|
|
-> VMA.Allocator
|
|
|
|
-> Vk.DescriptorPool
|
|
|
|
-> Vk.DescriptorSetLayout
|
2023-04-12 11:41:00 +00:00
|
|
|
-> Vk.DescriptorSetLayout
|
2023-05-15 10:10:02 +00:00
|
|
|
-> Word32
|
2023-01-06 15:54:30 +00:00
|
|
|
-> m (V.Vector FrameData, Vk.Queue)
|
2023-05-15 10:10:02 +00:00
|
|
|
createFrames
|
|
|
|
logicalDevice
|
|
|
|
allocator
|
|
|
|
descriptorPool
|
|
|
|
setLayout
|
|
|
|
objectSetLayout
|
|
|
|
queueFamilyIndex
|
|
|
|
= do
|
2022-07-13 17:29:38 +00:00
|
|
|
|
|
|
|
let poolCreateInfo = Vk.zero
|
|
|
|
{ Vk.flags = Vk.COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
|
|
|
|
, Vk.queueFamilyIndex = queueFamilyIndex
|
|
|
|
} :: Vk.CommandPoolCreateInfo
|
|
|
|
|
2022-07-14 05:02:10 +00:00
|
|
|
graphicsQueue <- Vk.getDeviceQueue logicalDevice queueFamilyIndex 0
|
|
|
|
|
2023-01-06 15:54:30 +00:00
|
|
|
frames <- V.mapM
|
2023-04-20 04:21:43 +00:00
|
|
|
(\_ -> do
|
2022-07-13 17:29:38 +00:00
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
commandPool <- snd <$>
|
|
|
|
(Vk.withCommandPool logicalDevice poolCreateInfo Nothing allocate)
|
2022-07-14 05:02:10 +00:00
|
|
|
|
2023-01-06 15:54:30 +00:00
|
|
|
let commandBufferAllocationInfo = Vk.zero
|
|
|
|
{ Vk.commandPool = commandPool
|
|
|
|
, Vk.level = Vk.COMMAND_BUFFER_LEVEL_PRIMARY
|
|
|
|
, Vk.commandBufferCount = 1
|
|
|
|
}
|
2022-07-13 17:29:38 +00:00
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
(_, commandBuffer) <- Vk.withCommandBuffers logicalDevice commandBufferAllocationInfo allocate
|
2023-01-06 15:54:30 +00:00
|
|
|
|
|
|
|
let semaphoreCreateInfo = Vk.zero
|
|
|
|
fenceCreateInfo = Vk.zero
|
|
|
|
{ Vk.flags = Vk.FENCE_CREATE_SIGNALED_BIT
|
|
|
|
} :: Vk.FenceCreateInfo '[]
|
|
|
|
|
|
|
|
[presentSemaphore, renderSemaphore] <- replicateM 2
|
2023-04-29 00:10:27 +00:00
|
|
|
(snd <$>
|
|
|
|
Vk.withSemaphore logicalDevice semaphoreCreateInfo Nothing allocate
|
2023-01-06 15:54:30 +00:00
|
|
|
)
|
2023-04-29 00:10:27 +00:00
|
|
|
renderFence <- snd <$>
|
|
|
|
Vk.withFence logicalDevice fenceCreateInfo Nothing allocate
|
2023-01-06 15:54:30 +00:00
|
|
|
|
2023-01-06 19:02:17 +00:00
|
|
|
cameraBuffer <- createAllocatedBuffer
|
|
|
|
allocator
|
|
|
|
(sizeOf (GPUCameraData identity identity identity))
|
|
|
|
Vk.BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
|
|
|
VMA.MEMORY_USAGE_CPU_TO_GPU
|
|
|
|
|
2023-04-12 11:41:00 +00:00
|
|
|
sceneBuffer <- createAllocatedBuffer
|
|
|
|
allocator
|
|
|
|
(sizeOf undefinedGPUSceneData * frameOverlap)
|
|
|
|
Vk.BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
|
|
|
VMA.MEMORY_USAGE_CPU_TO_GPU
|
|
|
|
|
|
|
|
objectBuffer <- createAllocatedBuffer
|
|
|
|
allocator
|
|
|
|
(sizeOf undefinedGPUObjectData * maxObjects)
|
|
|
|
Vk.BUFFER_USAGE_STORAGE_BUFFER_BIT
|
|
|
|
VMA.MEMORY_USAGE_CPU_TO_GPU
|
2023-01-06 19:02:17 +00:00
|
|
|
|
|
|
|
let allocationInfo = Vk.zero
|
|
|
|
{ Vk.descriptorPool = descriptorPool
|
|
|
|
, Vk.setLayouts = V.singleton setLayout
|
|
|
|
}
|
2023-04-12 11:41:00 +00:00
|
|
|
objectSetAllocInfo = Vk.zero
|
|
|
|
{ Vk.descriptorPool = descriptorPool
|
|
|
|
, Vk.setLayouts = V.singleton objectSetLayout
|
|
|
|
}
|
2023-01-06 19:02:17 +00:00
|
|
|
|
|
|
|
globalDescriptor <- Vk.allocateDescriptorSets logicalDevice allocationInfo
|
2023-04-12 11:41:00 +00:00
|
|
|
objectDescriptor <- Vk.allocateDescriptorSets logicalDevice objectSetAllocInfo
|
2023-01-06 19:02:17 +00:00
|
|
|
|
2023-04-02 08:46:02 +00:00
|
|
|
let cameraInfo = Vk.zero
|
2023-01-06 19:02:17 +00:00
|
|
|
{ Vk.buffer = allocatedBuffer cameraBuffer
|
|
|
|
, Vk.offset = 0
|
2023-05-12 11:30:00 +00:00
|
|
|
, Vk.range = fromIntegral $ sizeOf (undefined :: GPUCameraData)
|
2023-01-06 19:02:17 +00:00
|
|
|
} :: Vk.DescriptorBufferInfo
|
2023-04-02 08:46:02 +00:00
|
|
|
sceneInfo = Vk.zero
|
2023-04-12 11:41:00 +00:00
|
|
|
{ Vk.buffer = allocatedBuffer sceneBuffer
|
|
|
|
, Vk.offset = 0
|
|
|
|
-- , Vk.offset = padUniformBufferSize (fromIntegral $ sizeOf undefinedGPUSceneData) deviceProperties * fromIntegral index
|
|
|
|
, Vk.range = fromIntegral $ sizeOf undefinedGPUSceneData
|
|
|
|
} :: Vk.DescriptorBufferInfo
|
|
|
|
objectInfo = Vk.zero
|
|
|
|
{ Vk.buffer = allocatedBuffer objectBuffer
|
|
|
|
, Vk.offset = 0
|
|
|
|
, Vk.range = fromIntegral $ sizeOf undefinedGPUObjectData * maxObjects
|
2023-04-02 08:46:02 +00:00
|
|
|
} :: Vk.DescriptorBufferInfo
|
|
|
|
cameraWrite = writeDescriptorBuffer
|
|
|
|
Vk.DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
|
|
|
(V.head globalDescriptor)
|
|
|
|
cameraInfo
|
|
|
|
0
|
|
|
|
sceneWrite = writeDescriptorBuffer
|
2023-05-12 11:30:00 +00:00
|
|
|
Vk.DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
2023-04-02 08:46:02 +00:00
|
|
|
(V.head globalDescriptor)
|
|
|
|
sceneInfo
|
|
|
|
1
|
2023-04-12 11:41:00 +00:00
|
|
|
objectWrite = writeDescriptorBuffer
|
|
|
|
Vk.DESCRIPTOR_TYPE_STORAGE_BUFFER
|
|
|
|
(V.head objectDescriptor)
|
|
|
|
objectInfo
|
|
|
|
0
|
2023-04-02 08:46:02 +00:00
|
|
|
setWrites = V.fromList
|
|
|
|
[ cameraWrite
|
|
|
|
, sceneWrite
|
2023-04-12 11:41:00 +00:00
|
|
|
, objectWrite
|
2023-04-02 08:46:02 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
Vk.updateDescriptorSets logicalDevice setWrites V.empty
|
2023-01-06 19:02:17 +00:00
|
|
|
|
2023-01-06 15:54:30 +00:00
|
|
|
return FrameData
|
|
|
|
{ framePresentSemaphore = presentSemaphore
|
|
|
|
, frameRenderSemaphore = renderSemaphore
|
|
|
|
, frameRenderFence = renderFence
|
|
|
|
, frameCommandPool = commandPool
|
|
|
|
, frameMainCommandBuffer = V.head commandBuffer
|
2023-01-06 19:02:17 +00:00
|
|
|
, frameCameraBuffer = cameraBuffer
|
2023-04-19 15:26:33 +00:00
|
|
|
, frameSceneBuffer = sceneBuffer
|
2023-04-12 11:41:00 +00:00
|
|
|
, frameObjectBuffer = objectBuffer
|
2023-01-06 19:02:17 +00:00
|
|
|
, frameGlobalDescriptor = V.head globalDescriptor
|
2023-04-12 11:41:00 +00:00
|
|
|
, frameObjectDescriptor = V.head objectDescriptor
|
2022-07-13 17:29:38 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 15:54:30 +00:00
|
|
|
)
|
|
|
|
(V.fromList [1 .. frameOverlap])
|
|
|
|
|
|
|
|
return (frames, graphicsQueue)
|
2022-07-13 17:29:38 +00:00
|
|
|
|
|
|
|
recordCommandBuffer
|
2023-01-05 22:07:21 +00:00
|
|
|
:: (MonadResource m, MonadReader ReadState m, MonadIO m)
|
2022-07-13 17:29:38 +00:00
|
|
|
=> Vk.CommandBuffer
|
|
|
|
-> Vk.RenderPass
|
|
|
|
-> Vk.Framebuffer
|
|
|
|
-> V2 CInt
|
|
|
|
-> Vk.Pipeline
|
2023-01-06 19:02:17 +00:00
|
|
|
-> FrameData
|
2022-07-13 17:29:38 +00:00
|
|
|
-> m ()
|
2022-12-03 00:44:06 +00:00
|
|
|
recordCommandBuffer
|
|
|
|
commandBuffer
|
|
|
|
renderPass
|
|
|
|
frameBuffer
|
2023-04-29 17:54:52 +00:00
|
|
|
dimensions@(V2 width height)
|
2022-12-03 00:44:06 +00:00
|
|
|
graphicsPipeline
|
2023-01-06 19:02:17 +00:00
|
|
|
frame
|
2022-12-03 00:44:06 +00:00
|
|
|
= do
|
|
|
|
|
|
|
|
let commandBufferBeginInfo = Vk.zero
|
|
|
|
{ Vk.flags = Vk.COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
|
|
|
|
, Vk.inheritanceInfo = Nothing
|
|
|
|
}
|
2022-07-13 17:29:38 +00:00
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
Vk.useCommandBuffer commandBuffer commandBufferBeginInfo $ do
|
|
|
|
|
|
|
|
let renderPassInfo = Vk.zero
|
|
|
|
{ Vk.renderPass = renderPass
|
|
|
|
, Vk.framebuffer = frameBuffer
|
|
|
|
, Vk.renderArea = Vk.Rect2D
|
|
|
|
{ offset = Vk.Offset2D
|
|
|
|
{ Vk.x = 0
|
|
|
|
, Vk.y = 0
|
|
|
|
}
|
|
|
|
, extent = Vk.Extent2D
|
|
|
|
{ Vk.width = fromIntegral width
|
|
|
|
, Vk.height = fromIntegral height
|
|
|
|
}
|
2022-12-03 00:44:06 +00:00
|
|
|
}
|
2023-04-29 00:10:27 +00:00
|
|
|
, Vk.clearValues = V.fromList
|
|
|
|
[ Vk.Color (Vk.Float32 0 0 0 1)
|
|
|
|
, Vk.DepthStencil (Vk.ClearDepthStencilValue 1 0)
|
|
|
|
]
|
2022-12-03 00:44:06 +00:00
|
|
|
}
|
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
Vk.cmdUseRenderPass commandBuffer renderPassInfo Vk.SUBPASS_CONTENTS_INLINE $ do
|
2022-07-13 17:29:38 +00:00
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
liftIO $
|
2023-04-29 17:54:52 +00:00
|
|
|
prepareRecording dimensions commandBuffer graphicsPipeline
|
2022-07-13 17:29:38 +00:00
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
renderObjects <- (liftIO . STM.atomically . STM.readTMVar) =<< asks renderables
|
|
|
|
meshMap <- (liftIO . STM.atomically . STM.readTMVar) =<< asks meshLibrary
|
2023-05-20 16:36:31 +00:00
|
|
|
materialMap <- (liftIO . STM.atomically . STM.readTMVar) =<< asks materialLibrary
|
2023-04-29 00:10:27 +00:00
|
|
|
|
2023-05-20 16:36:31 +00:00
|
|
|
let draws = compactDraws meshMap materialMap renderObjects
|
2023-04-29 00:10:27 +00:00
|
|
|
|
2023-05-20 16:36:31 +00:00
|
|
|
V.mapM_
|
|
|
|
(\(IndirectBatch mesh material first count) -> do
|
2023-05-16 09:14:46 +00:00
|
|
|
|
|
|
|
when
|
|
|
|
(materialTextureSet material /= Vk.NULL_HANDLE)
|
|
|
|
(Vk.cmdBindDescriptorSets
|
|
|
|
commandBuffer
|
|
|
|
Vk.PIPELINE_BIND_POINT_GRAPHICS
|
|
|
|
(materialPipelineLayout material)
|
|
|
|
2
|
|
|
|
(V.singleton $ materialTextureSet material)
|
|
|
|
V.empty
|
|
|
|
)
|
2023-04-29 00:10:27 +00:00
|
|
|
|
|
|
|
Vk.cmdBindPipeline commandBuffer Vk.PIPELINE_BIND_POINT_GRAPHICS (materialPipeline material)
|
|
|
|
|
|
|
|
Vk.cmdBindDescriptorSets
|
|
|
|
commandBuffer
|
|
|
|
Vk.PIPELINE_BIND_POINT_GRAPHICS
|
|
|
|
(materialPipelineLayout material)
|
|
|
|
0
|
|
|
|
(V.singleton $ frameGlobalDescriptor frame)
|
|
|
|
V.empty
|
|
|
|
|
|
|
|
Vk.cmdBindDescriptorSets
|
|
|
|
commandBuffer
|
|
|
|
Vk.PIPELINE_BIND_POINT_GRAPHICS
|
|
|
|
(materialPipelineLayout material)
|
|
|
|
1
|
|
|
|
(V.singleton $ frameObjectDescriptor frame)
|
|
|
|
V.empty
|
|
|
|
|
|
|
|
Vk.cmdBindVertexBuffers
|
|
|
|
commandBuffer
|
|
|
|
0
|
|
|
|
(V.fromList [ allocatedBuffer $ meshBuffer mesh ])
|
|
|
|
(V.fromList [ 0 ])
|
|
|
|
|
2023-05-20 16:36:31 +00:00
|
|
|
mapM_
|
2023-05-20 16:36:31 +00:00
|
|
|
(\index ->
|
|
|
|
Vk.cmdDraw commandBuffer (fromIntegral $ V.length $ meshVertices mesh) 1 0 index
|
|
|
|
)
|
|
|
|
([first .. first + count])
|
2023-04-29 00:10:27 +00:00
|
|
|
)
|
2023-05-20 16:36:31 +00:00
|
|
|
draws
|
2022-07-13 17:29:38 +00:00
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
prepareRecording
|
2023-04-29 17:54:52 +00:00
|
|
|
:: V2 CInt
|
2023-04-29 00:10:27 +00:00
|
|
|
-> Vk.CommandBuffer
|
|
|
|
-> Vk.Pipeline
|
|
|
|
-> IO ()
|
2023-04-29 17:54:52 +00:00
|
|
|
prepareRecording (V2 width height) commandBuffer graphicsPipeline = do
|
2023-04-29 00:10:27 +00:00
|
|
|
Vk.cmdBindPipeline commandBuffer Vk.PIPELINE_BIND_POINT_GRAPHICS graphicsPipeline
|
|
|
|
|
2023-05-17 03:52:41 +00:00
|
|
|
-- Passing negative height and nonzero y origin to the viewport flips the models back in order
|
2023-04-29 00:10:27 +00:00
|
|
|
let viewport = Vk.zero
|
|
|
|
{ Vk.x = 0
|
2023-05-17 03:52:41 +00:00
|
|
|
, Vk.y = fromIntegral height
|
2023-04-29 00:10:27 +00:00
|
|
|
, Vk.width = fromIntegral width
|
2023-05-17 03:52:41 +00:00
|
|
|
, Vk.height = - fromIntegral height
|
2023-04-29 00:10:27 +00:00
|
|
|
, Vk.minDepth = 0
|
|
|
|
, Vk.maxDepth = 1
|
|
|
|
}
|
|
|
|
scissor = Vk.Rect2D
|
|
|
|
{ Vk.offset = Vk.Offset2D
|
|
|
|
{ Vk.x = 0
|
|
|
|
, Vk.y = 0
|
2023-04-12 11:41:00 +00:00
|
|
|
}
|
2023-04-29 00:10:27 +00:00
|
|
|
, Vk.extent = Vk.Extent2D
|
|
|
|
{ Vk.width = fromIntegral width
|
|
|
|
, Vk.height = fromIntegral height
|
|
|
|
}
|
|
|
|
}
|
2023-04-02 08:46:02 +00:00
|
|
|
|
2023-04-29 00:10:27 +00:00
|
|
|
Vk.cmdSetViewport commandBuffer 0 (V.singleton viewport)
|
|
|
|
Vk.cmdSetScissor commandBuffer 0 (V.singleton scissor)
|
2023-04-29 16:41:59 +00:00
|
|
|
|
|
|
|
pokeData
|
2023-05-12 11:30:00 +00:00
|
|
|
:: (MonadResource m, MonadReader ReadState m, MonadIO m)
|
|
|
|
=> FrameData
|
2023-04-29 16:41:59 +00:00
|
|
|
-> Int
|
|
|
|
-> GPUSceneData
|
2023-04-29 16:52:49 +00:00
|
|
|
-> GPUCameraData
|
2023-05-12 11:30:00 +00:00
|
|
|
-> m ()
|
2023-04-29 16:52:49 +00:00
|
|
|
pokeData frame frameNumber sceneParameters cameraParameters = do
|
2023-05-12 11:30:00 +00:00
|
|
|
renderObjects <- (liftIO . STM.atomically . STM.readTMVar) =<< asks renderables
|
|
|
|
|
2023-04-29 16:41:59 +00:00
|
|
|
let scenePointer = VMA.mappedData (bufferInfo $ frameSceneBuffer frame)
|
|
|
|
memoryPointer = VMA.mappedData (bufferInfo $ frameCameraBuffer frame)
|
2023-05-12 11:30:00 +00:00
|
|
|
objectPointer = VMA.mappedData (bufferInfo $ frameObjectBuffer frame)
|
2023-04-29 16:41:59 +00:00
|
|
|
framed = fromIntegral frameNumber / 120
|
|
|
|
ambient = normalize $ V4 (sin framed) 0 (cos framed) 1
|
|
|
|
-- ambient = V4 1 0 1 1
|
|
|
|
ambientParams = sceneParameters
|
|
|
|
{ ambientColor = ambient
|
|
|
|
}
|
|
|
|
|
2023-05-12 11:30:00 +00:00
|
|
|
V.mapM_
|
|
|
|
(\(index, obj) -> do
|
|
|
|
|
2023-05-14 08:18:09 +00:00
|
|
|
let modelMatrix = GPUObjectData (objectMatrix obj)
|
2023-05-12 11:30:00 +00:00
|
|
|
|
|
|
|
liftIO $ poke
|
2023-05-12 12:56:02 +00:00
|
|
|
(castPtr objectPointer `plusPtr` (index * sizeOf (undefined :: GPUObjectData)))
|
2023-05-12 11:30:00 +00:00
|
|
|
modelMatrix
|
|
|
|
)
|
|
|
|
(V.zip
|
|
|
|
(V.fromList [0 ..])
|
|
|
|
renderObjects
|
|
|
|
)
|
|
|
|
|
|
|
|
liftIO $ do
|
|
|
|
poke
|
|
|
|
(castPtr scenePointer)
|
|
|
|
ambientParams
|
2023-04-29 16:41:59 +00:00
|
|
|
|
2023-05-12 11:30:00 +00:00
|
|
|
poke
|
|
|
|
(castPtr memoryPointer)
|
|
|
|
cameraParameters
|