diff --git a/project-words.txt b/project-words.txt index fca2429..c80a547 100644 --- a/project-words.txt +++ b/project-words.txt @@ -6,6 +6,7 @@ framebuffer Framebuffer Framebuffers GLSL +Imageview Keysym KHRONOS Memdiscrete diff --git a/src/CommandBuffer.hs b/src/CommandBuffer.hs index 1a979f2..233b9c3 100644 --- a/src/CommandBuffer.hs +++ b/src/CommandBuffer.hs @@ -102,7 +102,7 @@ recordCommandBuffer , Vk.height = fromIntegral height } } - , Vk.clearValues = V.replicate 4 (Vk.Color $ Vk.Float32 0 0 0 1) + , Vk.clearValues = V.fromList [ Vk.Color (Vk.Float32 0 0 0 1), Vk.DepthStencil (Vk.ClearDepthStencilValue 1 0)] } Vk.cmdBeginRenderPass commandBuffer renderPassInfo Vk.SUBPASS_CONTENTS_INLINE @@ -134,7 +134,7 @@ recordCommandBuffer liftIO $ maybe (Vk.cmdDraw commandBuffer 3 1 0 0) (\jmesh -> do - let camPosition = V3 0 0 (-2) + let camPosition = V3 0 0 (-5) camCenter = V3 0 0 0 camUp = V3 0 1 0 view = lookAt camPosition camCenter camUp diff --git a/src/Devices.hs b/src/Devices.hs index 303563b..509d602 100644 --- a/src/Devices.hs +++ b/src/Devices.hs @@ -15,6 +15,12 @@ import Linear import qualified Vulkan as Vk import qualified Vulkan.Zero as Vk import qualified Vulkan.CStruct.Extends as Vk +import qualified VulkanMemoryAllocator as VMA + +-- internal imports + +import Image +import Types pickPhysicalDevice :: (MonadResource m) @@ -119,8 +125,9 @@ createSwapchain -> V.Vector Vk.SurfaceFormatKHR -> V2 CInt -> Vk.Device - -> m (Vk.SwapchainKHR, Vk.SurfaceFormatKHR) -createSwapchain surface surfaceFormats windowDimension logicalDevice = do + -> VMA.Allocator + -> m (Vk.SwapchainKHR, Vk.SurfaceFormatKHR, Vk.ImageView, AllocatedImage) +createSwapchain surface surfaceFormats windowDimension logicalDevice allocator = do liftIO $ do putStrLn "available formats:" @@ -166,7 +173,41 @@ createSwapchain surface surfaceFormats windowDimension logicalDevice = do Vk.destroySwapchainKHR logicalDevice swapchain Nothing ) - return (swapchain, Vk.SurfaceFormatKHR surfaceFormat colorSpace) + let depthImageExtent = + (\(V2 w h) -> Vk.Extent3D (fromIntegral w) (fromIntegral h) 1) + windowDimension + + let depthImageInfo = imageCreate + Vk.FORMAT_D32_SFLOAT + depthImageExtent + Vk.IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + + let depthImageAllocationInfo = Vk.zero + { VMA.usage = VMA.MEMORY_USAGE_GPU_ONLY + , VMA.requiredFlags = Vk.MEMORY_PROPERTY_DEVICE_LOCAL_BIT + } + + (depthImage, depthAllocation, _) <- snd <$> allocate + (VMA.createImage allocator depthImageInfo depthImageAllocationInfo) + (\(depthImage, depthAllocation, _) -> do + putStrLn "destroying image" + VMA.destroyImage allocator depthImage depthAllocation + ) + + let allocatedImage = AllocatedImage depthImage depthAllocation + depthImageView = imageviewCreate + (image allocatedImage) + Vk.FORMAT_D32_SFLOAT + Vk.IMAGE_ASPECT_DEPTH_BIT + + depthImageview <- snd <$> allocate + (Vk.createImageView logicalDevice depthImageView Nothing) + (\depthImageview -> do + putStrLn "destroying image view" + Vk.destroyImageView logicalDevice depthImageview Nothing + ) + + return (swapchain, Vk.SurfaceFormatKHR surfaceFormat colorSpace, depthImageview, allocatedImage) getImageViewHandles :: (MonadResource m) @@ -183,9 +224,9 @@ getImageViewHandles swapchain surfaceFormat logicalDevice = do putStrLn ("number of images: " <> show (V.length handles)) V.mapM - (\image -> do + (\tmpImage -> do let createInfo = Vk.zero - { Vk.image = image + { Vk.image = tmpImage , Vk.viewType = Vk.IMAGE_VIEW_TYPE_2D , Vk.format = (Vk.format :: Vk.SurfaceFormatKHR -> Vk.Format) surfaceFormat , Vk.components = Vk.ComponentMapping diff --git a/src/Draw.hs b/src/Draw.hs index f403506..3b9fa58 100644 --- a/src/Draw.hs +++ b/src/Draw.hs @@ -62,14 +62,7 @@ drawFrame engineData switch frameNumber = do (engineRenderPass engineData) (engineFramebuffers engineData V.! fromIntegral index) (engineWindowDimensions engineData) - (case switchState of - Rainbow -> - redEnginePipelines engineData V.! fromIntegral index - Red -> - rainbowEnginePipelines engineData V.! fromIntegral index - Green -> - meshPipeline engineData V.! fromIntegral index - ) + (meshPipeline engineData V.! fromIntegral index) (meshPipelineLayout engineData) (case switchState of Green -> diff --git a/src/Framebuffers.hs b/src/Framebuffers.hs index c3721e7..157c4fb 100644 --- a/src/Framebuffers.hs +++ b/src/Framebuffers.hs @@ -16,22 +16,28 @@ createFramebuffer => Vk.Device -> Vk.RenderPass -> V.Vector Vk.ImageView + -> Vk.ImageView -> V2 CInt -> m (V.Vector Vk.Framebuffer) -createFramebuffer logicalDevice renderPass swapchainImageViews (V2 swapchainWidth swapcheinHeight) +createFramebuffer + logicalDevice + renderPass + swapchainImageViews + depthImageView + (V2 swapchainWidth swapchainHeight) = do let framebufferCreateInfo = Vk.zero { Vk.renderPass = renderPass , Vk.width = fromIntegral swapchainWidth - , Vk.height = fromIntegral swapcheinHeight + , Vk.height = fromIntegral swapchainHeight , Vk.layers = 1 } V.mapM (\imageView -> do let createInfo = framebufferCreateInfo - { Vk.attachments = V.singleton imageView + { Vk.attachments = V.fromList [ imageView, depthImageView ] } :: Vk.FramebufferCreateInfo '[] snd <$> allocate (Vk.createFramebuffer logicalDevice createInfo Nothing) diff --git a/src/GraphicsPipeline.hs b/src/GraphicsPipeline.hs index 2001ee7..7b56129 100644 --- a/src/GraphicsPipeline.hs +++ b/src/GraphicsPipeline.hs @@ -59,14 +59,14 @@ createRenderPass :: (MonadResource m) => Vk.Device -> Vk.Format + -> Vk.Format -> m Vk.RenderPass createRenderPass logicalDevice swapchainImageFormat + depthFormat = do - - let colorAttachmentDescription = (Vk.zero :: Vk.AttachmentDescription) { Vk.format = swapchainImageFormat , Vk.samples = Vk.SAMPLE_COUNT_1_BIT @@ -81,23 +81,48 @@ createRenderPass { Vk.attachment = 0 , Vk.layout = Vk.IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } + 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 + } subpassDescriptor = (Vk.zero :: Vk.SubpassDescription) - { Vk.pipelineBindPoint = Vk.PIPELINE_BIND_POINT_GRAPHICS - , Vk.colorAttachments = V.singleton colorAttachmentReference + { Vk.pipelineBindPoint = Vk.PIPELINE_BIND_POINT_GRAPHICS + , Vk.colorAttachments = V.singleton colorAttachmentReference + , Vk.depthStencilAttachment = Just depthAttachmentReference } 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 - , Vk.srcAccessMask = Vk.ACCESS_COLOR_ATTACHMENT_WRITE_BIT - , Vk.dstAccessMask = - Vk.ACCESS_COLOR_ATTACHMENT_READ_BIT .|. Vk.ACCESS_COLOR_ATTACHMENT_WRITE_BIT + , Vk.srcAccessMask = bit 0 + , 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 + , Vk.srcAccessMask = bit 0 + , 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 } renderPassCreateInfo = Vk.zero - { Vk.attachments = V.singleton colorAttachmentDescription + { Vk.attachments = V.fromList [ colorAttachmentDescription, depthAttachmentDescription ] , Vk.subpasses = V.singleton subpassDescriptor - , Vk.dependencies = V.singleton subpassDependency + , Vk.dependencies = V.fromList [ subpassDependency, subpassDepthDependency ] } :: Vk.RenderPassCreateInfo '[] snd <$> allocate @@ -144,6 +169,22 @@ createRasterizationStateCreateInfo mode = , Vk.depthBiasSlopeFactor = 0 } +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 + } + createMultisampleStateCreateInfo :: Vk.SomeStruct Vk.PipelineMultisampleStateCreateInfo createMultisampleStateCreateInfo = @@ -160,6 +201,7 @@ createGraphicsPipelines -> V2 CInt -> Int -> Vk.PipelineLayout + -> Maybe Vk.PipelineDepthStencilStateCreateInfo -> m (V.Vector Vk.Pipeline) createGraphicsPipelines logicalDevice @@ -168,6 +210,7 @@ createGraphicsPipelines (V2 width height) number pipelineLayout + depthState = do let pipelineStagesCreateInfos = V.fromList $ map Vk.SomeStruct @@ -249,6 +292,7 @@ createGraphicsPipelines , Vk.multisampleState = Just createMultisampleStateCreateInfo , Vk.colorBlendState = Just $ Vk.SomeStruct pipelineColorBlendStateCreateInfo , Vk.dynamicState = Just pipelineDynamicStateCreateInfo + , Vk.depthStencilState = depthState , Vk.layout = pipelineLayout , Vk.renderPass = renderPass , Vk.subpass = 0 diff --git a/src/Image.hs b/src/Image.hs new file mode 100644 index 0000000..30052d2 --- /dev/null +++ b/src/Image.hs @@ -0,0 +1,47 @@ +{-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE DataKinds #-} +module Image where + +import qualified Vulkan as Vk +import qualified Vulkan.Zero as Vk + +imageCreate + :: Vk.Format + -> Vk.Extent3D + -> Vk.ImageUsageFlags + -> Vk.ImageCreateInfo '[] +imageCreate format extent usageFlags = + let imageCreateInfo = Vk.zero + { Vk.imageType = Vk.IMAGE_TYPE_2D + , Vk.format = format + , Vk.extent = extent + , Vk.mipLevels = 1 + , Vk.arrayLayers = 1 + , Vk.samples = Vk.SAMPLE_COUNT_1_BIT + , Vk.tiling = Vk.IMAGE_TILING_OPTIMAL + , Vk.usage = usageFlags + } + + in imageCreateInfo + +imageviewCreate + :: Vk.Image + -> Vk.Format + -> Vk.ImageAspectFlags + -> Vk.ImageViewCreateInfo '[] +imageviewCreate image format aspectFlags = + let imageviewCreateInfo = Vk.zero + { Vk.viewType = Vk.IMAGE_VIEW_TYPE_2D + , Vk.image = image + , Vk.format = format + , Vk.subresourceRange = Vk.zero + { Vk.baseMipLevel = 0 + , Vk.levelCount = 1 + , Vk.baseArrayLayer = 0 + , Vk.layerCount = 1 + , Vk.aspectMask = aspectFlags + } + } + + in imageviewCreateInfo + diff --git a/src/Init.hs b/src/Init.hs index f5c8a49..529b067 100644 --- a/src/Init.hs +++ b/src/Init.hs @@ -78,42 +78,18 @@ initVulkan window = do (vulkanLogicalDevice, surfaceFormats) <- createLogicalDevice vulkanPhysicalDevice vulkanSurface allocator <- initAllocator vulkanPhysicalDevice vulkanLogicalDevice vulkanInstance - mesh <- uploadMesh loadMeshes allocator maskMesh <- loadFromObj "./assets/cat_mask_cyberpunk.obj" allocator dimensions <- liftIO $ SDL.windowInitialSize <$> SDL.getWindowConfig window - (swapchain, surfaceFormat) <- - createSwapchain vulkanSurface surfaceFormats dimensions vulkanLogicalDevice + (swapchain, surfaceFormat, depthImageView, depthAllocatedImage) <- + createSwapchain vulkanSurface surfaceFormats dimensions vulkanLogicalDevice allocator imageViews <- getImageViewHandles swapchain surfaceFormat vulkanLogicalDevice - redVertexShader <- loadShader vulkanLogicalDevice "shadersrc/red.vert" "vert" - redFragmentShader <- loadShader vulkanLogicalDevice "shadersrc/red.frag" "frag" - rainbowVertexShader <- loadShader vulkanLogicalDevice "shadersrc/rainbow.vert" "vert" - rainbowFragmentShader <- loadShader vulkanLogicalDevice "shadersrc/rainbow.frag" "frag" meshVertexShader <- loadShader vulkanLogicalDevice "shadersrc/mesh.vert" "vert" meshFragmentShader <- loadShader vulkanLogicalDevice "shadersrc/rainbow.frag" "frag" - renderPass <- createRenderPass vulkanLogicalDevice (Khr.format surfaceFormat) - pipelineLayout <- createPipelineLayout vulkanLogicalDevice + renderPass <- createRenderPass vulkanLogicalDevice (Khr.format surfaceFormat) Vk.FORMAT_D32_SFLOAT meshLayout <- createMeshPipelineLayout vulkanLogicalDevice - let redContainer = ShaderContainer (Just redVertexShader) (Just redFragmentShader) - rainbowContainer = ShaderContainer (Just rainbowVertexShader) (Just rainbowFragmentShader) - meshContainer = ShaderContainer (Just meshVertexShader) (Just meshFragmentShader) - redPipelines <- - createGraphicsPipelines - vulkanLogicalDevice - renderPass - redContainer - dimensions - (length imageViews) - pipelineLayout - rainbowPipelines <- - createGraphicsPipelines - vulkanLogicalDevice - renderPass - rainbowContainer - dimensions - (length imageViews) - pipelineLayout + let meshContainer = ShaderContainer (Just meshVertexShader) (Just meshFragmentShader) meshPipelines <- createGraphicsPipelines vulkanLogicalDevice @@ -122,8 +98,9 @@ initVulkan window = do dimensions (length imageViews) meshLayout + (Just (createDepthStencilStateCreateInfo True True Vk.COMPARE_OP_LESS_OR_EQUAL)) - frameBuffers <- createFramebuffer vulkanLogicalDevice renderPass imageViews dimensions + frameBuffers <- createFramebuffer vulkanLogicalDevice renderPass imageViews depthImageView dimensions (commandPool, graphicsQueue) <- createCommandPool vulkanPhysicalDevice vulkanLogicalDevice commandBuffer <- createCommandBuffer vulkanLogicalDevice commandPool (length frameBuffers) @@ -142,8 +119,6 @@ initVulkan window = do commandBuffer frameBuffers meshLayout - redPipelines - rainbowPipelines meshPipelines renderPass inFlightFence @@ -152,3 +127,6 @@ initVulkan window = do maskMesh maskMesh allocator + depthImageView + depthAllocatedImage + Vk.FORMAT_D32_SFLOAT diff --git a/src/Main.hs b/src/Main.hs index 8106dd0..235da0f 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -47,19 +47,6 @@ main = runResourceT $ do (\e -> case SDL.eventPayload e of SDL.WindowClosedEvent _ -> void $ liftIO $ STM.atomically $ STM.swapTMVar quit False - SDL.KeyboardEvent dat -> - case dat of - SDL.KeyboardEventData _ SDL.Released _ (SDL.Keysym _ SDL.KeycodeSpace _) -> - liftIO $ STM.atomically $ do - state <- STM.readTMVar showPipeline - void $ STM.swapTMVar showPipeline - (if state /= maxBound then succ state else state) - SDL.KeyboardEventData _ SDL.Released _ (SDL.Keysym _ SDL.KeycodeTab _) -> - liftIO $ STM.atomically $ do - state <- STM.readTMVar showPipeline - void $ STM.swapTMVar showPipeline - (if state /= minBound then pred state else state) - _ -> return () _ -> return () ) evs diff --git a/src/Types.hs b/src/Types.hs index 69c142c..87e2b0a 100644 --- a/src/Types.hs +++ b/src/Types.hs @@ -33,8 +33,6 @@ data EngineData = EngineData , engineCommandBuffers :: V.Vector Vk.CommandBuffer , engineFramebuffers :: V.Vector Vk.Framebuffer , meshPipelineLayout :: Vk.PipelineLayout - , redEnginePipelines :: V.Vector Vk.Pipeline - , rainbowEnginePipelines :: V.Vector Vk.Pipeline , meshPipeline :: V.Vector Vk.Pipeline , engineRenderPass :: Vk.RenderPass , engineInFlightFence :: Vk.Fence @@ -43,6 +41,9 @@ data EngineData = EngineData , engineMesh :: Mesh , engineExternalMesh :: Mesh , engineAllocator :: VMA.Allocator + , engineDepthImageView :: Vk.ImageView + , engineDepthImage :: AllocatedImage + , engineDepthFormat :: Vk.Format } data AllocatedBuffer = AllocatedBuffer @@ -116,6 +117,7 @@ data VertexInputDescription = VertexInputDescription { vidBindings :: V.Vector Vk.VertexInputBindingDescription , vidAttributes :: V.Vector Vk.VertexInputAttributeDescription } + deriving (Show) data Mesh = Mesh { meshVertices :: V.Vector Vertex @@ -143,3 +145,9 @@ instance Storable MeshPushConstants where poke (castPtr $ ptr `plusPtr` sizeOf dat) mat alignment _ = 0 + +data AllocatedImage = AllocatedImage + { image :: Vk.Image + , allocation :: VMA.Allocation + } + deriving (Show) diff --git a/vulkan-tutorial.cabal b/vulkan-tutorial.cabal index f8abe92..3123e9c 100644 --- a/vulkan-tutorial.cabal +++ b/vulkan-tutorial.cabal @@ -33,6 +33,7 @@ executable vulkan-tutorial Draw Memory Mesh + Image Types -- LANGUAGE extensions used by modules in this package.