{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP                 #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE MagicHash           #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Strict              #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE TypeFamilies        #-}
-- | This module allows to load vulkan symbols at runtime.
--
--   It is based on Vulkan API function
--   <https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html vkGetInstanceProcAddr>
--   that is a part of Vulkan core 1.0.
--   Also, have a look at
--   <https://vulkan.lunarg.com/doc/view/1.1.70.1/windows/loader_and_layer_interface.html#user-content-instance-versus-device Vulkan loader>
--   page to see other reasons to load symbols manually.
--
--   All FFI functions are present in two variants:
--   @xxxUnsafe@ and @xxxSafe@, the names stand for @foreign import unsafe xxx@
--   @foreign import safe xxx@ respectively.
--   In particular, that does not mean that @vkGetXxxProcSafe@ function cannot fail;
--   it does error if the symbol is not present in the implementation!
module Graphics.Vulkan.Marshal.Proc
  ( VulkanProc (..)
  , vkGetInstanceProc, vkGetInstanceProcUnsafe, vkGetInstanceProcSafe
  , vkLookupInstanceProc, vkLookupInstanceProcUnsafe, vkLookupInstanceProcSafe
  , vkGetDeviceProc, vkGetDeviceProcUnsafe, vkGetDeviceProcSafe
  , vkLookupDeviceProc, vkLookupDeviceProcUnsafe, vkLookupDeviceProcSafe
  , vkGetProc, vkGetProcUnsafe, vkGetProcSafe
  , vkLookupProc, vkLookupProcUnsafe, vkLookupProcSafe
    -- * Re-export `Foreign.Ptr`
  , FunPtr, nullFunPtr
  ) where

import           Control.Monad                 (when)
import           Data.Void                     (Void)
import           Foreign.C.String              (CString, peekCString)
import           Foreign.ForeignPtr            (ForeignPtr, newForeignPtr,
                                                withForeignPtr)
import           Foreign.Marshal.Alloc         (alloca)
import           Foreign.Ptr                   (FunPtr, nullFunPtr, nullPtr)
import           Foreign.Storable              (peek)
import           GHC.Ptr                       (Ptr (..))
import           GHC.TypeLits                  (Symbol)
import           System.IO.Unsafe              (unsafePerformIO)



import           Graphics.Vulkan.Types.Handles (VkDevice, VkInstance)

-- | Some of the vulkan functions defined in vulkan extensions are not
--   available at the program linking time.
--   These functions should be discovered at runtime.
--   Vulkan api provides special functions for this,
--     called @vkGetInstanceProcAddr@ and @vkGetDeviceProcAddr@.
--   This class provides a simpler discovery mechanism based on that function.
--   For example, you can get @vkCreateDebugReportCallbackEXT@ function
--   as follows:
--
--   > vkGetInstanceProc @VkCreateDebugReportCallbackEXT vkInstance
class VulkanProc (proc :: Symbol) where
    -- | Haskell signature for the vulkan function
    type VkProcType proc
    -- | Name of the vulkan function
    vkProcSymbol :: CString
    -- | Convert C function pointer to an ordinary haskell function.
    --   Use unsafe FFI (@foreign import unsafe "dynamic" ...@).
    unwrapVkProcPtrUnsafe :: FunPtr (VkProcType proc) -> VkProcType proc
    -- | Convert C function pointer to an ordinary haskell function.
    --   Use safe FFI (@foreign import safe "dynamic" ...@).
    unwrapVkProcPtrSafe :: FunPtr (VkProcType proc) -> VkProcType proc



--------------------------------------------------------------------------------
-- Unsafe FFI version
--------------------------------------------------------------------------------





-- | An alternative to @vkGetInstanceProcAddr@ with type inference
--   and protection against typos.
--
--   Note, this is an unsafe function;
--   it does not check if the result of @vkGetInstanceProcAddr@
--   is a null function pointer.
vkGetInstanceProcUnsafe :: forall proc . VulkanProc proc
                        => VkInstance -> IO (VkProcType proc)
vkGetInstanceProcUnsafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (VkProcType proc)
vkGetInstanceProcUnsafe VkInstance
i
  = forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrUnsafe @proc
  (FunPtr (VkProcType proc) -> VkProcType proc)
-> IO (FunPtr (VkProcType proc)) -> IO (VkProcType proc)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkInstance -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrUnsafe VkInstance
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
{-# INLINE vkGetInstanceProcUnsafe #-}

-- | An alternative to @vkGetInstanceProcAddr@ with type inference
--   and protection against typos.
vkLookupInstanceProcUnsafe :: forall proc . VulkanProc proc
                           => VkInstance -> IO (Maybe (VkProcType proc))
vkLookupInstanceProcUnsafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (Maybe (VkProcType proc))
vkLookupInstanceProcUnsafe VkInstance
i
    = FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f (FunPtr (VkProcType proc) -> Maybe (VkProcType proc))
-> IO (FunPtr (VkProcType proc)) -> IO (Maybe (VkProcType proc))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkInstance -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrUnsafe VkInstance
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
  where
    f :: FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f FunPtr (VkProcType proc)
p = if FunPtr (VkProcType proc)
p FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr then Maybe (VkProcType proc)
forall a. Maybe a
Nothing else VkProcType proc -> Maybe (VkProcType proc)
forall a. a -> Maybe a
Just (forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrUnsafe @proc FunPtr (VkProcType proc)
p)
{-# INLINE vkLookupInstanceProcUnsafe #-}


-- | An alternative to @vkGetDeviceProcAddr@ with type inference
--   and protection against typos.
--
--   Note, this is an unsafe function;
--   it does not check if the result of @vkGetInstanceProcAddr@
--   is a null function pointer.
vkGetDeviceProcUnsafe :: forall proc . VulkanProc proc
                      => VkDevice -> IO (VkProcType proc)
vkGetDeviceProcUnsafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (VkProcType proc)
vkGetDeviceProcUnsafe VkDevice
i
  = forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrUnsafe @proc
  (FunPtr (VkProcType proc) -> VkProcType proc)
-> IO (FunPtr (VkProcType proc)) -> IO (VkProcType proc)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkDevice -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrUnsafe VkDevice
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
{-# INLINE vkGetDeviceProcUnsafe #-}

-- | An alternative to @vkGetDeviceProcAddr@ with type inference
--   and protection against typos.
vkLookupDeviceProcUnsafe :: forall proc . VulkanProc proc
                         => VkDevice -> IO (Maybe (VkProcType proc))
vkLookupDeviceProcUnsafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (Maybe (VkProcType proc))
vkLookupDeviceProcUnsafe VkDevice
i
    = FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f (FunPtr (VkProcType proc) -> Maybe (VkProcType proc))
-> IO (FunPtr (VkProcType proc)) -> IO (Maybe (VkProcType proc))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkDevice -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrUnsafe VkDevice
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
  where
    f :: FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f FunPtr (VkProcType proc)
p = if FunPtr (VkProcType proc)
p FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr then Maybe (VkProcType proc)
forall a. Maybe a
Nothing else VkProcType proc -> Maybe (VkProcType proc)
forall a. a -> Maybe a
Just (forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrUnsafe @proc FunPtr (VkProcType proc)
p)
{-# INLINE vkLookupDeviceProcUnsafe #-}


-- | Locate Vulkan symbol dynamically at runtime using platform-dependent machinery,
--   such as @dlsym@ or @GetProcAddress@.
--   This function throws an error on failure.
--
--   Consider using `vkGetDeviceProc` or `vkGetInstanceProc` for loading a symbol,
--    because they can return a more optimized version of a function.
--   Also note, you are likely not able to lookup an extension funcion using
--   `vkGetProc`, because a corresponding symbol is simply not present in the
--   vulkan loader library.
vkGetProcUnsafe :: forall proc . VulkanProc proc => IO (VkProcType proc)
vkGetProcUnsafe :: forall (proc :: Symbol). VulkanProc proc => IO (VkProcType proc)
vkGetProcUnsafe = (Ptr CString -> IO (VkProcType proc)) -> IO (VkProcType proc)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CString -> IO (VkProcType proc)) -> IO (VkProcType proc))
-> (Ptr CString -> IO (VkProcType proc)) -> IO (VkProcType proc)
forall a b. (a -> b) -> a -> b
$ \Ptr CString
errPtr -> do
    FunPtr (VkProcType proc)
fp <- ForeignPtr Void
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Void
_vkDlHandle ((Ptr Void -> IO (FunPtr (VkProcType proc)))
 -> IO (FunPtr (VkProcType proc)))
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ \Ptr Void
h ->
      Ptr Void -> CString -> Ptr CString -> IO (FunPtr (VkProcType proc))
forall a. Ptr Void -> CString -> Ptr CString -> IO (FunPtr a)
c'vkdll_dlsym Ptr Void
h (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc) Ptr CString
errPtr
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FunPtr (VkProcType proc)
fp FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr CString -> IO CString
forall a. Storable a => Ptr a -> IO a
peek Ptr CString
errPtr IO CString -> (CString -> IO String) -> IO String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CString -> IO String
peekCString IO String -> (String -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> (String -> String) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        (String
"An error happened while trying to load vulkan symbol dynamically: " String -> String -> String
forall a. [a] -> [a] -> [a]
++)
    VkProcType proc -> IO (VkProcType proc)
forall (m :: * -> *) a. Monad m => a -> m a
return (VkProcType proc -> IO (VkProcType proc))
-> VkProcType proc -> IO (VkProcType proc)
forall a b. (a -> b) -> a -> b
$ forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrUnsafe @proc FunPtr (VkProcType proc)
fp
{-# INLINE vkGetProcUnsafe #-}

-- | Locate Vulkan symbol dynamically at runtime using platform-dependent machinery,
--   such as @dlsym@ or @GetProcAddress@.
--   This function returns @Nothing@ on failure ignoring an error message.
--
--   Consider using `vkGetDeviceProc` or `vkGetInstanceProc` for loading a symbol,
--    because they can return a more optimized version of a function.
--   Also note, you are likely not able to lookup an extension funcion using
--   `vkLookupProc`, because a corresponding symbol is simply not present in the
--   vulkan loader library.
vkLookupProcUnsafe :: forall proc . VulkanProc proc => IO (Maybe (VkProcType proc))
vkLookupProcUnsafe :: forall (proc :: Symbol).
VulkanProc proc =>
IO (Maybe (VkProcType proc))
vkLookupProcUnsafe = (Ptr CString -> IO (Maybe (VkProcType proc)))
-> IO (Maybe (VkProcType proc))
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CString -> IO (Maybe (VkProcType proc)))
 -> IO (Maybe (VkProcType proc)))
-> (Ptr CString -> IO (Maybe (VkProcType proc)))
-> IO (Maybe (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ \Ptr CString
errPtr -> do
    FunPtr (VkProcType proc)
fp <- ForeignPtr Void
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Void
_vkDlHandle ((Ptr Void -> IO (FunPtr (VkProcType proc)))
 -> IO (FunPtr (VkProcType proc)))
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ \Ptr Void
h ->
      Ptr Void -> CString -> Ptr CString -> IO (FunPtr (VkProcType proc))
forall a. Ptr Void -> CString -> Ptr CString -> IO (FunPtr a)
c'vkdll_dlsym Ptr Void
h (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc) Ptr CString
errPtr
    Maybe (VkProcType proc) -> IO (Maybe (VkProcType proc))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (VkProcType proc) -> IO (Maybe (VkProcType proc)))
-> Maybe (VkProcType proc) -> IO (Maybe (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ if FunPtr (VkProcType proc)
fp FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr then Maybe (VkProcType proc)
forall a. Maybe a
Nothing else VkProcType proc -> Maybe (VkProcType proc)
forall a. a -> Maybe a
Just (forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrUnsafe @proc FunPtr (VkProcType proc)
fp)
{-# INLINE vkLookupProcUnsafe #-}



--------------------------------------------------------------------------------
-- Safe FFI version
--------------------------------------------------------------------------------



-- | An alternative to @vkGetInstanceProcAddr@ with type inference
--   and protection against typos.
--
--   Note, this is an unsafe function;
--   it does not check if the result of @vkGetInstanceProcAddr@
--   is a null function pointer.
vkGetInstanceProcSafe :: forall proc . VulkanProc proc
                  => VkInstance -> IO (VkProcType proc)
vkGetInstanceProcSafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (VkProcType proc)
vkGetInstanceProcSafe VkInstance
i
  = forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrSafe @proc
  (FunPtr (VkProcType proc) -> VkProcType proc)
-> IO (FunPtr (VkProcType proc)) -> IO (VkProcType proc)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkInstance -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrSafe VkInstance
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
{-# INLINE vkGetInstanceProcSafe #-}

-- | An alternative to @vkGetInstanceProcAddr@ with type inference
--   and protection against typos.
vkLookupInstanceProcSafe :: forall proc . VulkanProc proc
                     => VkInstance -> IO (Maybe (VkProcType proc))
vkLookupInstanceProcSafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (Maybe (VkProcType proc))
vkLookupInstanceProcSafe VkInstance
i
    = FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f (FunPtr (VkProcType proc) -> Maybe (VkProcType proc))
-> IO (FunPtr (VkProcType proc)) -> IO (Maybe (VkProcType proc))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkInstance -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrSafe VkInstance
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
  where
    f :: FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f FunPtr (VkProcType proc)
p = if FunPtr (VkProcType proc)
p FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr then Maybe (VkProcType proc)
forall a. Maybe a
Nothing else VkProcType proc -> Maybe (VkProcType proc)
forall a. a -> Maybe a
Just (forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrSafe @proc FunPtr (VkProcType proc)
p)
{-# INLINE vkLookupInstanceProcSafe #-}


-- | An alternative to @vkGetDeviceProcAddr@ with type inference
--   and protection against typos.
--
--   Note, this is an unsafe function;
--   it does not check if the result of @vkGetInstanceProcAddr@
--   is a null function pointer.
vkGetDeviceProcSafe :: forall proc . VulkanProc proc
                => VkDevice -> IO (VkProcType proc)
vkGetDeviceProcSafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (VkProcType proc)
vkGetDeviceProcSafe VkDevice
i
  = forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrSafe @proc
  (FunPtr (VkProcType proc) -> VkProcType proc)
-> IO (FunPtr (VkProcType proc)) -> IO (VkProcType proc)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkDevice -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrSafe VkDevice
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
{-# INLINE vkGetDeviceProcSafe #-}

-- | An alternative to @vkGetDeviceProcAddr@ with type inference
--   and protection against typos.
vkLookupDeviceProcSafe :: forall proc . VulkanProc proc
                   => VkDevice -> IO (Maybe (VkProcType proc))
vkLookupDeviceProcSafe :: forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (Maybe (VkProcType proc))
vkLookupDeviceProcSafe VkDevice
i
    = FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f (FunPtr (VkProcType proc) -> Maybe (VkProcType proc))
-> IO (FunPtr (VkProcType proc)) -> IO (Maybe (VkProcType proc))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VkDevice -> CString -> IO (FunPtr (VkProcType proc))
forall a. VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrSafe VkDevice
i (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc)
  where
    f :: FunPtr (VkProcType proc) -> Maybe (VkProcType proc)
f FunPtr (VkProcType proc)
p = if FunPtr (VkProcType proc)
p FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr then Maybe (VkProcType proc)
forall a. Maybe a
Nothing else VkProcType proc -> Maybe (VkProcType proc)
forall a. a -> Maybe a
Just (forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrSafe @proc FunPtr (VkProcType proc)
p)
{-# INLINE vkLookupDeviceProcSafe #-}


-- | Locate Vulkan symbol dynamically at runtime using platform-dependent machinery,
--   such as @dlsym@ or @GetProcAddress@.
--   This function throws an error on failure.
--
--   Consider using `vkGetDeviceProc` or `vkGetInstanceProc` for loading a symbol,
--    because they can return a more optimized version of a function.
--   Also note, you are likely not able to lookup an extension funcion using
--   `vkGetProc`, because a corresponding symbol is simply not present in the
--   vulkan loader library.
vkGetProcSafe :: forall proc . VulkanProc proc => IO (VkProcType proc)
vkGetProcSafe :: forall (proc :: Symbol). VulkanProc proc => IO (VkProcType proc)
vkGetProcSafe = (Ptr CString -> IO (VkProcType proc)) -> IO (VkProcType proc)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CString -> IO (VkProcType proc)) -> IO (VkProcType proc))
-> (Ptr CString -> IO (VkProcType proc)) -> IO (VkProcType proc)
forall a b. (a -> b) -> a -> b
$ \Ptr CString
errPtr -> do
    FunPtr (VkProcType proc)
fp <- ForeignPtr Void
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Void
_vkDlHandle ((Ptr Void -> IO (FunPtr (VkProcType proc)))
 -> IO (FunPtr (VkProcType proc)))
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ \Ptr Void
h ->
      Ptr Void -> CString -> Ptr CString -> IO (FunPtr (VkProcType proc))
forall a. Ptr Void -> CString -> Ptr CString -> IO (FunPtr a)
c'vkdll_dlsym Ptr Void
h (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc) Ptr CString
errPtr
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FunPtr (VkProcType proc)
fp FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr CString -> IO CString
forall a. Storable a => Ptr a -> IO a
peek Ptr CString
errPtr IO CString -> (CString -> IO String) -> IO String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CString -> IO String
peekCString IO String -> (String -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> (String -> String) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        (String
"An error happened while trying to load vulkan symbol dynamically: " String -> String -> String
forall a. [a] -> [a] -> [a]
++)
    VkProcType proc -> IO (VkProcType proc)
forall (m :: * -> *) a. Monad m => a -> m a
return (VkProcType proc -> IO (VkProcType proc))
-> VkProcType proc -> IO (VkProcType proc)
forall a b. (a -> b) -> a -> b
$ forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrSafe @proc FunPtr (VkProcType proc)
fp
{-# INLINE vkGetProcSafe #-}

-- | Locate Vulkan symbol dynamically at runtime using platform-dependent machinery,
--   such as @dlsym@ or @GetProcAddress@.
--   This function returns @Nothing@ on failure ignoring an error message.
--
--   Consider using `vkLookupDeviceProc` or `vkLookupInstanceProc` for loading a symbol,
--    because they can return a more optimized version of a function.
--   Also note, you are likely not able to lookup an extension funcion using
--   `vkLookupProc`, because a corresponding symbol is simply not present in the
--   vulkan loader library.
vkLookupProcSafe :: forall proc . VulkanProc proc => IO (Maybe (VkProcType proc))
vkLookupProcSafe :: forall (proc :: Symbol).
VulkanProc proc =>
IO (Maybe (VkProcType proc))
vkLookupProcSafe = (Ptr CString -> IO (Maybe (VkProcType proc)))
-> IO (Maybe (VkProcType proc))
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CString -> IO (Maybe (VkProcType proc)))
 -> IO (Maybe (VkProcType proc)))
-> (Ptr CString -> IO (Maybe (VkProcType proc)))
-> IO (Maybe (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ \Ptr CString
errPtr -> do
    FunPtr (VkProcType proc)
fp <- ForeignPtr Void
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Void
_vkDlHandle ((Ptr Void -> IO (FunPtr (VkProcType proc)))
 -> IO (FunPtr (VkProcType proc)))
-> (Ptr Void -> IO (FunPtr (VkProcType proc)))
-> IO (FunPtr (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ \Ptr Void
h ->
      Ptr Void -> CString -> Ptr CString -> IO (FunPtr (VkProcType proc))
forall a. Ptr Void -> CString -> Ptr CString -> IO (FunPtr a)
c'vkdll_dlsym Ptr Void
h (forall (proc :: Symbol). VulkanProc proc => CString
vkProcSymbol @proc) Ptr CString
errPtr
    Maybe (VkProcType proc) -> IO (Maybe (VkProcType proc))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (VkProcType proc) -> IO (Maybe (VkProcType proc)))
-> Maybe (VkProcType proc) -> IO (Maybe (VkProcType proc))
forall a b. (a -> b) -> a -> b
$ if FunPtr (VkProcType proc)
fp FunPtr (VkProcType proc) -> FunPtr (VkProcType proc) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkProcType proc)
forall a. FunPtr a
nullFunPtr then Maybe (VkProcType proc)
forall a. Maybe a
Nothing else VkProcType proc -> Maybe (VkProcType proc)
forall a. a -> Maybe a
Just (forall (proc :: Symbol).
VulkanProc proc =>
FunPtr (VkProcType proc) -> VkProcType proc
unwrapVkProcPtrSafe @proc FunPtr (VkProcType proc)
fp)
{-# INLINE vkLookupProcSafe #-}



--------------------------------------------------------------------------------
-- Default FFI version
--------------------------------------------------------------------------------



-- | An alternative to @vkGetInstanceProcAddr@ with type inference
--   and protection against typos.
--
--   Note, this is an unsafe function;
--   it does not check if the result of @vkGetInstanceProcAddr@
--   is a null function pointer.
vkGetInstanceProc :: forall proc . VulkanProc proc
                  => VkInstance -> IO (VkProcType proc)
vkGetInstanceProc :: forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (VkProcType proc)
vkGetInstanceProc =
#ifdef UNSAFE_FFI_DEFAULT
  vkGetInstanceProcUnsafe @proc
#else
  forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (VkProcType proc)
vkGetInstanceProcSafe @proc
#endif
{-# INLINE vkGetInstanceProc #-}

-- | An alternative to @vkGetInstanceProcAddr@ with type inference
--   and protection against typos.
vkLookupInstanceProc :: forall proc . VulkanProc proc
                     => VkInstance -> IO (Maybe (VkProcType proc))
vkLookupInstanceProc :: forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (Maybe (VkProcType proc))
vkLookupInstanceProc =
#ifdef UNSAFE_FFI_DEFAULT
  vkLookupInstanceProcUnsafe @proc
#else
  forall (proc :: Symbol).
VulkanProc proc =>
VkInstance -> IO (Maybe (VkProcType proc))
vkLookupInstanceProcSafe @proc
#endif
{-# INLINE vkLookupInstanceProc #-}


-- | An alternative to @vkGetDeviceProcAddr@ with type inference
--   and protection against typos.
--
--   Note, this is an unsafe function;
--   it does not check if the result of @vkGetInstanceProcAddr@
--   is a null function pointer.
vkGetDeviceProc :: forall proc . VulkanProc proc
                => VkDevice -> IO (VkProcType proc)
vkGetDeviceProc :: forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (VkProcType proc)
vkGetDeviceProc =
#ifdef UNSAFE_FFI_DEFAULT
  vkGetDeviceProcUnsafe @proc
#else
  forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (VkProcType proc)
vkGetDeviceProcSafe @proc
#endif
{-# INLINE vkGetDeviceProc #-}

-- | An alternative to @vkGetDeviceProcAddr@ with type inference
--   and protection against typos.
vkLookupDeviceProc :: forall proc . VulkanProc proc
                   => VkDevice -> IO (Maybe (VkProcType proc))
vkLookupDeviceProc :: forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (Maybe (VkProcType proc))
vkLookupDeviceProc =
#ifdef UNSAFE_FFI_DEFAULT
  vkLookupDeviceProcUnsafe @proc
#else
  forall (proc :: Symbol).
VulkanProc proc =>
VkDevice -> IO (Maybe (VkProcType proc))
vkLookupDeviceProcSafe @proc
#endif
{-# INLINE vkLookupDeviceProc #-}


-- | Locate Vulkan symbol dynamically at runtime using platform-dependent machinery,
--   such as @dlsym@ or @GetProcAddress@.
--   This function throws an error on failure.
--
--   Consider using `vkGetDeviceProc` or `vkGetInstanceProc` for loading a symbol,
--    because they can return a more optimized version of a function.
--   Also note, you are likely not able to lookup an extension funcion using
--   `vkGetProc`, because a corresponding symbol is simply not present in the
--   vulkan loader library.
vkGetProc :: forall proc . VulkanProc proc => IO (VkProcType proc)
vkGetProc :: forall (proc :: Symbol). VulkanProc proc => IO (VkProcType proc)
vkGetProc =
#ifdef UNSAFE_FFI_DEFAULT
  vkGetProcUnsafe @proc
#else
  forall (proc :: Symbol). VulkanProc proc => IO (VkProcType proc)
vkGetProcSafe @proc
#endif
{-# INLINE vkGetProc #-}

-- | Locate Vulkan symbol dynamically at runtime using platform-dependent machinery,
--   such as @dlsym@ or @GetProcAddress@.
--   This function returns @Nothing@ on failure ignoring an error message.
--
--   Consider using `vkGetDeviceProc` or `vkGetInstanceProc` for loading a symbol,
--    because they can return a more optimized version of a function.
--   Also note, you are likely not able to lookup an extension funcion using
--   `vkLookupProc`, because a corresponding symbol is simply not present in the
--   vulkan loader library.
vkLookupProc :: forall proc . VulkanProc proc => IO (Maybe (VkProcType proc))
vkLookupProc :: forall (proc :: Symbol).
VulkanProc proc =>
IO (Maybe (VkProcType proc))
vkLookupProc =
#ifdef UNSAFE_FFI_DEFAULT
  vkLookupProcUnsafe @proc
#else
  forall (proc :: Symbol).
VulkanProc proc =>
IO (Maybe (VkProcType proc))
vkLookupProcSafe @proc
#endif
{-# INLINE vkLookupProc #-}




--------------------------------------------------------------------------------
-- Utilities
--------------------------------------------------------------------------------




#ifdef VK_NO_PROTOTYPES

c'vkGetInstanceProcAddrSafe :: VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrSafe :: forall a. VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrSafe = (FunPtr (VkInstance -> CString -> IO (FunPtr a))
 -> VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
forall a.
(FunPtr (VkInstance -> CString -> IO (FunPtr a))
 -> VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddr' FunPtr (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
forall a.
FunPtr (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
unwrap'vkGetInstanceProcAddrSafe

c'vkGetInstanceProcAddrUnsafe :: VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrUnsafe :: forall a. VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddrUnsafe = (FunPtr (VkInstance -> CString -> IO (FunPtr a))
 -> VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
forall a.
(FunPtr (VkInstance -> CString -> IO (FunPtr a))
 -> VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddr' FunPtr (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
forall a.
FunPtr (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
unwrap'vkGetInstanceProcAddrUnsafe

c'vkGetDeviceProcAddrSafe :: VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrSafe :: forall a. VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrSafe = (FunPtr (VkDevice -> CString -> IO (FunPtr a))
 -> VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
forall a.
(FunPtr (VkDevice -> CString -> IO (FunPtr a))
 -> VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddr' FunPtr (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
forall a.
FunPtr (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
unwrap'vkGetDeviceProcAddrSafe

c'vkGetDeviceProcAddrUnsafe :: VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrUnsafe :: forall a. VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddrUnsafe = (FunPtr (VkDevice -> CString -> IO (FunPtr a))
 -> VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
forall a.
(FunPtr (VkDevice -> CString -> IO (FunPtr a))
 -> VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddr' FunPtr (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
forall a.
FunPtr (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
unwrap'vkGetDeviceProcAddrUnsafe

c'vkGetInstanceProcAddr'
    :: ( FunPtr (VkInstance -> CString -> IO (FunPtr a))
          -> VkInstance -> CString -> IO (FunPtr a)
       )
    -> VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddr' :: forall a.
(FunPtr (VkInstance -> CString -> IO (FunPtr a))
 -> VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
c'vkGetInstanceProcAddr' FunPtr (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
k = IO (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
forall a. IO a -> a
unsafePerformIO (IO (VkInstance -> CString -> IO (FunPtr a))
 -> VkInstance -> CString -> IO (FunPtr a))
-> IO (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance
-> CString
-> IO (FunPtr a)
forall a b. (a -> b) -> a -> b
$ (Ptr CString -> IO (VkInstance -> CString -> IO (FunPtr a)))
-> IO (VkInstance -> CString -> IO (FunPtr a))
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CString -> IO (VkInstance -> CString -> IO (FunPtr a)))
 -> IO (VkInstance -> CString -> IO (FunPtr a)))
-> (Ptr CString -> IO (VkInstance -> CString -> IO (FunPtr a)))
-> IO (VkInstance -> CString -> IO (FunPtr a))
forall a b. (a -> b) -> a -> b
$ \Ptr CString
errPtr -> do
    FunPtr (VkInstance -> CString -> IO (FunPtr a))
fp <- ForeignPtr Void
-> (Ptr Void
    -> IO (FunPtr (VkInstance -> CString -> IO (FunPtr a))))
-> IO (FunPtr (VkInstance -> CString -> IO (FunPtr a)))
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Void
_vkDlHandle ((Ptr Void -> IO (FunPtr (VkInstance -> CString -> IO (FunPtr a))))
 -> IO (FunPtr (VkInstance -> CString -> IO (FunPtr a))))
-> (Ptr Void
    -> IO (FunPtr (VkInstance -> CString -> IO (FunPtr a))))
-> IO (FunPtr (VkInstance -> CString -> IO (FunPtr a)))
forall a b. (a -> b) -> a -> b
$ \Ptr Void
h ->
      Ptr Void
-> CString
-> Ptr CString
-> IO (FunPtr (VkInstance -> CString -> IO (FunPtr a)))
forall a. Ptr Void -> CString -> Ptr CString -> IO (FunPtr a)
c'vkdll_dlsym Ptr Void
h (Addr# -> CString
forall a. Addr# -> Ptr a
Ptr Addr#
"vkGetInstanceProcAddr"#) Ptr CString
errPtr
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FunPtr (VkInstance -> CString -> IO (FunPtr a))
fp FunPtr (VkInstance -> CString -> IO (FunPtr a))
-> FunPtr (VkInstance -> CString -> IO (FunPtr a)) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkInstance -> CString -> IO (FunPtr a))
forall a. FunPtr a
nullFunPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      Ptr CString -> IO CString
forall a. Storable a => Ptr a -> IO a
peek Ptr CString
errPtr IO CString -> (CString -> IO String) -> IO String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CString -> IO String
peekCString IO String -> (String -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> (String -> String) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        (String
"Could not load 'vkGetInstanceProcAddr' C function from vulkan library dynamically: " String -> String -> String
forall a. [a] -> [a] -> [a]
++)
    (VkInstance -> CString -> IO (FunPtr a))
-> IO (VkInstance -> CString -> IO (FunPtr a))
forall (m :: * -> *) a. Monad m => a -> m a
return ((VkInstance -> CString -> IO (FunPtr a))
 -> IO (VkInstance -> CString -> IO (FunPtr a)))
-> (VkInstance -> CString -> IO (FunPtr a))
-> IO (VkInstance -> CString -> IO (FunPtr a))
forall a b. (a -> b) -> a -> b
$ FunPtr (VkInstance -> CString -> IO (FunPtr a))
-> VkInstance -> CString -> IO (FunPtr a)
k FunPtr (VkInstance -> CString -> IO (FunPtr a))
fp

c'vkGetDeviceProcAddr'
    :: ( FunPtr (VkDevice -> CString -> IO (FunPtr a))
          -> VkDevice -> CString -> IO (FunPtr a)
       )
    -> VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddr' :: forall a.
(FunPtr (VkDevice -> CString -> IO (FunPtr a))
 -> VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
c'vkGetDeviceProcAddr' FunPtr (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
k = IO (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
forall a. IO a -> a
unsafePerformIO (IO (VkDevice -> CString -> IO (FunPtr a))
 -> VkDevice -> CString -> IO (FunPtr a))
-> IO (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice
-> CString
-> IO (FunPtr a)
forall a b. (a -> b) -> a -> b
$ (Ptr CString -> IO (VkDevice -> CString -> IO (FunPtr a)))
-> IO (VkDevice -> CString -> IO (FunPtr a))
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CString -> IO (VkDevice -> CString -> IO (FunPtr a)))
 -> IO (VkDevice -> CString -> IO (FunPtr a)))
-> (Ptr CString -> IO (VkDevice -> CString -> IO (FunPtr a)))
-> IO (VkDevice -> CString -> IO (FunPtr a))
forall a b. (a -> b) -> a -> b
$ \Ptr CString
errPtr -> do
    FunPtr (VkDevice -> CString -> IO (FunPtr a))
fp <- ForeignPtr Void
-> (Ptr Void -> IO (FunPtr (VkDevice -> CString -> IO (FunPtr a))))
-> IO (FunPtr (VkDevice -> CString -> IO (FunPtr a)))
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Void
_vkDlHandle ((Ptr Void -> IO (FunPtr (VkDevice -> CString -> IO (FunPtr a))))
 -> IO (FunPtr (VkDevice -> CString -> IO (FunPtr a))))
-> (Ptr Void -> IO (FunPtr (VkDevice -> CString -> IO (FunPtr a))))
-> IO (FunPtr (VkDevice -> CString -> IO (FunPtr a)))
forall a b. (a -> b) -> a -> b
$ \Ptr Void
h ->
      Ptr Void
-> CString
-> Ptr CString
-> IO (FunPtr (VkDevice -> CString -> IO (FunPtr a)))
forall a. Ptr Void -> CString -> Ptr CString -> IO (FunPtr a)
c'vkdll_dlsym Ptr Void
h (Addr# -> CString
forall a. Addr# -> Ptr a
Ptr Addr#
"vkGetDeviceProcAddr"#) Ptr CString
errPtr
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FunPtr (VkDevice -> CString -> IO (FunPtr a))
fp FunPtr (VkDevice -> CString -> IO (FunPtr a))
-> FunPtr (VkDevice -> CString -> IO (FunPtr a)) -> Bool
forall a. Eq a => a -> a -> Bool
== FunPtr (VkDevice -> CString -> IO (FunPtr a))
forall a. FunPtr a
nullFunPtr) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr CString -> IO CString
forall a. Storable a => Ptr a -> IO a
peek Ptr CString
errPtr IO CString -> (CString -> IO String) -> IO String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CString -> IO String
peekCString IO String -> (String -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> (String -> String) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        (String
"Could not load 'vkGetDeviceProcAddr' C function from vulkan library dynamically: " String -> String -> String
forall a. [a] -> [a] -> [a]
++)
    (VkDevice -> CString -> IO (FunPtr a))
-> IO (VkDevice -> CString -> IO (FunPtr a))
forall (m :: * -> *) a. Monad m => a -> m a
return ((VkDevice -> CString -> IO (FunPtr a))
 -> IO (VkDevice -> CString -> IO (FunPtr a)))
-> (VkDevice -> CString -> IO (FunPtr a))
-> IO (VkDevice -> CString -> IO (FunPtr a))
forall a b. (a -> b) -> a -> b
$ FunPtr (VkDevice -> CString -> IO (FunPtr a))
-> VkDevice -> CString -> IO (FunPtr a)
k FunPtr (VkDevice -> CString -> IO (FunPtr a))
fp

foreign import ccall safe "dynamic"
  unwrap'vkGetInstanceProcAddrSafe
    :: FunPtr (VkInstance -> CString -> IO (FunPtr a))
    -> VkInstance -> CString -> IO (FunPtr a)

foreign import ccall safe "dynamic"
  unwrap'vkGetDeviceProcAddrSafe
    :: FunPtr (VkDevice -> CString -> IO (FunPtr a))
    -> VkDevice -> CString -> IO (FunPtr a)

foreign import ccall unsafe "dynamic"
  unwrap'vkGetInstanceProcAddrUnsafe
    :: FunPtr (VkInstance -> CString -> IO (FunPtr a))
    -> VkInstance -> CString -> IO (FunPtr a)

foreign import ccall unsafe "dynamic"
  unwrap'vkGetDeviceProcAddrUnsafe
    :: FunPtr (VkDevice -> CString -> IO (FunPtr a))
    -> VkDevice -> CString -> IO (FunPtr a)

#else

foreign import ccall safe "vkGetInstanceProcAddr"
  c'vkGetInstanceProcAddrSafe :: VkInstance -> CString -> IO (FunPtr a)

foreign import ccall safe "vkGetDeviceProcAddr"
  c'vkGetDeviceProcAddrSafe :: VkDevice -> CString -> IO (FunPtr a)

foreign import ccall unsafe "vkGetInstanceProcAddr"
  c'vkGetInstanceProcAddrUnsafe :: VkInstance -> CString -> IO (FunPtr a)

foreign import ccall unsafe "vkGetDeviceProcAddr"
  c'vkGetDeviceProcAddrUnsafe :: VkDevice -> CString -> IO (FunPtr a)


#endif


foreign import ccall safe "_vkdll_dlinit"
  c'vkdll_dlinit :: Ptr CString -> IO (Ptr Void)

foreign import ccall safe "_vkdll_dlsym"
  c'vkdll_dlsym :: Ptr Void -> CString -> Ptr CString -> IO (FunPtr a)

foreign import ccall safe "&_vkdll_dlclose"
  p'vk_dlclose :: FunPtr (Ptr Void -> IO ())

_vkDlHandle :: ForeignPtr Void
_vkDlHandle :: ForeignPtr Void
_vkDlHandle = IO (ForeignPtr Void) -> ForeignPtr Void
forall a. IO a -> a
unsafePerformIO (IO (ForeignPtr Void) -> ForeignPtr Void)
-> IO (ForeignPtr Void) -> ForeignPtr Void
forall a b. (a -> b) -> a -> b
$ (Ptr CString -> IO (ForeignPtr Void)) -> IO (ForeignPtr Void)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CString -> IO (ForeignPtr Void)) -> IO (ForeignPtr Void))
-> (Ptr CString -> IO (ForeignPtr Void)) -> IO (ForeignPtr Void)
forall a b. (a -> b) -> a -> b
$ \Ptr CString
errPtr -> do
  Ptr Void
handle <- Ptr CString -> IO (Ptr Void)
c'vkdll_dlinit Ptr CString
errPtr
  if Ptr Void
handle Ptr Void -> Ptr Void -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr Void
forall a. Ptr a
nullPtr
  then
    Ptr CString -> IO CString
forall a. Storable a => Ptr a -> IO a
peek Ptr CString
errPtr IO CString -> (CString -> IO String) -> IO String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CString -> IO String
peekCString IO String
-> (String -> IO (ForeignPtr Void)) -> IO (ForeignPtr Void)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO (ForeignPtr Void)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO (ForeignPtr Void))
-> (String -> String) -> String -> IO (ForeignPtr Void)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
      (String
"An error happened while trying to load vulkan library dynamically: " String -> String -> String
forall a. [a] -> [a] -> [a]
++)
  else
    FinalizerPtr Void -> Ptr Void -> IO (ForeignPtr Void)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr Void
p'vk_dlclose Ptr Void
handle
{-# NOINLINE _vkDlHandle #-}