module Render.ForwardMsaa
  ( ForwardMsaa(..)
  , allocateMsaa
  , updateMsaa
  , usePass
  ) where

import RIO

import Control.Monad.Trans.Resource qualified as Resource
import Data.Bits ((.|.))
import Data.Vector qualified as Vector
import Vulkan.Core10 qualified as Vk
import Vulkan.Zero (zero)

import Engine.Types.RefCounted (RefCounted, releaseRefCounted, resourceTRefCount)
import Engine.Types.RefCounted qualified as RefCounted
import Engine.Vulkan.Types (HasVulkan(..), HasSwapchain(..), HasRenderPass(..), RenderPass(..), MonadVulkan)
import Render.Pass (usePass)
import Resource.Image (AllocatedImage)
import Resource.Image qualified as Image
import Resource.Region qualified as Region
import Resource.Vulkan.Named qualified as Named

-- * Simple MSAA-enabled pass

data ForwardMsaa = ForwardMsaa
  { ForwardMsaa -> RenderPass
fmRenderPass   :: Vk.RenderPass
  , ForwardMsaa -> AllocatedImage
fmColor        :: AllocatedImage
  , ForwardMsaa -> AllocatedImage
fmDepth        :: AllocatedImage
  , ForwardMsaa -> Vector Framebuffer
fmFrameBuffers :: Vector Vk.Framebuffer
  , ForwardMsaa -> Rect2D
fmRenderArea   :: Vk.Rect2D
  , ForwardMsaa -> Vector ClearValue
fmClear        :: Vector Vk.ClearValue
  , ForwardMsaa -> RefCounted
fmRelease      :: RefCounted
  }

instance HasRenderPass ForwardMsaa where
  getRenderPass :: ForwardMsaa -> RenderPass
getRenderPass   = ForwardMsaa -> RenderPass
fmRenderPass
  getFramebuffers :: ForwardMsaa -> Vector Framebuffer
getFramebuffers = ForwardMsaa -> Vector Framebuffer
fmFrameBuffers
  getClearValues :: ForwardMsaa -> Vector ClearValue
getClearValues  = ForwardMsaa -> Vector ClearValue
fmClear
  getRenderArea :: ForwardMsaa -> Rect2D
getRenderArea   = ForwardMsaa -> Rect2D
fmRenderArea

instance RenderPass ForwardMsaa where
  updateRenderpass :: forall env swapchain.
(HasLogFunc env, HasSwapchain swapchain, HasVulkan env,
 MonadResource (RIO env)) =>
swapchain -> ForwardMsaa -> RIO env ForwardMsaa
updateRenderpass = swapchain -> ForwardMsaa -> RIO env ForwardMsaa
forall (m :: * -> *) env swapchain.
(MonadResource m, MonadVulkan env m, HasLogFunc env,
 HasSwapchain swapchain) =>
swapchain -> ForwardMsaa -> m ForwardMsaa
updateMsaa
  refcountRenderpass :: forall env. MonadResource (RIO env) => ForwardMsaa -> RIO env ()
refcountRenderpass = RefCounted -> RIO env ()
forall (f :: * -> *). MonadResource f => RefCounted -> f ()
resourceTRefCount (RefCounted -> RIO env ())
-> (ForwardMsaa -> RefCounted) -> ForwardMsaa -> RIO env ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ForwardMsaa -> RefCounted
fmRelease

allocateMsaa
  :: ( Resource.MonadResource m
     , MonadVulkan env m
     , HasLogFunc env
     , HasSwapchain swapchain
     )
  => swapchain
  -> m ForwardMsaa
allocateMsaa :: forall (m :: * -> *) env swapchain.
(MonadResource m, MonadVulkan env m, HasLogFunc env,
 HasSwapchain swapchain) =>
swapchain -> m ForwardMsaa
allocateMsaa swapchain
swapchain = do
  (ReleaseKey
_rpKey, RenderPass
renderPass) <- swapchain -> m (ReleaseKey, RenderPass)
forall env (m :: * -> *) swapchain.
(MonadVulkan env m, MonadResource m, HasSwapchain swapchain) =>
swapchain -> m (ReleaseKey, RenderPass)
allocateRenderPassMsaa swapchain
swapchain

  (RefCounted
release, FramebuffersMsaa
resources) <- m (ReleaseKey, FramebuffersMsaa)
-> m (RefCounted, FramebuffersMsaa)
forall (m :: * -> *) a.
MonadResource m =>
m (ReleaseKey, a) -> m (RefCounted, a)
RefCounted.wrapped (m (ReleaseKey, FramebuffersMsaa)
 -> m (RefCounted, FramebuffersMsaa))
-> m (ReleaseKey, FramebuffersMsaa)
-> m (RefCounted, FramebuffersMsaa)
forall a b. (a -> b) -> a -> b
$ ResourceT m FramebuffersMsaa -> m (ReleaseKey, FramebuffersMsaa)
forall (m :: * -> *) a.
MonadResource m =>
ResourceT m a -> m (ReleaseKey, a)
Region.run do
    Utf8Builder -> Utf8Builder -> ResourceT m ()
forall (m :: * -> *) env.
(MonadUnliftIO m, MonadReader env m, HasLogFunc env,
 HasCallStack) =>
Utf8Builder -> Utf8Builder -> ResourceT m ()
Region.logDebug
      Utf8Builder
"Allocating ForwardMsaa resources"
      Utf8Builder
"Releasing ForwardMsaa resources"
    swapchain -> RenderPass -> ResourceT m FramebuffersMsaa
forall (m :: * -> *) env swapchain.
(MonadResource m, MonadVulkan env m, HasSwapchain swapchain) =>
swapchain -> RenderPass -> m FramebuffersMsaa
allocateFramebufferMsaa swapchain
swapchain RenderPass
renderPass
  let (AllocatedImage
color, AllocatedImage
depth, Vector Framebuffer
framebuffers) = FramebuffersMsaa
resources

  ForwardMsaa -> m ForwardMsaa
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ForwardMsaa
    { $sel:fmRenderPass:ForwardMsaa :: RenderPass
fmRenderPass   = RenderPass
renderPass
    , $sel:fmRenderArea:ForwardMsaa :: Rect2D
fmRenderArea   = Rect2D
fullSurface
    , $sel:fmClear:ForwardMsaa :: Vector ClearValue
fmClear        = Vector ClearValue
clear
    , $sel:fmColor:ForwardMsaa :: AllocatedImage
fmColor        = AllocatedImage
color
    , $sel:fmDepth:ForwardMsaa :: AllocatedImage
fmDepth        = AllocatedImage
depth
    , $sel:fmFrameBuffers:ForwardMsaa :: Vector Framebuffer
fmFrameBuffers = Vector Framebuffer
framebuffers
    , $sel:fmRelease:ForwardMsaa :: RefCounted
fmRelease      = RefCounted
release
    }
  where
    fullSurface :: Rect2D
fullSurface = Vk.Rect2D
      { $sel:offset:Rect2D :: Offset2D
Vk.offset = Offset2D
forall a. Zero a => a
zero
      , $sel:extent:Rect2D :: Extent2D
Vk.extent = swapchain -> Extent2D
forall a. HasSwapchain a => a -> Extent2D
getSurfaceExtent swapchain
swapchain
      }
    clear :: Vector ClearValue
clear = [ClearValue] -> Vector ClearValue
forall a. [a] -> Vector a
Vector.fromList
      [ ClearValue
clearColor
      , ClearDepthStencilValue -> ClearValue
Vk.DepthStencil (Float -> Word32 -> ClearDepthStencilValue
Vk.ClearDepthStencilValue Float
1.0 Word32
0)
      , ClearValue
clearColor
      ]
    clearColor :: ClearValue
clearColor = ClearColorValue -> ClearValue
Vk.Color ClearColorValue
forall a. Zero a => a
zero

updateMsaa
  :: ( Resource.MonadResource m
     , MonadVulkan env m
     , HasLogFunc env
     , HasSwapchain swapchain
     )
  => swapchain
  -> ForwardMsaa
  -> m ForwardMsaa
updateMsaa :: forall (m :: * -> *) env swapchain.
(MonadResource m, MonadVulkan env m, HasLogFunc env,
 HasSwapchain swapchain) =>
swapchain -> ForwardMsaa -> m ForwardMsaa
updateMsaa swapchain
swapchain old :: ForwardMsaa
old@ForwardMsaa{RefCounted
$sel:fmRelease:ForwardMsaa :: ForwardMsaa -> RefCounted
fmRelease :: RefCounted
fmRelease, RenderPass
$sel:fmRenderPass:ForwardMsaa :: ForwardMsaa -> RenderPass
fmRenderPass :: RenderPass
fmRenderPass} = do
  RefCounted -> m ()
forall (m :: * -> *). MonadIO m => RefCounted -> m ()
releaseRefCounted RefCounted
fmRelease
  (RefCounted
release, FramebuffersMsaa
resources) <- m (ReleaseKey, FramebuffersMsaa)
-> m (RefCounted, FramebuffersMsaa)
forall (m :: * -> *) a.
MonadResource m =>
m (ReleaseKey, a) -> m (RefCounted, a)
RefCounted.wrapped (m (ReleaseKey, FramebuffersMsaa)
 -> m (RefCounted, FramebuffersMsaa))
-> m (ReleaseKey, FramebuffersMsaa)
-> m (RefCounted, FramebuffersMsaa)
forall a b. (a -> b) -> a -> b
$ ResourceT m FramebuffersMsaa -> m (ReleaseKey, FramebuffersMsaa)
forall (m :: * -> *) a.
MonadResource m =>
ResourceT m a -> m (ReleaseKey, a)
Region.run do
    Utf8Builder -> Utf8Builder -> ResourceT m ()
forall (m :: * -> *) env.
(MonadUnliftIO m, MonadReader env m, HasLogFunc env,
 HasCallStack) =>
Utf8Builder -> Utf8Builder -> ResourceT m ()
Region.logDebug
      Utf8Builder
"Updating ForwardMsaa resources"
      Utf8Builder
"Releasing ForwardMsaa resources"
    swapchain -> RenderPass -> ResourceT m FramebuffersMsaa
forall (m :: * -> *) env swapchain.
(MonadResource m, MonadVulkan env m, HasSwapchain swapchain) =>
swapchain -> RenderPass -> m FramebuffersMsaa
allocateFramebufferMsaa swapchain
swapchain RenderPass
fmRenderPass
  let (AllocatedImage
color, AllocatedImage
depth, Vector Framebuffer
framebuffers) = FramebuffersMsaa
resources
  pure ForwardMsaa
old
    { $sel:fmColor:ForwardMsaa :: AllocatedImage
fmColor        = AllocatedImage
color
    , $sel:fmDepth:ForwardMsaa :: AllocatedImage
fmDepth        = AllocatedImage
depth
    , $sel:fmFrameBuffers:ForwardMsaa :: Vector Framebuffer
fmFrameBuffers = Vector Framebuffer
framebuffers
    , $sel:fmRelease:ForwardMsaa :: RefCounted
fmRelease      = RefCounted
release
    , $sel:fmRenderArea:ForwardMsaa :: Rect2D
fmRenderArea   = Rect2D
fullSurface
    }
  where
    fullSurface :: Rect2D
fullSurface = Vk.Rect2D
      { $sel:offset:Rect2D :: Offset2D
Vk.offset = Offset2D
forall a. Zero a => a
zero
      , $sel:extent:Rect2D :: Extent2D
Vk.extent = swapchain -> Extent2D
forall a. HasSwapchain a => a -> Extent2D
getSurfaceExtent swapchain
swapchain
      }

-- ** Render pass

allocateRenderPassMsaa
  :: ( MonadVulkan env m
     , Resource.MonadResource m
     , HasSwapchain swapchain
     )
  => swapchain
  -> m (Resource.ReleaseKey, Vk.RenderPass)
allocateRenderPassMsaa :: forall env (m :: * -> *) swapchain.
(MonadVulkan env m, MonadResource m, HasSwapchain swapchain) =>
swapchain -> m (ReleaseKey, RenderPass)
allocateRenderPassMsaa swapchain
swapchain = do
  Device
device <- (env -> Device) -> m Device
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks env -> Device
forall a. HasVulkan a => a -> Device
getDevice

  (ReleaseKey, RenderPass)
res <- Device
-> RenderPassCreateInfo '[]
-> Maybe AllocationCallbacks
-> (IO RenderPass
    -> (RenderPass -> IO ()) -> m (ReleaseKey, RenderPass))
-> m (ReleaseKey, RenderPass)
forall (a :: [*]) (io :: * -> *) r.
(Extendss RenderPassCreateInfo a, PokeChain a, MonadIO io) =>
Device
-> RenderPassCreateInfo a
-> Maybe AllocationCallbacks
-> (io RenderPass -> (RenderPass -> io ()) -> r)
-> r
Vk.withRenderPass Device
device RenderPassCreateInfo '[]
createInfo Maybe AllocationCallbacks
forall a. Maybe a
Nothing IO RenderPass
-> (RenderPass -> IO ()) -> m (ReleaseKey, RenderPass)
forall (m :: * -> *) a.
MonadResource m =>
IO a -> (a -> IO ()) -> m (ReleaseKey, a)
Resource.allocate
  RenderPass -> Text -> m ()
forall env (m :: * -> *) a.
(MonadVulkan env m, HasObjectType a) =>
a -> Text -> m ()
Named.object ((ReleaseKey, RenderPass) -> RenderPass
forall a b. (a, b) -> b
snd (ReleaseKey, RenderPass)
res) Text
"ForwardMSAA"
  pure (ReleaseKey, RenderPass)
res
  where
    format :: Format
format = swapchain -> Format
forall a. HasSwapchain a => a -> Format
getSurfaceFormat swapchain
swapchain
    depthFormat :: Format
depthFormat = swapchain -> Format
forall a. HasSwapchain a => a -> Format
getDepthFormat swapchain
swapchain
    msaa :: SampleCountFlagBits
msaa = swapchain -> SampleCountFlagBits
forall a. HasSwapchain a => a -> SampleCountFlagBits
getMultisample swapchain
swapchain

    onMsaa :: a -> a -> a
    onMsaa :: forall a. a -> a -> a
onMsaa a
none a
more = case SampleCountFlagBits
msaa of
      SampleCountFlagBits
Vk.SAMPLE_COUNT_1_BIT ->
        a
none
      SampleCountFlagBits
_mucho ->
        a
more

    attachments :: [AttachmentDescription]
attachments =
      AttachmentDescription
color AttachmentDescription
-> [AttachmentDescription] -> [AttachmentDescription]
forall a. a -> [a] -> [a]
:
      AttachmentDescription
depth AttachmentDescription
-> [AttachmentDescription] -> [AttachmentDescription]
forall a. a -> [a] -> [a]
:
      [AttachmentDescription]
-> [AttachmentDescription] -> [AttachmentDescription]
forall a. a -> a -> a
onMsaa [] [AttachmentDescription
colorResolve]

    createInfo :: RenderPassCreateInfo '[]
createInfo = RenderPassCreateInfo '[]
forall a. Zero a => a
zero
      { $sel:attachments:RenderPassCreateInfo :: Vector AttachmentDescription
Vk.attachments  = [AttachmentDescription] -> Vector AttachmentDescription
forall a. [a] -> Vector a
Vector.fromList [AttachmentDescription]
attachments
      , $sel:subpasses:RenderPassCreateInfo :: Vector SubpassDescription
Vk.subpasses    = [SubpassDescription] -> Vector SubpassDescription
forall a. [a] -> Vector a
Vector.fromList [SubpassDescription
subpass]
      , $sel:dependencies:RenderPassCreateInfo :: Vector SubpassDependency
Vk.dependencies = [SubpassDependency] -> Vector SubpassDependency
forall a. [a] -> Vector a
Vector.fromList [SubpassDependency
colorDeps, SubpassDependency
depthDeps]
      }

    -- | Main color-rendering attachment. Used as presentation when MSAA is disabled.
    color :: AttachmentDescription
color = AttachmentDescription
forall a. Zero a => a
zero
      { $sel:format:AttachmentDescription :: Format
Vk.format         = Format
format
      , $sel:samples:AttachmentDescription :: SampleCountFlagBits
Vk.samples        = SampleCountFlagBits
msaa
      , $sel:finalLayout:AttachmentDescription :: ImageLayout
Vk.finalLayout    = ImageLayout
finalColorLayout
      , $sel:loadOp:AttachmentDescription :: AttachmentLoadOp
Vk.loadOp         = AttachmentLoadOp
Vk.ATTACHMENT_LOAD_OP_CLEAR
      , $sel:storeOp:AttachmentDescription :: AttachmentStoreOp
Vk.storeOp        = AttachmentStoreOp
Vk.ATTACHMENT_STORE_OP_DONT_CARE
      , $sel:stencilLoadOp:AttachmentDescription :: AttachmentLoadOp
Vk.stencilLoadOp  = AttachmentLoadOp
Vk.ATTACHMENT_LOAD_OP_DONT_CARE
      , $sel:stencilStoreOp:AttachmentDescription :: AttachmentStoreOp
Vk.stencilStoreOp = AttachmentStoreOp
Vk.ATTACHMENT_STORE_OP_DONT_CARE
      , $sel:initialLayout:AttachmentDescription :: ImageLayout
Vk.initialLayout  = ImageLayout
Vk.IMAGE_LAYOUT_UNDEFINED
      }
    finalColorLayout :: ImageLayout
finalColorLayout =
      ImageLayout -> ImageLayout -> ImageLayout
forall a. a -> a -> a
onMsaa
        ImageLayout
Vk.IMAGE_LAYOUT_PRESENT_SRC_KHR
        ImageLayout
Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL

    depth :: AttachmentDescription
depth = AttachmentDescription
forall a. Zero a => a
zero
      { $sel:format:AttachmentDescription :: Format
Vk.format         = Format
depthFormat
      , $sel:samples:AttachmentDescription :: SampleCountFlagBits
Vk.samples        = SampleCountFlagBits
msaa
      , $sel:loadOp:AttachmentDescription :: AttachmentLoadOp
Vk.loadOp         = AttachmentLoadOp
Vk.ATTACHMENT_LOAD_OP_CLEAR
      , $sel:storeOp:AttachmentDescription :: AttachmentStoreOp
Vk.storeOp        = AttachmentStoreOp
Vk.ATTACHMENT_STORE_OP_DONT_CARE
      , $sel:stencilLoadOp:AttachmentDescription :: AttachmentLoadOp
Vk.stencilLoadOp  = AttachmentLoadOp
Vk.ATTACHMENT_LOAD_OP_DONT_CARE
      , $sel:stencilStoreOp:AttachmentDescription :: AttachmentStoreOp
Vk.stencilStoreOp = AttachmentStoreOp
Vk.ATTACHMENT_STORE_OP_DONT_CARE
      , $sel:initialLayout:AttachmentDescription :: ImageLayout
Vk.initialLayout  = ImageLayout
Vk.IMAGE_LAYOUT_UNDEFINED
      , $sel:finalLayout:AttachmentDescription :: ImageLayout
Vk.finalLayout    = ImageLayout
Vk.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
      }

    -- | Extra attachment to collect samples AND present.
    colorResolve :: AttachmentDescription
colorResolve = AttachmentDescription
forall a. Zero a => a
zero
      { $sel:format:AttachmentDescription :: Format
Vk.format      = Format
format
      , $sel:samples:AttachmentDescription :: SampleCountFlagBits
Vk.samples     = SampleCountFlagBits
Vk.SAMPLE_COUNT_1_BIT
      , $sel:finalLayout:AttachmentDescription :: ImageLayout
Vk.finalLayout = ImageLayout
Vk.IMAGE_LAYOUT_PRESENT_SRC_KHR
      , $sel:loadOp:AttachmentDescription :: AttachmentLoadOp
Vk.loadOp      = AttachmentLoadOp
Vk.ATTACHMENT_LOAD_OP_DONT_CARE
      }

    subpass :: SubpassDescription
subpass = SubpassDescription
forall a. Zero a => a
zero
      { $sel:pipelineBindPoint:SubpassDescription :: PipelineBindPoint
Vk.pipelineBindPoint = PipelineBindPoint
Vk.PIPELINE_BIND_POINT_GRAPHICS
      , $sel:colorAttachments:SubpassDescription :: Vector AttachmentReference
Vk.colorAttachments = AttachmentReference -> Vector AttachmentReference
forall a. a -> Vector a
Vector.singleton AttachmentReference
forall a. Zero a => a
zero
          { $sel:attachment:AttachmentReference :: Word32
Vk.attachment = Word32
0
          , $sel:layout:AttachmentReference :: ImageLayout
Vk.layout     = ImageLayout
Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
          }
      , $sel:depthStencilAttachment:SubpassDescription :: Maybe AttachmentReference
Vk.depthStencilAttachment = AttachmentReference -> Maybe AttachmentReference
forall a. a -> Maybe a
Just AttachmentReference
forall a. Zero a => a
zero
          { $sel:attachment:AttachmentReference :: Word32
Vk.attachment = Word32
1
          , $sel:layout:AttachmentReference :: ImageLayout
Vk.layout     = ImageLayout
Vk.IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
          }
      , $sel:resolveAttachments:SubpassDescription :: Vector AttachmentReference
Vk.resolveAttachments =
          Vector AttachmentReference
-> Vector AttachmentReference -> Vector AttachmentReference
forall a. a -> a -> a
onMsaa Vector AttachmentReference
forall a. Monoid a => a
mempty (Vector AttachmentReference -> Vector AttachmentReference)
-> Vector AttachmentReference -> Vector AttachmentReference
forall a b. (a -> b) -> a -> b
$
            AttachmentReference -> Vector AttachmentReference
forall a. a -> Vector a
Vector.singleton AttachmentReference
forall a. Zero a => a
zero
            { $sel:attachment:AttachmentReference :: Word32
Vk.attachment = Word32
2
            , $sel:layout:AttachmentReference :: ImageLayout
Vk.layout     = ImageLayout
Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
            }
      }

    colorDeps :: SubpassDependency
colorDeps = SubpassDependency
forall a. Zero a => a
zero
      { $sel:srcSubpass:SubpassDependency :: Word32
Vk.srcSubpass    = Word32
Vk.SUBPASS_EXTERNAL
      , $sel:dstSubpass:SubpassDependency :: Word32
Vk.dstSubpass    = Word32
0
      , $sel:srcStageMask:SubpassDependency :: PipelineStageFlags
Vk.srcStageMask  = PipelineStageFlags
colorOut
      , $sel:srcAccessMask:SubpassDependency :: AccessFlags
Vk.srcAccessMask = AccessFlags
forall a. Zero a => a
zero
      , $sel:dstStageMask:SubpassDependency :: PipelineStageFlags
Vk.dstStageMask  = PipelineStageFlags
colorOut
      , $sel:dstAccessMask:SubpassDependency :: AccessFlags
Vk.dstAccessMask = AccessFlags
colorRW
      }
      where
        colorOut :: PipelineStageFlags
colorOut =
          PipelineStageFlags
Vk.PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

        colorRW :: AccessFlags
colorRW =
          AccessFlags
Vk.ACCESS_COLOR_ATTACHMENT_READ_BIT AccessFlags -> AccessFlags -> AccessFlags
forall a. Bits a => a -> a -> a
.|.
          AccessFlags
Vk.ACCESS_COLOR_ATTACHMENT_WRITE_BIT

    depthDeps :: SubpassDependency
depthDeps = SubpassDependency
forall a. Zero a => a
zero
      { $sel:srcSubpass:SubpassDependency :: Word32
Vk.srcSubpass    = Word32
Vk.SUBPASS_EXTERNAL
      , $sel:dstSubpass:SubpassDependency :: Word32
Vk.dstSubpass    = Word32
0
      , $sel:srcStageMask:SubpassDependency :: PipelineStageFlags
Vk.srcStageMask  = PipelineStageFlags
fragTests
      , $sel:srcAccessMask:SubpassDependency :: AccessFlags
Vk.srcAccessMask = AccessFlags
depthW
      , $sel:dstStageMask:SubpassDependency :: PipelineStageFlags
Vk.dstStageMask  = PipelineStageFlags
fragTests
      , $sel:dstAccessMask:SubpassDependency :: AccessFlags
Vk.dstAccessMask = AccessFlags
depthRW
      }
      where
        fragTests :: PipelineStageFlags
fragTests =
          PipelineStageFlags
Vk.PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT PipelineStageFlags -> PipelineStageFlags -> PipelineStageFlags
forall a. Bits a => a -> a -> a
.|.
          PipelineStageFlags
Vk.PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT

        depthW :: AccessFlags
depthW =
          AccessFlags
Vk.ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT

        depthRW :: AccessFlags
depthRW =
          AccessFlags
Vk.ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT AccessFlags -> AccessFlags -> AccessFlags
forall a. Bits a => a -> a -> a
.|.
          AccessFlags
depthW

-- ** Framebuffer

type FramebuffersMsaa =
  ( Image.AllocatedImage
  , Image.AllocatedImage
  , Vector Vk.Framebuffer
  )

allocateFramebufferMsaa
  :: ( Resource.MonadResource m
     , MonadVulkan env m
     , HasSwapchain swapchain
     )
  => swapchain
  -> Vk.RenderPass
  -> m FramebuffersMsaa
allocateFramebufferMsaa :: forall (m :: * -> *) env swapchain.
(MonadResource m, MonadVulkan env m, HasSwapchain swapchain) =>
swapchain -> RenderPass -> m FramebuffersMsaa
allocateFramebufferMsaa swapchain
swapchain RenderPass
renderPass = do
  AllocatedImage
color <- Maybe Text
-> ImageAspectFlags
-> ("image dimensions" ::: Extent3D)
-> Word32
-> Word32
-> SampleCountFlagBits
-> Format
-> ImageUsageFlags
-> m AllocatedImage
forall env (io :: * -> *).
(MonadVulkan env io, MonadResource io) =>
Maybe Text
-> ImageAspectFlags
-> ("image dimensions" ::: Extent3D)
-> Word32
-> Word32
-> SampleCountFlagBits
-> Format
-> ImageUsageFlags
-> io AllocatedImage
Image.allocate
    (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"ForwardMSAA.color")
    ImageAspectFlags
Vk.IMAGE_ASPECT_COLOR_BIT
    (Extent2D -> Word32 -> "image dimensions" ::: Extent3D
Image.inflateExtent Extent2D
extent Word32
1)
    Word32
1
    Word32
1
    (swapchain -> SampleCountFlagBits
forall a. HasSwapchain a => a -> SampleCountFlagBits
getMultisample swapchain
swapchain)
    (swapchain -> Format
forall a. HasSwapchain a => a -> Format
getSurfaceFormat swapchain
swapchain)
    ImageUsageFlags
Vk.IMAGE_USAGE_COLOR_ATTACHMENT_BIT

  AllocatedImage
depth <- Maybe Text
-> ImageAspectFlags
-> ("image dimensions" ::: Extent3D)
-> Word32
-> Word32
-> SampleCountFlagBits
-> Format
-> ImageUsageFlags
-> m AllocatedImage
forall env (io :: * -> *).
(MonadVulkan env io, MonadResource io) =>
Maybe Text
-> ImageAspectFlags
-> ("image dimensions" ::: Extent3D)
-> Word32
-> Word32
-> SampleCountFlagBits
-> Format
-> ImageUsageFlags
-> io AllocatedImage
Image.allocate
    (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"ForwardMSAA.depth")
    ImageAspectFlags
Vk.IMAGE_ASPECT_DEPTH_BIT
    (Extent2D -> Word32 -> "image dimensions" ::: Extent3D
Image.inflateExtent Extent2D
extent Word32
1)
    Word32
1
    Word32
1
    (swapchain -> SampleCountFlagBits
forall a. HasSwapchain a => a -> SampleCountFlagBits
getMultisample swapchain
swapchain)
    (swapchain -> Format
forall a. HasSwapchain a => a -> Format
getDepthFormat swapchain
swapchain)
    ImageUsageFlags
Vk.IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT

  Vector Framebuffer
perView <- Vector ImageView
-> (Int -> ImageView -> m Framebuffer) -> m (Vector Framebuffer)
forall (m :: * -> *) a b.
Monad m =>
Vector a -> (Int -> a -> m b) -> m (Vector b)
Vector.iforM (swapchain -> Vector ImageView
forall a. HasSwapchain a => a -> Vector ImageView
getSwapchainViews swapchain
swapchain) \Int
ix ImageView
colorResolve -> do
    let
      attachments :: Vector ImageView
attachments = [ImageView] -> Vector ImageView
forall a. [a] -> Vector a
Vector.fromList
        case swapchain -> SampleCountFlagBits
forall a. HasSwapchain a => a -> SampleCountFlagBits
getMultisample swapchain
swapchain of
          SampleCountFlagBits
Vk.SAMPLE_COUNT_1_BIT ->
            [ ImageView
colorResolve
            , AllocatedImage -> ImageView
Image.aiImageView AllocatedImage
depth
            ]
          SampleCountFlagBits
_ ->
            [ AllocatedImage -> ImageView
Image.aiImageView AllocatedImage
color
            , AllocatedImage -> ImageView
Image.aiImageView AllocatedImage
depth
            , ImageView
colorResolve
            ]

      fbCI :: FramebufferCreateInfo '[]
fbCI = FramebufferCreateInfo '[]
forall a. Zero a => a
zero
        { $sel:renderPass:FramebufferCreateInfo :: RenderPass
Vk.renderPass  = RenderPass
renderPass
        , $sel:width:FramebufferCreateInfo :: Word32
Vk.width       = Word32
width
        , $sel:height:FramebufferCreateInfo :: Word32
Vk.height      = Word32
height
        , $sel:attachments:FramebufferCreateInfo :: Vector ImageView
Vk.attachments = Vector ImageView
attachments
        , $sel:layers:FramebufferCreateInfo :: Word32
Vk.layers      = Word32
1
        }

    Device
device <- (env -> Device) -> m Device
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks env -> Device
forall a. HasVulkan a => a -> Device
getDevice
    (ReleaseKey
_fbKey, Framebuffer
fb) <- Device
-> FramebufferCreateInfo '[]
-> Maybe AllocationCallbacks
-> (IO Framebuffer
    -> (Framebuffer -> IO ()) -> m (ReleaseKey, Framebuffer))
-> m (ReleaseKey, Framebuffer)
forall (a :: [*]) (io :: * -> *) r.
(Extendss FramebufferCreateInfo a, PokeChain a, MonadIO io) =>
Device
-> FramebufferCreateInfo a
-> Maybe AllocationCallbacks
-> (io Framebuffer -> (Framebuffer -> io ()) -> r)
-> r
Vk.withFramebuffer Device
device FramebufferCreateInfo '[]
fbCI Maybe AllocationCallbacks
forall a. Maybe a
Nothing IO Framebuffer
-> (Framebuffer -> IO ()) -> m (ReleaseKey, Framebuffer)
forall (m :: * -> *) a.
MonadResource m =>
IO a -> (a -> IO ()) -> m (ReleaseKey, a)
Resource.allocate
    Framebuffer -> Text -> m ()
forall env (m :: * -> *) a.
(MonadVulkan env m, HasObjectType a) =>
a -> Text -> m ()
Named.object Framebuffer
fb (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
      Text
"ForwardMSAA.FB:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
forall a. IsString a => String -> a
fromString (forall a. Show a => a -> String
show @Int Int
ix)
    pure Framebuffer
fb

  pure (AllocatedImage
color, AllocatedImage
depth, Vector Framebuffer
perView)
  where
    extent :: Extent2D
extent@Vk.Extent2D{Word32
width :: Word32
$sel:width:Extent2D :: Extent2D -> Word32
width, Word32
height :: Word32
$sel:height:Extent2D :: Extent2D -> Word32
height} = swapchain -> Extent2D
forall a. HasSwapchain a => a -> Extent2D
getSurfaceExtent swapchain
swapchain