151 lines
4 KiB
Haskell
151 lines
4 KiB
Haskell
|
{-# LANGUAGE OverloadedStrings #-}
|
||
|
{-# LANGUAGE OverloadedLists #-}
|
||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||
|
{-# LANGUAGE DataKinds #-}
|
||
|
module Main where
|
||
|
|
||
|
import Control.Monad
|
||
|
import Control.Monad.Loops
|
||
|
import Control.Monad.IO.Class
|
||
|
import Control.Monad.Trans.Resource
|
||
|
import Control.Monad.Trans.Maybe
|
||
|
import Data.Bits
|
||
|
import qualified Data.ByteString as BS
|
||
|
import Data.Maybe (isNothing, fromMaybe)
|
||
|
import qualified Data.Text as T
|
||
|
import qualified Data.Vector as V
|
||
|
import Data.Word
|
||
|
import Data.List as L
|
||
|
import Linear
|
||
|
import qualified SDL
|
||
|
import qualified SDL.Video.Vulkan as SDL
|
||
|
import qualified Control.Concurrent.STM as STM
|
||
|
import Data.Foldable
|
||
|
import Foreign.Ptr
|
||
|
import qualified Vulkan as Vk
|
||
|
import qualified Vulkan.CStruct.Extends as Vk
|
||
|
import qualified Vulkan.Extensions as Vk
|
||
|
import qualified Vulkan.Requirement as Vk
|
||
|
import qualified Vulkan.Core10 as Vk
|
||
|
import qualified Vulkan.Core11 as Vk
|
||
|
import qualified Vulkan.Core12 as Vk
|
||
|
import qualified Vulkan.Utils.Initialization as Vk
|
||
|
import qualified Vulkan.Utils.QueueAssignment as Vk
|
||
|
import qualified Vulkan.Utils.Requirements as Vk
|
||
|
import qualified Vulkan.Zero as Vk
|
||
|
|
||
|
myApiVersion :: Word32
|
||
|
myApiVersion = Vk.API_VERSION_1_2
|
||
|
|
||
|
main :: IO ()
|
||
|
main = runResourceT $ do
|
||
|
window <- initEngine
|
||
|
|
||
|
SDL.showWindow window
|
||
|
|
||
|
-- create abort condition for upcoming lop
|
||
|
quit <- liftIO $ STM.newTMVarIO True
|
||
|
|
||
|
-- main loop
|
||
|
liftIO $ whileM_
|
||
|
(STM.atomically $ STM.readTMVar quit
|
||
|
)
|
||
|
( do
|
||
|
-- poll events
|
||
|
evs <- SDL.pollEvents
|
||
|
-- flip abort condition on window close
|
||
|
mapM_
|
||
|
(\e -> case SDL.eventPayload e of
|
||
|
SDL.WindowClosedEvent _ ->
|
||
|
void $ STM.atomically $ STM.swapTMVar quit False
|
||
|
_ -> return ()
|
||
|
)
|
||
|
evs
|
||
|
)
|
||
|
|
||
|
quitEngine window
|
||
|
|
||
|
initEngine :: MonadResource m => m SDL.Window
|
||
|
initEngine = do
|
||
|
-- initialize SDL2 with all subsystems
|
||
|
SDL.initializeAll
|
||
|
|
||
|
-- create a window configuration
|
||
|
let windowConfig = SDL.defaultWindow
|
||
|
{ SDL.windowGraphicsContext = SDL.VulkanContext -- enable Vulkan support
|
||
|
}
|
||
|
|
||
|
-- load vulkan library
|
||
|
SDL.vkLoadLibrary Nothing
|
||
|
|
||
|
-- create the window
|
||
|
window <- SDL.createWindow "Vulkan window" windowConfig
|
||
|
|
||
|
initVulkan window
|
||
|
|
||
|
return window
|
||
|
|
||
|
initVulkan :: MonadResource m => SDL.Window -> m ()
|
||
|
initVulkan window = do
|
||
|
|
||
|
vulkanInstance <- createInstance window
|
||
|
vulkanDevice <- pickPhysicalDevice vulkanInstance
|
||
|
liftIO $ print vulkanDevice
|
||
|
|
||
|
return ()
|
||
|
|
||
|
|
||
|
quitEngine :: MonadResource m => SDL.Window -> m ()
|
||
|
quitEngine window = liftIO $ do
|
||
|
-- destroy window
|
||
|
SDL.destroyWindow window
|
||
|
|
||
|
-- quit SDL
|
||
|
SDL.quit
|
||
|
|
||
|
createInstance :: MonadResource m => SDL.Window -> m Vk.Instance
|
||
|
createInstance window = do
|
||
|
windowExtensions <- liftIO $
|
||
|
traverse BS.packCString =<< SDL.vkGetInstanceExtensions window
|
||
|
let createInfo = Vk.zero
|
||
|
{ Vk.applicationInfo = Just Vk.zero
|
||
|
{ Vk.applicationName = Nothing
|
||
|
, Vk.apiVersion = myApiVersion
|
||
|
}
|
||
|
}
|
||
|
requirements =
|
||
|
(\n -> Vk.RequireInstanceExtension Nothing n minBound) <$>
|
||
|
( Vk.KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
|
||
|
: windowExtensions
|
||
|
)
|
||
|
Vk.createInstanceFromRequirements requirements [] createInfo
|
||
|
|
||
|
pickPhysicalDevice :: MonadResource m => Vk.Instance -> m Vk.PhysicalDevice
|
||
|
pickPhysicalDevice inst = do
|
||
|
(_, devices) <- Vk.enumeratePhysicalDevices inst
|
||
|
when (V.null devices) (error "Failed to find GPUs with Vulkan support")
|
||
|
mDevice <- V.foldM
|
||
|
(\acc dev -> do
|
||
|
suitability <- isDeviceSuitable dev
|
||
|
if suitability && isNothing acc
|
||
|
then
|
||
|
return (Just dev)
|
||
|
else
|
||
|
return acc
|
||
|
)
|
||
|
Nothing
|
||
|
devices
|
||
|
return $ fromMaybe
|
||
|
(error "Failed to find suitable GPU")
|
||
|
mDevice
|
||
|
|
||
|
isDeviceSuitable :: MonadResource m => Vk.PhysicalDevice -> m Bool
|
||
|
isDeviceSuitable device = do
|
||
|
props <- Vk.getPhysicalDeviceProperties device
|
||
|
features <- Vk.getPhysicalDeviceFeatures device
|
||
|
|
||
|
return
|
||
|
( Vk.deviceType props == Vk.PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
|
||
|
Vk.geometryShader features
|
||
|
)
|