keid-core-0.1.7.2: src/Engine/Setup.hs
{-# LANGUAGE CPP #-}
module Engine.Setup where
import RIO
import UnliftIO.Resource (MonadResource)
import UnliftIO.Resource qualified as Resource
import Vulkan.Core10 qualified as Vk
import Vulkan.Extensions.VK_EXT_debug_utils qualified as Ext
import Vulkan.Extensions.VK_KHR_get_physical_device_properties2 qualified as Khr
import Vulkan.Extensions.VK_KHR_surface qualified as Khr
import Vulkan.Requirement (InstanceRequirement(..))
import Vulkan.Utils.Initialization (createInstanceFromRequirements)
import Vulkan.Utils.QueueAssignment (QueueFamilyIndex(..))
import Vulkan.Zero (zero)
import VulkanMemoryAllocator qualified as VMA
#if MIN_VERSION_vulkan(3,15,0)
import Foreign.Ptr (castFunPtr)
import Vulkan.Dynamic qualified as VkDynamic
#endif
import Engine.Setup.Device (allocatePhysical, allocateLogical)
import Engine.Setup.Window qualified as Window
import Engine.Types (GlobalHandles(..))
import Engine.Types.Options (Options(..))
import Engine.Vulkan.Swapchain (SwapchainResources)
import Engine.Vulkan.Types (PhysicalDeviceInfo(..))
import Engine.Vulkan.Types qualified as Vulkan
import Engine.Worker qualified as Worker
import Engine.StageSwitch (newStageSwitchVar)
setup
:: ( HasLogFunc env
, MonadResource (RIO env)
)
=> Options -> RIO env (GlobalHandles, Maybe SwapchainResources)
setup ghOptions = do
logDebug $ displayShow ghOptions
(windowReqs, ghWindow) <- Window.allocate
(optionsFullscreen ghOptions)
(optionsSize ghOptions)
(optionsDisplay ghOptions)
Window.pickLargest
"Keid Engine"
logDebug "Creating instance"
ghInstance <- createInstanceFromRequirements
(deviceProps : debugUtils : windowReqs)
mempty
zero
logDebug "Creating surface"
(_surfaceKey, ghSurface) <- Window.allocateSurface ghWindow ghInstance
logDebug "Creating physical device"
(ghPhysicalDeviceInfo, ghPhysicalDevice) <- allocatePhysical
ghInstance
(Just ghSurface)
pdiTotalMemory
logDebug "Creating logical device"
ghDevice <- allocateLogical ghPhysicalDeviceInfo ghPhysicalDevice
logDebug "Creating VMA"
let
allocatorCI :: VMA.AllocatorCreateInfo
allocatorCI = zero
{ VMA.physicalDevice = Vk.physicalDeviceHandle ghPhysicalDevice
, VMA.device = Vk.deviceHandle ghDevice
, VMA.instance' = Vk.instanceHandle ghInstance
, VMA.vulkanFunctions = Just $ vmaVulkanFunctions ghDevice ghInstance
}
(_vmaKey, ghAllocator) <- VMA.withAllocator allocatorCI Resource.allocate
toIO (logDebug "Releasing VMA") >>= Resource.register
ghQueues <- liftIO $ pdiGetQueues ghPhysicalDeviceInfo ghDevice
logDebug $ "Got command queues: " <> displayShow (fmap (unQueueFamilyIndex . fst) ghQueues)
screen <- liftIO $ Window.getExtent2D ghWindow
ghScreenVar <- Worker.newVar screen
ghStageSwitch <- newStageSwitchVar
pure (GlobalHandles{..}, Nothing)
vmaVulkanFunctions
:: Vk.Device
-> Vk.Instance
-> VMA.VulkanFunctions
#if MIN_VERSION_vulkan(3,15,0)
vmaVulkanFunctions Vk.Device{deviceCmds} Vk.Instance{instanceCmds} =
zero
{ VMA.vkGetInstanceProcAddr =
castFunPtr $ VkDynamic.pVkGetInstanceProcAddr instanceCmds
, VMA.vkGetDeviceProcAddr =
castFunPtr $ VkDynamic.pVkGetDeviceProcAddr deviceCmds
}
#else
vmaVulkanFunctions _device _instance = zero
#endif
setupHeadless
:: ( HasLogFunc env
, MonadResource (RIO env)
)
=> Options
-> RIO env Headless
setupHeadless opts = do
logDebug $ displayShow opts
logDebug "Creating instance"
hInstance <- createInstanceFromRequirements
(deviceProps : debugUtils : headlessReqs)
mempty
zero
logDebug "Creating physical device"
(hPhysicalDeviceInfo, hPhysicalDevice) <- allocatePhysical
hInstance
Nothing
pdiTotalMemory
logDebug "Creating logical device"
hDevice <- allocateLogical hPhysicalDeviceInfo hPhysicalDevice
logDebug "Creating VMA"
let
allocatorCI :: VMA.AllocatorCreateInfo
allocatorCI = zero
{ VMA.physicalDevice = Vk.physicalDeviceHandle hPhysicalDevice
, VMA.device = Vk.deviceHandle hDevice
, VMA.instance' = Vk.instanceHandle hInstance
, VMA.vulkanFunctions = Just $ vmaVulkanFunctions hDevice hInstance
}
(_vmaKey, hAllocator) <- VMA.withAllocator allocatorCI Resource.allocate
toIO (logDebug "Releasing VMA") >>= Resource.register
hQueues <- liftIO $ pdiGetQueues hPhysicalDeviceInfo hDevice
logDebug $ "Got command queues: " <> displayShow (fmap (unQueueFamilyIndex . fst) hQueues)
pure Headless{..}
data Headless = Headless
{ hInstance :: Vk.Instance
, hPhysicalDeviceInfo :: Vulkan.PhysicalDeviceInfo
, hPhysicalDevice :: Vk.PhysicalDevice
, hDevice :: Vk.Device
, hAllocator :: VMA.Allocator
, hQueues :: Vulkan.Queues (QueueFamilyIndex, Vk.Queue)
}
instance Vulkan.HasVulkan Headless where
getInstance = hInstance
getQueues = hQueues
getPhysicalDevice = hPhysicalDevice
getPhysicalDeviceInfo = hPhysicalDeviceInfo
getDevice = hDevice
getAllocator = hAllocator
deviceProps :: InstanceRequirement
deviceProps = RequireInstanceExtension
Nothing
Khr.KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
minBound
debugUtils :: InstanceRequirement
debugUtils = RequireInstanceExtension
Nothing
Ext.EXT_DEBUG_UTILS_EXTENSION_NAME
minBound
headlessReqs :: [InstanceRequirement]
headlessReqs =
[ RequireInstanceExtension
Nothing
Khr.KHR_SURFACE_EXTENSION_NAME
minBound
]