Compare commits
No commits in common. "main" and "textures" have entirely different histories.
13 changed files with 93 additions and 242 deletions
12
flake.lock
12
flake.lock
|
@ -5,11 +5,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1694529238,
|
"lastModified": 1681202837,
|
||||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -20,11 +20,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1699181587,
|
"lastModified": 1684120848,
|
||||||
"narHash": "sha256-v35mUUgVU2ituIHPNHifpjl5uiYQYyLrpaMtz8X8Ums=",
|
"narHash": "sha256-gIwJ5ac1FwZEkCRwjY+gLwgD4G1Bw3Xtr2jr2XihMPo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "197629b470f184a47b2a5716312d25b09454bbf8",
|
"rev": "0cb867999eec4085e1c9ca61c09b72261fa63bb4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
45
flake.nix
45
flake.nix
|
@ -11,36 +11,28 @@
|
||||||
let
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
|
||||||
nixos-lib = import (nixpkgs + "/nixos/lib") {};
|
haskellPackages = pkgs.haskellPackages;
|
||||||
|
|
||||||
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 (pkgs.haskell.lib.markUnbroken pkg);
|
pkgs.haskell.lib.doJailbreak (pkg.overrideAttrs (_: { meta = { }; }));
|
||||||
|
|
||||||
packageName = "vulkan-tutorial";
|
packageName = "vulkan-tutorial";
|
||||||
in rec {
|
in rec {
|
||||||
packages.default = haskellPackages.vulkan-tutorial;
|
packages.${packageName} = # (ref:haskell-package-def)
|
||||||
|
haskellPackages.callCabal2nix packageName self rec {
|
||||||
|
# Dependency overrides go here
|
||||||
|
wavefront = jailbreakUnbreak haskellPackages.wavefront;
|
||||||
|
};
|
||||||
|
|
||||||
devShells.default = haskellPackages.shellFor {
|
defaultPackage = self.packages.${system}.${packageName};
|
||||||
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
|
||||||
|
@ -50,6 +42,21 @@
|
||||||
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};
|
||||||
|
#};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,6 @@ layout(set = 2, binding = 0) uniform sampler2D tex1;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 color = texture(tex1, texCoord).xyz;
|
vec3 color = texture(tex1,texCoord).xyz;
|
||||||
outFragColor = vec4(color, inColor.w);
|
outFragColor = vec4(color, inColor.w);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
@ -22,7 +23,7 @@ import qualified VulkanMemoryAllocator as VMA
|
||||||
import Types
|
import Types
|
||||||
import Memory
|
import Memory
|
||||||
import Util
|
import Util
|
||||||
import Mesh (compactDraws)
|
import Data.Maybe (fromMaybe)
|
||||||
|
|
||||||
frameOverlap :: Int
|
frameOverlap :: Int
|
||||||
frameOverlap = 2
|
frameOverlap = 2
|
||||||
|
@ -59,7 +60,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
|
||||||
|
@ -99,15 +100,6 @@ 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
|
||||||
|
@ -169,7 +161,6 @@ 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
|
||||||
}
|
}
|
||||||
|
@ -181,8 +172,7 @@ createFrames
|
||||||
|
|
||||||
recordCommandBuffer
|
recordCommandBuffer
|
||||||
:: (MonadResource m, MonadReader ReadState m, MonadIO m)
|
:: (MonadResource m, MonadReader ReadState m, MonadIO m)
|
||||||
=> VMA.Allocator
|
=> Vk.CommandBuffer
|
||||||
-> Vk.CommandBuffer
|
|
||||||
-> Vk.RenderPass
|
-> Vk.RenderPass
|
||||||
-> Vk.Framebuffer
|
-> Vk.Framebuffer
|
||||||
-> V2 CInt
|
-> V2 CInt
|
||||||
|
@ -190,7 +180,6 @@ recordCommandBuffer
|
||||||
-> FrameData
|
-> FrameData
|
||||||
-> m ()
|
-> m ()
|
||||||
recordCommandBuffer
|
recordCommandBuffer
|
||||||
allocator
|
|
||||||
commandBuffer
|
commandBuffer
|
||||||
renderPass
|
renderPass
|
||||||
frameBuffer
|
frameBuffer
|
||||||
|
@ -232,43 +221,22 @@ 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 draws = compactDraws meshMap materialMap renderObjects
|
let constants = MeshPushConstants
|
||||||
drawCommands = V.map
|
{ meshPushData = V4 0 0 0 0
|
||||||
(\(i, RenderObject mesh _ _) ->
|
, meshRenderMatrix = modelMatrix
|
||||||
Vk.DrawIndirectCommand
|
|
||||||
{ vertexCount = fromIntegral (V.length $ meshVertices $ meshMap M.! mesh)
|
|
||||||
, firstVertex = 0
|
|
||||||
, instanceCount = 1
|
|
||||||
, firstInstance = i
|
|
||||||
}
|
}
|
||||||
)
|
mesh = fromMaybe
|
||||||
(V.zip
|
(error $ "no mesh called " <> meshID <> " present")
|
||||||
(V.fromList [0..])
|
(meshMap M.!? meshID)
|
||||||
renderObjects
|
material = fromMaybe
|
||||||
)
|
(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)
|
||||||
|
@ -299,24 +267,28 @@ 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 ])
|
||||||
|
|
||||||
let indirectOffset = fromIntegral $
|
Vk.cmdDraw commandBuffer (fromIntegral $ V.length $ meshVertices mesh) 1 0 index
|
||||||
first * fromIntegral ( sizeOf (undefined :: Vk.DrawIndirectCommand))
|
)
|
||||||
drawStride = fromIntegral $ sizeOf (undefined :: Vk.DrawIndirectCommand)
|
(V.zip
|
||||||
|
(V.fromList [0 ..])
|
||||||
Vk.cmdDrawIndirect
|
renderObjects
|
||||||
commandBuffer
|
|
||||||
(allocatedBuffer $ frameIndirectBuffer frame)
|
|
||||||
indirectOffset
|
|
||||||
count
|
|
||||||
drawStride
|
|
||||||
)
|
)
|
||||||
draws
|
|
||||||
|
|
||||||
prepareRecording
|
prepareRecording
|
||||||
:: V2 CInt
|
:: V2 CInt
|
||||||
|
@ -326,12 +298,11 @@ 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 = fromIntegral height
|
, Vk.y = 0
|
||||||
, 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{-# 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
|
||||||
|
@ -39,7 +38,7 @@ pickPhysicalDevice vkInstance = do
|
||||||
physDevices
|
physDevices
|
||||||
|
|
||||||
let discretePhysDevices = V.filter
|
let discretePhysDevices = V.filter
|
||||||
(\(_, _, devFeatures) ->
|
(\(_, devProps, 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
|
||||||
)
|
)
|
||||||
|
@ -105,9 +104,6 @@ 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
|
||||||
|
@ -144,9 +140,9 @@ createSwapchain surface surfaceFormats windowDimension logicalDevice allocator =
|
||||||
if
|
if
|
||||||
V.any
|
V.any
|
||||||
(\a ->
|
(\a ->
|
||||||
a.format ==
|
(Vk.format :: Vk.SurfaceFormatKHR -> Vk.Format) a ==
|
||||||
Vk.FORMAT_B8G8R8A8_SRGB
|
Vk.FORMAT_B8G8R8A8_SRGB
|
||||||
&& a.colorSpace ==
|
&& (Vk.colorSpace :: Vk.SurfaceFormatKHR -> Vk.ColorSpaceKHR) a ==
|
||||||
Vk.COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
Vk.COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
surfaceFormats
|
surfaceFormats
|
||||||
then
|
then
|
||||||
|
@ -223,7 +219,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 = surfaceFormat.format
|
, Vk.format = (Vk.format :: Vk.SurfaceFormatKHR -> Vk.Format) surfaceFormat
|
||||||
, 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
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{-# 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
|
||||||
|
@ -58,7 +57,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
|
||||||
|
@ -81,7 +80,6 @@ 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)
|
||||||
|
|
11
src/Init.hs
11
src/Init.hs
|
@ -10,7 +10,6 @@ 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
|
||||||
|
@ -306,9 +305,7 @@ initDescriptors device = do
|
||||||
, Vk.bindings = V.singleton textureBind
|
, Vk.bindings = V.singleton textureBind
|
||||||
}
|
}
|
||||||
poolInfo = Vk.zero
|
poolInfo = Vk.zero
|
||||||
{ Vk.flags =
|
{ Vk.flags = Vk.DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT
|
||||||
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
|
||||||
|
@ -336,10 +333,10 @@ initDescriptors device = do
|
||||||
(_, descriptorSetLayout2) <-
|
(_, descriptorSetLayout2) <-
|
||||||
Vk.withDescriptorSetLayout device setInfo2 Nothing allocate
|
Vk.withDescriptorSetLayout device setInfo2 Nothing allocate
|
||||||
|
|
||||||
(_, textureDescriptorSetLayout) <-
|
|
||||||
Vk.withDescriptorSetLayout device setInfo3 Nothing allocate
|
|
||||||
|
|
||||||
(_, descriptorPool) <-
|
(_, descriptorPool) <-
|
||||||
Vk.withDescriptorPool device poolInfo Nothing allocate
|
Vk.withDescriptorPool device poolInfo Nothing allocate
|
||||||
|
|
||||||
|
(_, textureDescriptorSetLayout) <-
|
||||||
|
Vk.withDescriptorSetLayout device setInfo3 Nothing allocate
|
||||||
|
|
||||||
return (descriptorSetLayout1, descriptorSetLayout2, textureDescriptorSetLayout, descriptorPool)
|
return (descriptorSetLayout1, descriptorSetLayout2, textureDescriptorSetLayout, descriptorPool)
|
||||||
|
|
29
src/Main.hs
29
src/Main.hs
|
@ -1,8 +1,6 @@
|
||||||
{-# 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
|
||||||
|
@ -11,12 +9,10 @@ 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
|
||||||
|
@ -47,8 +43,6 @@ 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_
|
||||||
|
@ -56,24 +50,11 @@ 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
|
||||||
|
@ -87,12 +68,6 @@ 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
|
||||||
|
@ -128,7 +103,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 = memoryRequirements.size
|
{ Vk.allocationSize = (Vk.size :: Vk.MemoryRequirements -> Word64) memoryRequirements
|
||||||
, Vk.memoryTypeIndex = error ("createBuffer: TODO: populate memoryTypeIndex!" :: String)
|
, Vk.memoryTypeIndex = error ("createBuffer: TODO: populate memoryTypeIndex!" :: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
{-# 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
|
||||||
|
@ -28,9 +27,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 (instance'.instanceCmds)
|
Vk.pVkGetInstanceProcAddr ((Vk.instanceCmds :: Vk.Instance -> Vk.InstanceCmds) instance')
|
||||||
deviceProcAddr = castFunPtr $
|
deviceProcAddr = castFunPtr $
|
||||||
Vk.pVkGetDeviceProcAddr (device.deviceCmds)
|
Vk.pVkGetDeviceProcAddr ((Vk.deviceCmds :: Vk.Device -> Vk.DeviceCmds) device)
|
||||||
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
|
||||||
|
|
45
src/Mesh.hs
45
src/Mesh.hs
|
@ -16,6 +16,8 @@ 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(..))
|
||||||
|
@ -38,9 +40,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 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.5) 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)
|
, Vertex (V3 0 (-0.5) 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
|
||||||
|
@ -188,39 +190,4 @@ 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
|
||||||
-- flip V coordinate of UVs to fix display
|
V2 r s
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
18
src/Types.hs
18
src/Types.hs
|
@ -54,17 +54,13 @@ 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, Eq)
|
deriving (Show)
|
||||||
|
|
||||||
instance Storable Vertex where
|
instance Storable Vertex where
|
||||||
|
|
||||||
|
@ -147,7 +143,7 @@ data Mesh = Mesh
|
||||||
{ meshVertices :: V.Vector Vertex
|
{ meshVertices :: V.Vector Vertex
|
||||||
, meshBuffer :: AllocatedBuffer
|
, meshBuffer :: AllocatedBuffer
|
||||||
}
|
}
|
||||||
deriving (Show, Eq)
|
deriving (Show)
|
||||||
|
|
||||||
data MeshPushConstants = MeshPushConstants
|
data MeshPushConstants = MeshPushConstants
|
||||||
{ meshPushData :: V4 Float
|
{ meshPushData :: V4 Float
|
||||||
|
@ -184,7 +180,7 @@ data Material = Material
|
||||||
, materialPipeline :: Vk.Pipeline
|
, materialPipeline :: Vk.Pipeline
|
||||||
, materialPipelineLayout :: Vk.PipelineLayout
|
, materialPipelineLayout :: Vk.PipelineLayout
|
||||||
}
|
}
|
||||||
deriving (Show, Eq)
|
deriving (Show)
|
||||||
|
|
||||||
data RenderObject = RenderObject
|
data RenderObject = RenderObject
|
||||||
{ objectMesh :: String
|
{ objectMesh :: String
|
||||||
|
@ -227,7 +223,6 @@ 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
|
||||||
}
|
}
|
||||||
|
@ -322,10 +317,3 @@ 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
46
test.nix
|
@ -1,46 +0,0 @@
|
||||||
{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()
|
|
||||||
'';
|
|
||||||
})
|
|
|
@ -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
|
build-depends: base >=4.14.3.0
|
||||||
, sdl2
|
, sdl2
|
||||||
, vulkan
|
, vulkan
|
||||||
, vulkan-utils
|
, vulkan-utils
|
||||||
|
@ -50,7 +50,6 @@ executable vulkan-tutorial
|
||||||
, linear
|
, linear
|
||||||
, monad-loops
|
, monad-loops
|
||||||
, stm
|
, stm
|
||||||
, time
|
|
||||||
, bytestring
|
, bytestring
|
||||||
, text
|
, text
|
||||||
, vector
|
, vector
|
||||||
|
|
Loading…
Reference in a new issue