@@ -14,18 +14,11 @@ import AutoApply
1414import qualified Codec.Picture as JP
1515import Control.Exception.Safe
1616import Control.Monad.IO.Class
17- import Control.Monad.Trans.Maybe ( MaybeT (.. ) )
1817import Control.Monad.Trans.Reader
1918import Control.Monad.Trans.Resource
2019import Data.Bits
2120import qualified Data.ByteString.Lazy as BSL
22- import Data.Foldable
23- import Data.List ( partition )
24- import Data.Maybe ( catMaybes )
25- import Data.Ord ( comparing )
26- import Data.Text ( Text )
27- import qualified Data.Text as T
28- import Data.Text.Encoding ( decodeUtf8 )
21+ import Data.Functor.Identity ( Identity (.. ) )
2922import qualified Data.Vector as V
3023import Data.Word
3124import Foreign.Marshal.Array ( peekArray )
@@ -55,8 +48,18 @@ import Vulkan.Dynamic ( DeviceCmds
5548 )
5649 )
5750import Vulkan.Extensions.VK_EXT_debug_utils
58- import Vulkan.Extensions.VK_EXT_validation_features
59- import Vulkan.Utils.Debug
51+ import Vulkan.Requirement ( InstanceRequirement (.. ) )
52+ import Vulkan.Utils.Debug ( debugCallbackPtr )
53+ import qualified Vulkan.Utils.Init.Headless as Init
54+ import Vulkan.Utils.Initialization ( createDeviceFromRequirements
55+ , physicalDeviceName
56+ , pickPhysicalDevice
57+ )
58+ import Vulkan.Utils.QueueAssignment ( QueueFamilyIndex (.. )
59+ , QueueSpec (.. )
60+ , assignQueues
61+ , isComputeQueueFamily
62+ )
6063import Vulkan.Utils.ShaderQQ.GLSL.Glslang
6164import Vulkan.Zero
6265import VulkanMemoryAllocator as VMA
@@ -146,7 +149,6 @@ autoapplyDecs
146149 , 'withCommandPool
147150 , 'withFence
148151 , 'withComputePipelines
149- , 'withInstance
150152 , 'withPipelineLayout
151153 , 'withShaderModule
152154 , 'withDescriptorPool
@@ -405,31 +407,22 @@ createShader = do
405407myApiVersion :: Word32
406408myApiVersion = API_VERSION_1_0
407409
408- -- | Create an instance with a debug messenger
410+ -- | Create an instance with a debug messenger and validation layer.
409411createInstance :: MonadResource m => m Instance
410412createInstance = do
411- availableExtensionNames <-
412- toList
413- . fmap extensionName
414- . snd
415- <$> enumerateInstanceExtensionProperties Nothing
416- availableLayerNames <-
417- toList . fmap layerName . snd <$> enumerateInstanceLayerProperties
418-
419- let requiredLayers = []
420- optionalLayers = [" VK_LAYER_KHRONOS_validation" ]
421- requiredExtensions = [EXT_DEBUG_UTILS_EXTENSION_NAME ]
422- optionalExtensions = [EXT_VALIDATION_FEATURES_EXTENSION_NAME ]
423-
424- extensions <- partitionOptReq " extension"
425- availableExtensionNames
426- optionalExtensions
427- requiredExtensions
428- layers <- partitionOptReq " layer"
429- availableLayerNames
430- optionalLayers
431- requiredLayers
432-
413+ inst <- Init. withInstance
414+ (Just zero { applicationName = Nothing , apiVersion = myApiVersion })
415+ [ RequireInstanceExtension
416+ { instanceExtensionLayerName = Nothing
417+ , instanceExtensionName = EXT_DEBUG_UTILS_EXTENSION_NAME
418+ , instanceExtensionMinVersion = minBound
419+ }
420+ ]
421+ [ RequireInstanceLayer
422+ { instanceLayerName = " VK_LAYER_KHRONOS_validation"
423+ , instanceLayerMinVersion = minBound
424+ }
425+ ]
433426 let debugMessengerCreateInfo = zero
434427 { messageSeverity = DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
435428 .|. DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
@@ -438,20 +431,6 @@ createInstance = do
438431 .|. DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
439432 , pfnUserCallback = debugCallbackPtr
440433 }
441- instanceCreateInfo =
442- zero
443- { applicationInfo = Just zero { applicationName = Nothing
444- , apiVersion = myApiVersion
445- }
446- , enabledLayerNames = V. fromList layers
447- , enabledExtensionNames = V. fromList extensions
448- }
449- ::& debugMessengerCreateInfo
450- :& ValidationFeaturesEXT
451- [VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT ]
452- []
453- :& ()
454- (_, inst) <- withInstance' instanceCreateInfo
455434 _ <- withDebugUtilsMessengerEXT inst debugMessengerCreateInfo Nothing allocate
456435 pure inst
457436
@@ -460,89 +439,38 @@ createDevice
460439 => Instance
461440 -> m (PhysicalDevice , PhysicalDeviceInfo , Device )
462441createDevice inst = do
463- (pdi, phys) <- pickPhysicalDevice inst physicalDeviceInfo
442+ mPd <- pickPhysicalDevice inst hasComputeQueue id
443+ (_, phys) <- maybe (throwString " Unable to find appropriate PhysicalDevice" )
444+ pure
445+ mPd
464446 sayErr . (" Using device: " <> ) =<< physicalDeviceName phys
465447
466- let deviceCreateInfo = zero
467- { queueCreateInfos =
468- [ SomeStruct zero { queueFamilyIndex = pdiComputeQueueFamilyIndex pdi
469- , queuePriorities = [1 ]
470- }
471- ]
472- }
473-
474- (_, dev) <- withDevice phys deviceCreateInfo Nothing allocate
475- pure (phys, pdi, dev)
476-
477- ----------------------------------------------------------------
478- -- Physical device tools
479- ----------------------------------------------------------------
480-
481- -- | Get a single PhysicalDevice deciding with a scoring function
482- pickPhysicalDevice
483- :: (MonadIO m , MonadThrow m , Ord a )
484- => Instance
485- -> (PhysicalDevice -> m (Maybe a ))
486- -- ^ Some "score" for a PhysicalDevice, Nothing if it is not to be chosen.
487- -> m (a , PhysicalDevice )
488- pickPhysicalDevice inst devScore = do
489- (_, devs) <- enumeratePhysicalDevices inst
490- scores <- catMaybes
491- <$> sequence [ fmap (, d) <$> devScore d | d <- toList devs ]
492- case scores of
493- [] -> throwString " Unable to find appropriate PhysicalDevice"
494- _ -> pure (maximumBy (comparing fst ) scores)
495-
496- -- | The Ord instance prioritises devices with more memory
497- data PhysicalDeviceInfo = PhysicalDeviceInfo
498- { pdiTotalMemory :: Word64
499- , pdiComputeQueueFamilyIndex :: Word32
448+ mAssign <- assignQueues
449+ phys
450+ (Identity (QueueSpec 1 (\ _ q -> pure (isComputeQueueFamily q))))
451+ (qInfos, getQs) <- maybe (throwString " Unable to assign compute queue" )
452+ pure
453+ mAssign
454+ dev <- createDeviceFromRequirements
455+ []
456+ []
457+ phys
458+ zero { queueCreateInfos = SomeStruct <$> qInfos }
459+ Identity (QueueFamilyIndex computeFamilyIdx, _q) <- liftIO (getQs dev)
460+ pure (phys, PhysicalDeviceInfo computeFamilyIdx, dev)
461+ where
462+ hasComputeQueue :: MonadIO m => PhysicalDevice -> m (Maybe Word64 )
463+ hasComputeQueue phys = do
464+ qProps <- getPhysicalDeviceQueueFamilyProperties phys
465+ if V. any isComputeQueueFamily qProps
466+ then do
467+ heaps <- memoryHeaps <$> getPhysicalDeviceMemoryProperties phys
468+ pure (Just (sum (DI. size <$> heaps)))
469+ else pure Nothing
470+
471+ newtype PhysicalDeviceInfo = PhysicalDeviceInfo
472+ { pdiComputeQueueFamilyIndex :: Word32
500473 -- ^ The queue family index of the first compute queue
501474 }
502475 deriving (Eq , Ord )
503476
504- physicalDeviceInfo
505- :: MonadIO m => PhysicalDevice -> m (Maybe PhysicalDeviceInfo )
506- physicalDeviceInfo phys = runMaybeT $ do
507- pdiTotalMemory <- do
508- heaps <- memoryHeaps <$> getPhysicalDeviceMemoryProperties phys
509- pure $ sum (DI. size <$> heaps)
510- pdiComputeQueueFamilyIndex <- do
511- queueFamilyProperties <- getPhysicalDeviceQueueFamilyProperties phys
512- let isComputeQueue q =
513- (QUEUE_COMPUTE_BIT .&&. queueFlags q) && (queueCount q > 0 )
514- computeQueueIndices = fromIntegral . fst <$> V. filter
515- (isComputeQueue . snd )
516- (V. indexed queueFamilyProperties)
517- MaybeT (pure $ computeQueueIndices V. !? 0 )
518- pure PhysicalDeviceInfo { .. }
519-
520- physicalDeviceName :: MonadIO m => PhysicalDevice -> m Text
521- physicalDeviceName phys = do
522- props <- getPhysicalDeviceProperties phys
523- pure $ decodeUtf8 (deviceName props)
524-
525- ----------------------------------------------------------------
526- -- Utils
527- ----------------------------------------------------------------
528-
529- partitionOptReq
530- :: (Show a , Eq a , MonadIO m ) => Text -> [a ] -> [a ] -> [a ] -> m [a ]
531- partitionOptReq type' available optional required = do
532- let (optHave, optMissing) = partition (`elem` available) optional
533- (reqHave, reqMissing) = partition (`elem` available) required
534- tShow = T. pack . show
535- for_ optMissing
536- $ \ n -> sayErr $ " Missing optional " <> type' <> " : " <> tShow n
537- case reqMissing of
538- [] -> pure ()
539- [x] -> sayErr $ " Missing required " <> type' <> " : " <> tShow x
540- xs -> sayErr $ " Missing required " <> type' <> " s: " <> tShow xs
541- pure (reqHave <> optHave)
542-
543- ----------------------------------------------------------------
544- -- Bit utils
545- ----------------------------------------------------------------
546-
547- (.&&.) :: Bits a => a -> a -> Bool
548- x .&&. y = (/= zeroBits) (x .&. y)
0 commit comments