keid-render-basic-0.1.0.0: src/Render/ForwardMsaa.hs
module Render.ForwardMsaa where
import RIO
import Control.Monad.Trans.Resource qualified as Resource
import Data.Bits ((.|.))
import Data.Vector qualified as Vector
import RIO.Vector.Partial ((!))
import Vulkan.Core10 qualified as Vk
import Vulkan.Utils.Debug qualified as Debug
import Vulkan.Zero (zero)
import Engine.Types.RefCounted (RefCounted, newRefCounted, releaseRefCounted, resourceTRefCount)
import Engine.Vulkan.Types (HasVulkan(..), HasSwapchain(..), HasRenderPass(..), RenderPass(..), MonadVulkan)
import Resource.Image (AllocatedImage)
import Resource.Image qualified as Image
-- * Simple MSAA-enabled pass
data ForwardMsaa = ForwardMsaa
{ fmRenderPass :: Vk.RenderPass
, fmColor :: AllocatedImage
, fmDepth :: AllocatedImage
, fmFrameBuffers :: Vector Vk.Framebuffer
, fmRenderArea :: Vk.Rect2D
, fmClear :: Vector Vk.ClearValue
, fmRelease :: RefCounted
}
instance HasRenderPass ForwardMsaa where
getRenderPass = fmRenderPass
getFramebuffers = fmFrameBuffers
getClearValues = fmClear
getRenderArea = fmRenderArea
instance RenderPass ForwardMsaa where
allocateRenderpass_ = allocateMsaa -- error "Thou shalt allocateMsaa instead"
updateRenderpass = updateMsaa
refcountRenderpass = resourceTRefCount . fmRelease
allocateMsaa
:: ( Resource.MonadResource m
, MonadVulkan env m
, HasLogFunc env
, HasSwapchain context
)
=> context
-> m ForwardMsaa
allocateMsaa context = do
logDebug "Allocating ForwardMsaa resources"
(_rpKey, renderPass) <- allocateRenderPassMsaa context
(refcounted, color, depth, framebuffers) <- allocateFramebufferMsaa context renderPass
pure ForwardMsaa
{ fmRenderPass = renderPass
, fmRenderArea = fullSurface
, fmClear = clear
, fmColor = color
, fmDepth = depth
, fmFrameBuffers = framebuffers
, fmRelease = refcounted
}
where
fullSurface = Vk.Rect2D
{ Vk.offset = zero
, Vk.extent = getSurfaceExtent context
}
clear = Vector.fromList
[ clearColor
, Vk.DepthStencil (Vk.ClearDepthStencilValue 1.0 0)
, clearColor
]
clearColor = Vk.Color zero
updateMsaa
:: ( Resource.MonadResource m
, MonadVulkan env m
, HasLogFunc env
, HasSwapchain context
)
=> context
-> ForwardMsaa
-> m ForwardMsaa
updateMsaa context old@ForwardMsaa{fmRelease, fmRenderPass} = do
releaseRefCounted fmRelease
(refcounted, color, depth, framebuffers) <- allocateFramebufferMsaa context fmRenderPass
pure old
{ fmColor = color
, fmDepth = depth
, fmFrameBuffers = framebuffers
, fmRelease = refcounted
, fmRenderArea = fullSurface
}
where
fullSurface = Vk.Rect2D
{ Vk.offset = zero
, Vk.extent = getSurfaceExtent context
}
-- ** Render pass
allocateRenderPassMsaa
:: ( MonadVulkan env m
, Resource.MonadResource m
, HasSwapchain context
)
=> context
-> m (Resource.ReleaseKey, Vk.RenderPass)
allocateRenderPassMsaa context = do
device <- asks getDevice
let
format = getSurfaceFormat context
depthFormat = getDepthFormat context
msaa = getMultisample context
attachments =
[ color format msaa
, depth depthFormat msaa
, colorResolve format
]
res@(_key, object) <- Vk.withRenderPass device (createInfo attachments) Nothing Resource.allocate
Debug.nameObject device object "ForwardMSAA"
pure res
where
createInfo attachments = zero
{ Vk.attachments = Vector.fromList attachments
, Vk.subpasses = Vector.fromList [subpass]
, Vk.dependencies = Vector.fromList [colorDeps, depthDeps]
}
color format msaa = zero
{ Vk.format = format
, Vk.samples = msaa
, Vk.finalLayout = Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
, Vk.loadOp = Vk.ATTACHMENT_LOAD_OP_CLEAR
, Vk.storeOp = Vk.ATTACHMENT_STORE_OP_DONT_CARE
, Vk.stencilLoadOp = Vk.ATTACHMENT_LOAD_OP_DONT_CARE
, Vk.stencilStoreOp = Vk.ATTACHMENT_STORE_OP_DONT_CARE
, Vk.initialLayout = Vk.IMAGE_LAYOUT_UNDEFINED
}
depth format msaa = zero
{ Vk.format = format
, Vk.samples = msaa
, Vk.loadOp = Vk.ATTACHMENT_LOAD_OP_CLEAR
, Vk.storeOp = Vk.ATTACHMENT_STORE_OP_DONT_CARE
, 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_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
}
colorResolve format = zero
{ Vk.format = format
, Vk.samples = Vk.SAMPLE_COUNT_1_BIT
, Vk.finalLayout = Vk.IMAGE_LAYOUT_PRESENT_SRC_KHR
, Vk.loadOp = Vk.ATTACHMENT_LOAD_OP_DONT_CARE
}
subpass = zero
{ Vk.pipelineBindPoint = Vk.PIPELINE_BIND_POINT_GRAPHICS
, Vk.colorAttachments = Vector.singleton zero
{ Vk.attachment = 0
, Vk.layout = Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
}
, Vk.depthStencilAttachment = Just zero
{ Vk.attachment = 1
, Vk.layout = Vk.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
}
, Vk.resolveAttachments = Vector.singleton zero
{ Vk.attachment = 2
, Vk.layout = Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
}
}
colorDeps = zero
{ Vk.srcSubpass = Vk.SUBPASS_EXTERNAL
, Vk.dstSubpass = 0
, Vk.srcStageMask = colorOut
, Vk.srcAccessMask = zero
, Vk.dstStageMask = colorOut
, Vk.dstAccessMask = colorRW
}
where
colorOut =
Vk.PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
colorRW =
Vk.ACCESS_COLOR_ATTACHMENT_READ_BIT .|.
Vk.ACCESS_COLOR_ATTACHMENT_WRITE_BIT
depthDeps = zero
{ Vk.srcSubpass = Vk.SUBPASS_EXTERNAL
, Vk.dstSubpass = 0
, Vk.srcStageMask = fragTests
, Vk.srcAccessMask = depthW
, Vk.dstStageMask = fragTests
, Vk.dstAccessMask = depthRW
}
where
fragTests =
Vk.PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT .|.
Vk.PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
depthW =
Vk.ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
depthRW =
Vk.ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT .|.
depthW
-- ** Framebuffer
type FramebuffersMsaa =
( RefCounted
, Image.AllocatedImage
, Image.AllocatedImage
, Vector Vk.Framebuffer
)
allocateFramebufferMsaa
:: ( Resource.MonadResource m
, MonadVulkan env m
, HasLogFunc env
, HasSwapchain context
)
=> context
-> Vk.RenderPass
-> m FramebuffersMsaa
allocateFramebufferMsaa context renderPass = do
device <- asks getDevice
context' <- asks (, context)
let extent@Vk.Extent2D{width, height} = getSurfaceExtent context
(colorKey, color) <- Resource.allocate
(Image.createColorResource context' extent)
(Image.destroyAllocatedImage context')
(depthKey, depth) <- Resource.allocate
(Image.createDepthResource context' extent Nothing)
(Image.destroyAllocatedImage context')
perView <- for (getSwapchainViews context) \colorResolve -> do
let
attachments = Vector.fromList
[ Image.aiImageView color
, Image.aiImageView depth
, colorResolve
]
fbCI = zero
{ Vk.renderPass = renderPass
, Vk.width = width
, Vk.height = height
, Vk.attachments = attachments
, Vk.layers = 1
}
Vk.withFramebuffer device fbCI Nothing Resource.allocate
let (framebufferKeys, framebuffers) = Vector.unzip perView
releaseDebug <- toIO $ logDebug "Releasing ForwardMsaa resources"
release <- newRefCounted do
releaseDebug
Resource.release colorKey
Resource.release depthKey
traverse_ Resource.release framebufferKeys
pure (release, color, depth, framebuffers)
usePass :: (MonadIO io, HasRenderPass a) => a -> Word32 -> Vk.CommandBuffer -> io r -> io r
usePass render imageIndex cb =
Vk.cmdUseRenderPass
cb
(beginInfo render imageIndex)
Vk.SUBPASS_CONTENTS_INLINE
beginInfo :: HasRenderPass a => a -> Word32 -> Vk.RenderPassBeginInfo '[]
beginInfo rp imageIndex = zero
{ Vk.renderPass = getRenderPass rp
, Vk.framebuffer = getFramebuffers rp ! fromIntegral imageIndex
, Vk.renderArea = getRenderArea rp
, Vk.clearValues = getClearValues rp
}