Compare commits

...

31 commits

Author SHA1 Message Date
bab538a0e4 flake update 2023-11-05 12:02:16 +01:00
2d3fc457be a little cleaner 2023-10-22 12:46:16 +02:00
4feac51f26 weed out stuff 2023-10-22 07:14:22 +02:00
def6e56d1f implement FPS meter in Console output 2023-10-22 06:08:43 +02:00
1b6a6392ba fix rendering! 2023-10-22 02:27:33 +02:00
8f6f5e428d flake update 2023-10-22 01:32:38 +02:00
676e02ed8d more twiddling 2023-10-22 01:30:52 +02:00
167599df74 try fixing 2023-10-22 01:30:52 +02:00
9350198e35 explicitly enable multiIndirectDraw 2023-10-22 01:30:52 +02:00
9d34dacf76 condense flake 2023-10-22 01:30:52 +02:00
a6af76f3b3 fix ambiguous record updates 2023-10-22 01:30:51 +02:00
934085906c final flake fix 2023-10-22 01:30:18 +02:00
c55bfc5416 make shell 2023-10-22 01:30:18 +02:00
f873fa7291 move package 2023-10-22 01:30:18 +02:00
ccd18f803b flake update 2023-10-22 01:30:16 +02:00
fe4155d26f fix flake 2023-10-22 01:29:49 +02:00
2ae3daf0f9 fix flake 2023-10-22 01:29:49 +02:00
d2dac89ce3 small-ish fixes 2023-10-22 01:29:47 +02:00
0cb8bd8363 add test/debug VM capability 2023-10-22 01:28:21 +02:00
d9b7c48953 using indirect draw, not working yet 2023-10-22 01:27:18 +02:00
9084be8bba first little optimisation 2023-10-22 01:27:13 +02:00
3928655bb0 fix changing rules 2023-10-22 01:15:03 +02:00
ea87f58b26 flake update 2023-10-22 00:33:07 +02:00
272db907a0 fix double spaceships 2023-06-11 08:13:53 +02:00
6caf99a13c remove lambda 2023-06-11 08:13:53 +02:00
ef135731a4 first little optimisation 2023-06-11 08:13:49 +02:00
b3a7670c97 fix UVs in Code, not in shader 2023-05-30 01:44:20 +01:00
c0f8e10f44 hunt validation errors 2023-05-17 10:31:01 +02:00
89464b769f add comment 2023-05-17 06:05:05 +02:00
6f6716e69a flip uv coordintes right 2023-05-17 06:02:56 +02:00
61f800cdd9 flip y axis 2023-05-17 05:52:41 +02:00
13 changed files with 240 additions and 91 deletions

View file

@ -5,11 +5,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1681202837, "lastModified": 1694529238,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401", "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1684120848, "lastModified": 1699181587,
"narHash": "sha256-gIwJ5ac1FwZEkCRwjY+gLwgD4G1Bw3Xtr2jr2XihMPo=", "narHash": "sha256-v35mUUgVU2ituIHPNHifpjl5uiYQYyLrpaMtz8X8Ums=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0cb867999eec4085e1c9ca61c09b72261fa63bb4", "rev": "197629b470f184a47b2a5716312d25b09454bbf8",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -11,28 +11,36 @@
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
haskellPackages = pkgs.haskellPackages; nixos-lib = import (nixpkgs + "/nixos/lib") {};
haskellPackages = pkgs.haskellPackages.override (old: {
overrides = final: prev: {
wavefront = jailbreakUnbreak prev.wavefront;
vulkan-tutorial = vulkan-tutorial;
};
});
vulkan-tutorial = # (ref:haskell-package-def)
haskellPackages.callCabal2nix packageName self {
# Dependency overrides go here
#wavefront = jailbreakUnbreak haskellPackages.wavefront;
};
jailbreakUnbreak = pkg: jailbreakUnbreak = pkg:
pkgs.haskell.lib.doJailbreak (pkg.overrideAttrs (_: { meta = { }; })); pkgs.haskell.lib.doJailbreak (pkgs.haskell.lib.markUnbroken pkg);
packageName = "vulkan-tutorial"; packageName = "vulkan-tutorial";
in rec { in rec {
packages.${packageName} = # (ref:haskell-package-def) packages.default = haskellPackages.vulkan-tutorial;
haskellPackages.callCabal2nix packageName self rec {
# Dependency overrides go here
wavefront = jailbreakUnbreak haskellPackages.wavefront;
};
defaultPackage = self.packages.${system}.${packageName}; devShells.default = haskellPackages.shellFor {
packages = p: [ p.vulkan-tutorial ];
devShell = haskellPackages.shellFor {
packages = p: [ defaultPackage ];
withHoogle = true; withHoogle = true;
buildInputs = (with haskellPackages; [ buildInputs = (with haskellPackages; [
haskell-language-server haskell-language-server
ghcid ghcid
cabal-install cabal-install
(jailbreakUnbreak wavefront)
]) ++ (with pkgs; [ ]) ++ (with pkgs; [
shaderc shaderc
vulkan-loader vulkan-loader
@ -42,21 +50,6 @@
VK_LAYER_PATH="${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; VK_LAYER_PATH="${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d";
SDL_VULKAN_LIBRARY="${pkgs.vulkan-loader}/lib/libvulkan.so"; SDL_VULKAN_LIBRARY="${pkgs.vulkan-loader}/lib/libvulkan.so";
}; };
#devShell = pkgs.mkShell {
# buildInputs = with haskellPackages; [
# haskell-language-server
# ghcid
# cabal-install
# ];
# nativeBuildInputs = with pkgs; [
# pkg-config
# SDL2
# vulkan-validation-layers
# vulkan-headers
# vulkan-loader
# ];
# inputsFrom = builtins.attrValues self.packages.${system};
#};
}); });
} }

View file

@ -1,4 +1,3 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
@ -23,7 +22,7 @@ import qualified VulkanMemoryAllocator as VMA
import Types import Types
import Memory import Memory
import Util import Util
import Data.Maybe (fromMaybe) import Mesh (compactDraws)
frameOverlap :: Int frameOverlap :: Int
frameOverlap = 2 frameOverlap = 2
@ -60,7 +59,7 @@ createFrames
(\_ -> do (\_ -> do
commandPool <- snd <$> commandPool <- snd <$>
(Vk.withCommandPool logicalDevice poolCreateInfo Nothing allocate) Vk.withCommandPool logicalDevice poolCreateInfo Nothing allocate
let commandBufferAllocationInfo = Vk.zero let commandBufferAllocationInfo = Vk.zero
{ Vk.commandPool = commandPool { Vk.commandPool = commandPool
@ -100,6 +99,15 @@ createFrames
Vk.BUFFER_USAGE_STORAGE_BUFFER_BIT Vk.BUFFER_USAGE_STORAGE_BUFFER_BIT
VMA.MEMORY_USAGE_CPU_TO_GPU VMA.MEMORY_USAGE_CPU_TO_GPU
indirectBuffer <- createAllocatedBuffer
allocator
(maxObjects * sizeOf (undefined :: Vk.DrawIndirectCommand))
(Vk.BUFFER_USAGE_TRANSFER_DST_BIT .|.
Vk.BUFFER_USAGE_STORAGE_BUFFER_BIT .|.
Vk.BUFFER_USAGE_INDIRECT_BUFFER_BIT
)
VMA.MEMORY_USAGE_CPU_TO_GPU
let allocationInfo = Vk.zero let allocationInfo = Vk.zero
{ Vk.descriptorPool = descriptorPool { Vk.descriptorPool = descriptorPool
, Vk.setLayouts = V.singleton setLayout , Vk.setLayouts = V.singleton setLayout
@ -161,6 +169,7 @@ createFrames
, frameCameraBuffer = cameraBuffer , frameCameraBuffer = cameraBuffer
, frameSceneBuffer = sceneBuffer , frameSceneBuffer = sceneBuffer
, frameObjectBuffer = objectBuffer , frameObjectBuffer = objectBuffer
, frameIndirectBuffer = indirectBuffer
, frameGlobalDescriptor = V.head globalDescriptor , frameGlobalDescriptor = V.head globalDescriptor
, frameObjectDescriptor = V.head objectDescriptor , frameObjectDescriptor = V.head objectDescriptor
} }
@ -172,7 +181,8 @@ createFrames
recordCommandBuffer recordCommandBuffer
:: (MonadResource m, MonadReader ReadState m, MonadIO m) :: (MonadResource m, MonadReader ReadState m, MonadIO m)
=> Vk.CommandBuffer => VMA.Allocator
-> Vk.CommandBuffer
-> Vk.RenderPass -> Vk.RenderPass
-> Vk.Framebuffer -> Vk.Framebuffer
-> V2 CInt -> V2 CInt
@ -180,6 +190,7 @@ recordCommandBuffer
-> FrameData -> FrameData
-> m () -> m ()
recordCommandBuffer recordCommandBuffer
allocator
commandBuffer commandBuffer
renderPass renderPass
frameBuffer frameBuffer
@ -221,22 +232,43 @@ recordCommandBuffer
renderObjects <- (liftIO . STM.atomically . STM.readTMVar) =<< asks renderables renderObjects <- (liftIO . STM.atomically . STM.readTMVar) =<< asks renderables
meshMap <- (liftIO . STM.atomically . STM.readTMVar) =<< asks meshLibrary meshMap <- (liftIO . STM.atomically . STM.readTMVar) =<< asks meshLibrary
V.mapM_
(\(index, RenderObject meshID materialID modelMatrix) -> do
materialMap <- (liftIO . STM.atomically . STM.readTMVar) =<< asks materialLibrary materialMap <- (liftIO . STM.atomically . STM.readTMVar) =<< asks materialLibrary
let constants = MeshPushConstants let draws = compactDraws meshMap materialMap renderObjects
{ meshPushData = V4 0 0 0 0 drawCommands = V.map
, meshRenderMatrix = modelMatrix (\(i, RenderObject mesh _ _) ->
Vk.DrawIndirectCommand
{ vertexCount = fromIntegral (V.length $ meshVertices $ meshMap M.! mesh)
, firstVertex = 0
, instanceCount = 1
, firstInstance = i
} }
mesh = fromMaybe )
(error $ "no mesh called " <> meshID <> " present") (V.zip
(meshMap M.!? meshID) (V.fromList [0..])
material = fromMaybe renderObjects
(error $ "no material called " <> materialID <> " present") )
(materialMap M.!? materialID)
(memRelease, memPtr) <- VMA.withMappedMemory
allocator
(bufferAllocation $ frameIndirectBuffer frame)
allocate
V.mapM_
(\(idx, command) -> liftIO $
poke
(castPtr memPtr `plusPtr` (idx * sizeOf command))
command
)
(V.zip
(V.fromList [0 ..])
drawCommands
)
release memRelease
V.mapM_
(\(IndirectBatch mesh material first count) -> do
when when
(materialTextureSet material /= Vk.NULL_HANDLE) (materialTextureSet material /= Vk.NULL_HANDLE)
@ -267,28 +299,24 @@ recordCommandBuffer
(V.singleton $ frameObjectDescriptor frame) (V.singleton $ frameObjectDescriptor frame)
V.empty V.empty
dataPointer <- liftIO (castPtr <$> new constants)
Vk.cmdPushConstants
commandBuffer
(materialPipelineLayout material)
Vk.SHADER_STAGE_VERTEX_BIT
0
(fromIntegral $ sizeOf constants)
dataPointer
Vk.cmdBindVertexBuffers Vk.cmdBindVertexBuffers
commandBuffer commandBuffer
0 0
(V.fromList [ allocatedBuffer $ meshBuffer mesh ]) (V.fromList [ allocatedBuffer $ meshBuffer mesh ])
(V.fromList [ 0 ]) (V.fromList [ 0 ])
Vk.cmdDraw commandBuffer (fromIntegral $ V.length $ meshVertices mesh) 1 0 index let indirectOffset = fromIntegral $
) first * fromIntegral ( sizeOf (undefined :: Vk.DrawIndirectCommand))
(V.zip drawStride = fromIntegral $ sizeOf (undefined :: Vk.DrawIndirectCommand)
(V.fromList [0 ..])
renderObjects Vk.cmdDrawIndirect
commandBuffer
(allocatedBuffer $ frameIndirectBuffer frame)
indirectOffset
count
drawStride
) )
draws
prepareRecording prepareRecording
:: V2 CInt :: V2 CInt
@ -298,11 +326,12 @@ prepareRecording
prepareRecording (V2 width height) commandBuffer graphicsPipeline = do prepareRecording (V2 width height) commandBuffer graphicsPipeline = do
Vk.cmdBindPipeline commandBuffer Vk.PIPELINE_BIND_POINT_GRAPHICS graphicsPipeline Vk.cmdBindPipeline commandBuffer Vk.PIPELINE_BIND_POINT_GRAPHICS graphicsPipeline
-- Passing negative height and nonzero y origin to the viewport flips the models back in order
let viewport = Vk.zero let viewport = Vk.zero
{ Vk.x = 0 { Vk.x = 0
, Vk.y = 0 , Vk.y = fromIntegral height
, Vk.width = fromIntegral width , Vk.width = fromIntegral width
, Vk.height = fromIntegral height , Vk.height = - fromIntegral height
, Vk.minDepth = 0 , Vk.minDepth = 0
, Vk.maxDepth = 1 , Vk.maxDepth = 1
} }

View file

@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedRecordDot #-}
module Devices where module Devices where
import Control.Monad import Control.Monad
@ -38,7 +39,7 @@ pickPhysicalDevice vkInstance = do
physDevices physDevices
let discretePhysDevices = V.filter let discretePhysDevices = V.filter
(\(_, devProps, devFeatures) -> (\(_, _, devFeatures) ->
-- Vk.deviceType devProps == Vk.PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && -- Vk.deviceType devProps == Vk.PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
Vk.geometryShader devFeatures Vk.geometryShader devFeatures
) )
@ -104,6 +105,9 @@ createLogicalDevice physDevice surface = do
deviceCreateInfo = Vk.zero deviceCreateInfo = Vk.zero
{ Vk.queueCreateInfos = V.singleton (Vk.SomeStruct queueCreateInfo) { Vk.queueCreateInfos = V.singleton (Vk.SomeStruct queueCreateInfo)
, Vk.enabledExtensionNames = extensionNames , Vk.enabledExtensionNames = extensionNames
, Vk.enabledFeatures = Just (Vk.zero
{ Vk.multiDrawIndirect = True
} :: Vk.PhysicalDeviceFeatures)
} }
shaderDrawParametersFeatures = Vk.zero shaderDrawParametersFeatures = Vk.zero
{ Vk.shaderDrawParameters = True { Vk.shaderDrawParameters = True
@ -140,9 +144,9 @@ createSwapchain surface surfaceFormats windowDimension logicalDevice allocator =
if if
V.any V.any
(\a -> (\a ->
(Vk.format :: Vk.SurfaceFormatKHR -> Vk.Format) a == a.format ==
Vk.FORMAT_B8G8R8A8_SRGB Vk.FORMAT_B8G8R8A8_SRGB
&& (Vk.colorSpace :: Vk.SurfaceFormatKHR -> Vk.ColorSpaceKHR) a == && a.colorSpace ==
Vk.COLOR_SPACE_SRGB_NONLINEAR_KHR) Vk.COLOR_SPACE_SRGB_NONLINEAR_KHR)
surfaceFormats surfaceFormats
then then
@ -219,7 +223,7 @@ getImageViewHandles swapchain surfaceFormat logicalDevice = do
let createInfo = Vk.zero let createInfo = Vk.zero
{ Vk.image = tmpImage { Vk.image = tmpImage
, Vk.viewType = Vk.IMAGE_VIEW_TYPE_2D , Vk.viewType = Vk.IMAGE_VIEW_TYPE_2D
, Vk.format = (Vk.format :: Vk.SurfaceFormatKHR -> Vk.Format) surfaceFormat , Vk.format = surfaceFormat.format
, Vk.components = Vk.ComponentMapping , Vk.components = Vk.ComponentMapping
{ Vk.r = Vk.COMPONENT_SWIZZLE_IDENTITY { Vk.r = Vk.COMPONENT_SWIZZLE_IDENTITY
, Vk.g = Vk.COMPONENT_SWIZZLE_IDENTITY , Vk.g = Vk.COMPONENT_SWIZZLE_IDENTITY

View file

@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedRecordDot #-}
module Draw where module Draw where
import qualified Control.Concurrent.STM as STM import qualified Control.Concurrent.STM as STM
@ -57,7 +58,7 @@ drawFrame engineData frameNumber = do
let (V2 width height) = engineWindowDimensions engineData let (V2 width height) = engineWindowDimensions engineData
camPosition = V3 camPosition = V3
(-10 * sin (fromIntegral frameNumber / 90)) (-10 * sin (fromIntegral frameNumber / 90))
(-2) 2
(-10 * cos (fromIntegral frameNumber / 90)) (-10 * cos (fromIntegral frameNumber / 90))
camCenter = V3 0 0 0 camCenter = V3 0 0 0
camUp = V3 0 1 0 camUp = V3 0 1 0
@ -80,6 +81,7 @@ drawFrame engineData frameNumber = do
cameraData cameraData
recordCommandBuffer recordCommandBuffer
(engineData.engineAllocator)
(frameMainCommandBuffer frame) (frameMainCommandBuffer frame)
(engineRenderPass engineData) (engineRenderPass engineData)
(engineFramebuffers engineData V.! fromIntegral index) (engineFramebuffers engineData V.! fromIntegral index)

View file

@ -10,6 +10,7 @@ import Control.Monad
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.Trans.Resource import Control.Monad.Trans.Resource
import Data.Bits
import qualified Data.Map.Strict as M import qualified Data.Map.Strict as M
import Data.Maybe import Data.Maybe
import qualified Data.Vector as V import qualified Data.Vector as V
@ -305,7 +306,9 @@ initDescriptors device = do
, Vk.bindings = V.singleton textureBind , Vk.bindings = V.singleton textureBind
} }
poolInfo = Vk.zero poolInfo = Vk.zero
{ Vk.flags = Vk.DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT { Vk.flags =
Vk.DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT .|.
Vk.DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
, Vk.maxSets = 10 , Vk.maxSets = 10
, Vk.poolSizes = V.fromList , Vk.poolSizes = V.fromList
[ Vk.zero [ Vk.zero
@ -333,10 +336,10 @@ initDescriptors device = do
(_, descriptorSetLayout2) <- (_, descriptorSetLayout2) <-
Vk.withDescriptorSetLayout device setInfo2 Nothing allocate Vk.withDescriptorSetLayout device setInfo2 Nothing allocate
(_, descriptorPool) <-
Vk.withDescriptorPool device poolInfo Nothing allocate
(_, textureDescriptorSetLayout) <- (_, textureDescriptorSetLayout) <-
Vk.withDescriptorSetLayout device setInfo3 Nothing allocate Vk.withDescriptorSetLayout device setInfo3 Nothing allocate
(_, descriptorPool) <-
Vk.withDescriptorPool device poolInfo Nothing allocate
return (descriptorSetLayout1, descriptorSetLayout2, textureDescriptorSetLayout, descriptorPool) return (descriptorSetLayout1, descriptorSetLayout2, textureDescriptorSetLayout, descriptorPool)

View file

@ -1,6 +1,8 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedRecordDot #-}
module Main where module Main where
import qualified Control.Concurrent.STM as STM import qualified Control.Concurrent.STM as STM
@ -9,10 +11,12 @@ import Control.Monad.Loops
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.Trans.Resource import Control.Monad.Trans.Resource
import Data.Bits import Data.Bits
import Data.ByteString.Char8
import qualified Data.Map.Strict as M import qualified Data.Map.Strict as M
import Data.Time.Clock
import qualified Data.Vector as V import qualified Data.Vector as V
import Data.Word
import qualified SDL hiding (V2) import qualified SDL hiding (V2)
import System.IO (stdout)
import System.Mem import System.Mem
import qualified Vulkan as Vk import qualified Vulkan as Vk
import qualified Vulkan.Zero as Vk import qualified Vulkan.Zero as Vk
@ -43,6 +47,8 @@ main = do
-- create abort condition for upcoming lop -- create abort condition for upcoming lop
quit <- liftIO $ STM.newTMVarIO True quit <- liftIO $ STM.newTMVarIO True
time <- liftIO $ STM.newTMVarIO =<< getCurrentTime
average <- liftIO $ STM.newTMVarIO 0
-- main loop -- main loop
whileM_ whileM_
@ -50,11 +56,24 @@ main = do
) )
( do ( do
liftIO performMajorGC liftIO performMajorGC
now <- liftIO getCurrentTime
before <- liftIO $ STM.atomically $ STM.swapTMVar time now
let timeDiff = diffUTCTime now before
fps = recip $ nominalDiffTimeToSeconds timeDiff
liftIO $ hPutStr stdout $ pack $ "Current FPS: " <> show (floor fps) <> " \r"
number <- liftIO $ STM.atomically $ do number <- liftIO $ STM.atomically $ do
number <- STM.readTMVar frameNumber number <- STM.readTMVar frameNumber
if number == 0 then
void $ STM.swapTMVar average fps
else do
oldAverage <- STM.readTMVar average
let newAverage = (oldAverage * fromIntegral number + fps) / frameCount
frameCount = fromIntegral number + 1
void $ STM.swapTMVar average newAverage
void $ STM.swapTMVar frameNumber (succ number) void $ STM.swapTMVar frameNumber (succ number)
return number return number
-- draw -- draw
-- liftIO $ putStr $ show (recip $ nominalDiffTimeToSeconds timeDiff) <> "\r"
drawFrame engineData number drawFrame engineData number
-- poll events -- poll events
evs <- liftIO SDL.pollEvents evs <- liftIO SDL.pollEvents
@ -68,6 +87,12 @@ main = do
evs evs
) )
fps <- liftIO $ STM.atomically $ STM.readTMVar average
liftIO $ hPutStr stdout $
"\n" <>
"Average FPS: " <> pack (show fps) <> "\n"
Vk.deviceWaitIdle $ engineLogicalDevice engineData Vk.deviceWaitIdle $ engineLogicalDevice engineData
createBufferView createBufferView
@ -103,7 +128,7 @@ allocateMemory logicalDevice buffer = do
memoryRequirements <- Vk.getBufferMemoryRequirements logicalDevice buffer memoryRequirements <- Vk.getBufferMemoryRequirements logicalDevice buffer
let memoryAllocateInfo = Vk.zero let memoryAllocateInfo = Vk.zero
{ Vk.allocationSize = (Vk.size :: Vk.MemoryRequirements -> Word64) memoryRequirements { Vk.allocationSize = memoryRequirements.size
, Vk.memoryTypeIndex = error ("createBuffer: TODO: populate memoryTypeIndex!" :: String) , Vk.memoryTypeIndex = error ("createBuffer: TODO: populate memoryTypeIndex!" :: String)
} }

View file

@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedRecordDot #-}
module Memory where module Memory where
import Control.Monad.IO.Class import Control.Monad.IO.Class
@ -27,9 +28,9 @@ initAllocator
-> m VMA.Allocator -> m VMA.Allocator
initAllocator physicalDevice device instance' = do initAllocator physicalDevice device instance' = do
let instanceProcAddr = castFunPtr $ let instanceProcAddr = castFunPtr $
Vk.pVkGetInstanceProcAddr ((Vk.instanceCmds :: Vk.Instance -> Vk.InstanceCmds) instance') Vk.pVkGetInstanceProcAddr (instance'.instanceCmds)
deviceProcAddr = castFunPtr $ deviceProcAddr = castFunPtr $
Vk.pVkGetDeviceProcAddr ((Vk.deviceCmds :: Vk.Device -> Vk.DeviceCmds) device) Vk.pVkGetDeviceProcAddr (device.deviceCmds)
let allocatorInfo = Vk.zero let allocatorInfo = Vk.zero
{ VMA.physicalDevice = Vk.physicalDeviceHandle physicalDevice { VMA.physicalDevice = Vk.physicalDeviceHandle physicalDevice
, VMA.device = Vk.deviceHandle device , VMA.device = Vk.deviceHandle device

View file

@ -16,8 +16,6 @@ import qualified Data.Map.Strict as M
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import qualified Data.Vector as V import qualified Data.Vector as V
import Debug.Trace
import Foreign import Foreign
import Linear (V2(..), V3(..), V4(..)) import Linear (V2(..), V3(..), V4(..))
@ -40,9 +38,9 @@ loadMeshes
-> m () -> m ()
loadMeshes allocator uploadContext queue device = do loadMeshes allocator uploadContext queue device = do
let triangle = V.fromList let triangle = V.fromList
[ Vertex (V3 0.5 0.5 0) (V3 0 0 0) (V4 0 1 0 1) (V2 0 0) [ Vertex (V3 0.5 0 0) (V3 0 0 0) (V4 0 1 0 1) (V2 0 0)
, Vertex (V3 (-0.5) 0.5 0) (V3 0 0 0) (V4 0 1 0 1) (V2 0 0) , Vertex (V3 (-0.5) 0 0) (V3 0 0 0) (V4 0 1 0 1) (V2 0 0)
, Vertex (V3 0 (-0.5) 0) (V3 0 0 0) (V4 0 1 0 1) (V2 0 0) , Vertex (V3 0 1 0) (V3 0 0 0) (V4 0 1 0 1) (V2 0 0)
] ]
triMesh <- uploadMesh triangle allocator uploadContext queue device triMesh <- uploadMesh triangle allocator uploadContext queue device
@ -190,4 +188,39 @@ loadFromObj filepath vma uploadContext queue device = do
texCoords V.! texCoords V.!
(fromMaybe (error "no UV coordinates present") (faceTexCoordIndex index) - 1) (fromMaybe (error "no UV coordinates present") (faceTexCoordIndex index) - 1)
in in
V2 r s -- flip V coordinate of UVs to fix display
V2 r (-s)
compactDraws
:: M.Map String Mesh
-> M.Map String Material
-> V.Vector RenderObject
-> V.Vector IndirectBatch
compactDraws meshLib materialLib objects =
V.foldl
(\acc (index, RenderObject mesh material _) ->
let newDraw = IndirectBatch
{ batchMesh = meshLib M.! mesh
, batchMaterial = materialLib M.! material
, batchFirst = index
, batchCount = 1
}
sameMesh = not (V.null acc) && (meshLib M.! mesh == batchMesh (V.last acc))
sameMaterial = not (V.null acc) && (materialLib M.! material == batchMaterial (V.last acc))
in
if sameMesh && sameMaterial
then
V.init acc `V.snoc` ((V.last acc)
{ batchCount = batchCount (V.last acc) + 1
})
else
acc `V.snoc` newDraw
)
V.empty
(V.zip
(V.fromList [0..])
objects
)

View file

@ -54,13 +54,17 @@ data AllocatedBuffer = AllocatedBuffer
} }
deriving (Show) deriving (Show)
instance Eq AllocatedBuffer where
(AllocatedBuffer buf1 _ _) == (AllocatedBuffer buf2 _ _) = buf1 == buf2
data Vertex = Vertex data Vertex = Vertex
{ vertexPosition :: V3 Float { vertexPosition :: V3 Float
, vertexNormal :: V3 Float , vertexNormal :: V3 Float
, vertexColor :: V4 Float , vertexColor :: V4 Float
, vertexUV :: V2 Float , vertexUV :: V2 Float
} }
deriving (Show) deriving (Show, Eq)
instance Storable Vertex where instance Storable Vertex where
@ -143,7 +147,7 @@ data Mesh = Mesh
{ meshVertices :: V.Vector Vertex { meshVertices :: V.Vector Vertex
, meshBuffer :: AllocatedBuffer , meshBuffer :: AllocatedBuffer
} }
deriving (Show) deriving (Show, Eq)
data MeshPushConstants = MeshPushConstants data MeshPushConstants = MeshPushConstants
{ meshPushData :: V4 Float { meshPushData :: V4 Float
@ -180,7 +184,7 @@ data Material = Material
, materialPipeline :: Vk.Pipeline , materialPipeline :: Vk.Pipeline
, materialPipelineLayout :: Vk.PipelineLayout , materialPipelineLayout :: Vk.PipelineLayout
} }
deriving (Show) deriving (Show, Eq)
data RenderObject = RenderObject data RenderObject = RenderObject
{ objectMesh :: String { objectMesh :: String
@ -223,6 +227,7 @@ data FrameData = FrameData
, frameCameraBuffer :: AllocatedBuffer , frameCameraBuffer :: AllocatedBuffer
, frameSceneBuffer :: AllocatedBuffer , frameSceneBuffer :: AllocatedBuffer
, frameObjectBuffer :: AllocatedBuffer , frameObjectBuffer :: AllocatedBuffer
, frameIndirectBuffer :: AllocatedBuffer
, frameGlobalDescriptor :: Vk.DescriptorSet , frameGlobalDescriptor :: Vk.DescriptorSet
, frameObjectDescriptor :: Vk.DescriptorSet , frameObjectDescriptor :: Vk.DescriptorSet
} }
@ -317,3 +322,10 @@ data UploadContext = UploadContext
, uploadCommandBuffer :: Vk.CommandBuffer , uploadCommandBuffer :: Vk.CommandBuffer
} }
deriving (Show) deriving (Show)
data IndirectBatch = IndirectBatch
{ batchMesh :: Mesh
, batchMaterial :: Material
, batchFirst :: Word32
, batchCount :: Word32
}

46
test.nix Normal file
View file

@ -0,0 +1,46 @@
{pkgs, vulkan-tutorial, ...}:
pkgs.nixosTest ({
name = "test";
nodes = {
machine = { config, pkgs, ...}: {
environment = {
systemPackages = with pkgs; [
vulkan-tutorial
git
shaderc
vulkan-loader
vulkan-validation-layers
];
sessionVariables = {
VK_LAYER_PATH="${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d";
SDL_VULKAN_LIBRARY="${pkgs.vulkan-loader}/lib/libvulkan.so";
};
};
hardware.opengl = {
enable = true;
driSupport = true;
driSupport32Bit = true;
};
services.xserver = {
enable = true;
displayManager.sddm.enable = true;
desktopManager.cinnamon.enable = true;
};
users.users.test = {
password = "test";
extraGroups = [
"wheel"
];
isNormalUser = true;
};
};
};
skipLint = true;
testScript = ''
start_all()
machine.shell_interact()
'';
})

View file

@ -41,7 +41,7 @@ executable vulkan-tutorial
-- LANGUAGE extensions used by modules in this package. -- LANGUAGE extensions used by modules in this package.
-- other-extensions: -- other-extensions:
build-depends: base >=4.14.3.0 build-depends: base
, sdl2 , sdl2
, vulkan , vulkan
, vulkan-utils , vulkan-utils
@ -50,6 +50,7 @@ executable vulkan-tutorial
, linear , linear
, monad-loops , monad-loops
, stm , stm
, time
, bytestring , bytestring
, text , text
, vector , vector