Compare commits

..

No commits in common. "main" and "textures" have entirely different histories.

13 changed files with 93 additions and 242 deletions

View file

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

View file

@ -11,36 +11,28 @@
let
pkgs = nixpkgs.legacyPackages.${system};
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;
};
haskellPackages = pkgs.haskellPackages;
jailbreakUnbreak = pkg:
pkgs.haskell.lib.doJailbreak (pkgs.haskell.lib.markUnbroken pkg);
pkgs.haskell.lib.doJailbreak (pkg.overrideAttrs (_: { meta = { }; }));
packageName = "vulkan-tutorial";
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 {
packages = p: [ p.vulkan-tutorial ];
defaultPackage = self.packages.${system}.${packageName};
devShell = haskellPackages.shellFor {
packages = p: [ defaultPackage ];
withHoogle = true;
buildInputs = (with haskellPackages; [
haskell-language-server
ghcid
cabal-install
(jailbreakUnbreak wavefront)
]) ++ (with pkgs; [
shaderc
vulkan-loader
@ -50,6 +42,21 @@
VK_LAYER_PATH="${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d";
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

@ -19,6 +19,6 @@ layout(set = 2, binding = 0) uniform sampler2D tex1;
void main()
{
vec3 color = texture(tex1, texCoord).xyz;
vec3 color = texture(tex1,texCoord).xyz;
outFragColor = vec4(color, inColor.w);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,6 +16,8 @@ import qualified Data.Map.Strict as M
import Data.Maybe (fromMaybe)
import qualified Data.Vector as V
import Debug.Trace
import Foreign
import Linear (V2(..), V3(..), V4(..))
@ -38,9 +40,9 @@ loadMeshes
-> m ()
loadMeshes allocator uploadContext queue device = do
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 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.5 0.5 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 (-0.5) 0) (V3 0 0 0) (V4 0 1 0 1) (V2 0 0)
]
triMesh <- uploadMesh triangle allocator uploadContext queue device
@ -188,39 +190,4 @@ loadFromObj filepath vma uploadContext queue device = do
texCoords V.!
(fromMaybe (error "no UV coordinates present") (faceTexCoordIndex index) - 1)
in
-- 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
)
V2 r s

View file

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

View file

@ -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()
'';
})

View file

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