diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,13 @@
+2.5.0.0
+=======
+
+* Version 2.0.6 of the SDL2 C library is now required.
+
+* Added Vulkan support. See `SDL.Video.WindowGraphicsContext` data type and `SDL.Video.Vulkan` module.
+
+* Support `StateVar` < 1.3
+
+
 2.4.1.0
 =======
 
@@ -11,7 +21,7 @@
   https://github.com/haskell-game/sdl2/pull/177 for more information. Thanks to
   @Linearity for identifying and fixing this bug.
 
-        
+
 2.4.0.1
 =======
 * Raise upper bounds for `exceptions` to <0.11
diff --git a/bench/Space.hs b/bench/Space.hs
--- a/bench/Space.hs
+++ b/bench/Space.hs
@@ -44,9 +44,9 @@
                (\weight ->
                   if weightGCs weight > 0
                     then Just "Non-zero number of garbage collections!"
-                    else if weightAllocatedBytes weight > 3000
+                    else if weightAllocatedBytes weight > 4000
                            then Just
-                                  "Allocated >3KB! Allocations should be constant."
+                                  "Allocated >4KB! Allocations should be constant."
                            else Nothing)
              | i <- [1, 10, 100, 1000, 10000]
              ])
diff --git a/examples/EventWatch.hs b/examples/EventWatch.hs
--- a/examples/EventWatch.hs
+++ b/examples/EventWatch.hs
@@ -18,15 +18,15 @@
 main = do
   initializeAll
   window <- createWindow "resize" WindowConfig {
-      windowBorder       = True
-    , windowHighDPI      = False
-    , windowInputGrabbed = False
-    , windowMode         = Windowed
-    , windowOpenGL       = Nothing
-    , windowPosition     = Wherever
-    , windowResizable    = True
-    , windowInitialSize  = V2 800 600
-    , windowVisible      = True
+      windowBorder          = True
+    , windowHighDPI         = False
+    , windowInputGrabbed    = False
+    , windowMode            = Windowed
+    , windowGraphicsContext = NoGraphicsContext
+    , windowPosition        = Wherever
+    , windowResizable       = True
+    , windowInitialSize     = V2 800 600
+    , windowVisible         = True
   }
   renderer <- createRenderer window (-1) defaultRenderer
   addEventWatch $ \ev ->
diff --git a/examples/OpenGLExample.hs b/examples/OpenGLExample.hs
--- a/examples/OpenGLExample.hs
+++ b/examples/OpenGLExample.hs
@@ -31,7 +31,7 @@
     SDL.createWindow
       "SDL / OpenGL Example"
       SDL.defaultWindow {SDL.windowInitialSize = V2 screenWidth screenHeight,
-                         SDL.windowOpenGL = Just SDL.defaultOpenGL}
+                         SDL.windowGraphicsContext = SDL.OpenGLContext SDL.defaultOpenGL}
   SDL.showWindow window
 
   _ <- SDL.glCreateContext window
diff --git a/sdl2.cabal b/sdl2.cabal
--- a/sdl2.cabal
+++ b/sdl2.cabal
@@ -1,6 +1,6 @@
 name:                sdl2
-version:             2.4.1.0
-synopsis:            Both high- and low-level bindings to the SDL library (version 2.0.4+).
+version:             2.5.0.0
+synopsis:            Both high- and low-level bindings to the SDL library (version 2.0.6+).
 description:
   This package contains bindings to the SDL 2 library, in both high- and
   low-level forms:
@@ -78,6 +78,7 @@
     SDL.Video
     SDL.Video.OpenGL
     SDL.Video.Renderer
+    SDL.Video.Vulkan
 
     SDL.Internal.Exception
     SDL.Internal.Numbered
@@ -113,19 +114,20 @@
 
   includes:
     SDL.h
+    SDL_vulkan.h
     sdlhelper.h
 
   extra-libraries:
     SDL2
 
   pkgconfig-depends:
-    sdl2 >= 2.0.4
+    sdl2 >= 2.0.6
 
   build-depends:
     base >= 4.7 && < 5,
     bytestring >= 0.10.4.0 && < 0.11,
     exceptions >= 0.4 && < 0.11,
-    StateVar >= 1.1.0.0 && < 1.2,
+    StateVar >= 1.1.0.0 && < 1.3,
     text >= 1.1.0.0 && < 1.3,
     transformers >= 0.2 && < 0.6,
     vector >= 0.10.9.0 && < 0.13
diff --git a/src/SDL/Raw/Enum.hsc b/src/SDL/Raw/Enum.hsc
--- a/src/SDL/Raw/Enum.hsc
+++ b/src/SDL/Raw/Enum.hsc
@@ -898,6 +898,7 @@
   pattern SDL_WINDOW_FOREIGN,
   pattern SDL_WINDOW_ALLOW_HIGHDPI,
   pattern SDL_WINDOW_MOUSE_CAPTURE,
+  pattern SDL_WINDOW_VULKAN,
 
   -- ** Window Positioning
   pattern SDL_WINDOWPOS_UNDEFINED,
@@ -1767,6 +1768,7 @@
 pattern SDL_WINDOW_FOREIGN = (#const SDL_WINDOW_FOREIGN)
 pattern SDL_WINDOW_ALLOW_HIGHDPI = (#const SDL_WINDOW_ALLOW_HIGHDPI)
 pattern SDL_WINDOW_MOUSE_CAPTURE = (#const SDL_WINDOW_MOUSE_CAPTURE)
+pattern SDL_WINDOW_VULKAN = (#const SDL_WINDOW_VULKAN)
 
 pattern SDL_WINDOWPOS_UNDEFINED = (#const SDL_WINDOWPOS_UNDEFINED)
 pattern SDL_WINDOWPOS_CENTERED = (#const SDL_WINDOWPOS_CENTERED)
diff --git a/src/SDL/Raw/Types.hsc b/src/SDL/Raw/Types.hsc
--- a/src/SDL/Raw/Types.hsc
+++ b/src/SDL/Raw/Types.hsc
@@ -2,6 +2,8 @@
 module SDL.Raw.Types (
   -- * Type Aliases
   -- ** Function Types
+  VkGetInstanceProcAddrFunc,
+
   AudioCallback,
   EventFilter,
   HintCallback,
@@ -40,6 +42,8 @@
   TimerID,
   TLSID,
   TouchID,
+  VkInstance,
+  VkSurfaceKHR,
   Window,
 
   -- * Data Structures
@@ -81,6 +85,8 @@
 import Foreign.Storable
 import SDL.Raw.Enum
 
+type VkGetInstanceProcAddrFunc = VkInstance -> CString -> IO (FunPtr ())
+
 type AudioCallback = FunPtr (Ptr () -> Ptr Word8 -> CInt -> IO ())
 type EventFilter = FunPtr (Ptr () -> Ptr Event -> IO CInt)
 type HintCallback = FunPtr (Ptr () -> CString -> CString -> CString -> IO ())
@@ -140,6 +146,8 @@
 type TimerID = CInt
 type TLSID = CUInt
 type TouchID = Int64
+type VkInstance = Ptr ()
+type VkSurfaceKHR = Word64
 type Window = Ptr ()
 
 data Atomic = Atomic
diff --git a/src/SDL/Raw/Video.hs b/src/SDL/Raw/Video.hs
--- a/src/SDL/Raw/Video.hs
+++ b/src/SDL/Raw/Video.hs
@@ -195,7 +195,15 @@
   -- * Clipboard Handling
   getClipboardText,
   hasClipboardText,
-  setClipboardText
+  setClipboardText,
+
+  -- * Vulkan support functions
+  vkLoadLibrary,
+  vkGetVkGetInstanceProcAddr,
+  vkUnloadLibrary,
+  vkGetInstanceExtensions,
+  vkCreateSurface,
+  vkGetDrawableSize
 ) where
 
 import Control.Monad.IO.Class
@@ -396,6 +404,13 @@
 foreign import ccall "SDL.h SDL_HasClipboardText" hasClipboardTextFFI :: IO Bool
 foreign import ccall "SDL.h SDL_SetClipboardText" setClipboardTextFFI :: CString -> IO CInt
 
+foreign import ccall "SDL_vulkan.h SDL_Vulkan_LoadLibrary" vkLoadLibraryFFI :: CString -> IO CInt
+foreign import ccall "SDL_vulkan.h SDL_Vulkan_GetVkGetInstanceProcAddr" vkGetVkGetInstanceProcAddrFFI :: IO (FunPtr VkGetInstanceProcAddrFunc)
+foreign import ccall "SDL_vulkan.h SDL_Vulkan_UnloadLibrary" vkUnloadLibraryFFI :: IO ()
+foreign import ccall "SDL_vulkan.h SDL_Vulkan_GetInstanceExtensions" vkGetInstanceExtensionsFFI :: Window -> Ptr CUInt -> Ptr CString -> IO Bool
+foreign import ccall "SDL_vulkan.h SDL_Vulkan_CreateSurface" vkCreateSurfaceFFI :: Window -> VkInstance -> Ptr VkSurfaceKHR -> IO Bool
+foreign import ccall "SDL_vulkan.h SDL_Vulkan_GetDrawableSize" vkGetDrawableSizeFFI :: Window -> Ptr CInt -> Ptr CInt -> IO ()
+
 createWindow :: MonadIO m => CString -> CInt -> CInt -> CInt -> CInt -> Word32 -> m Window
 createWindow v1 v2 v3 v4 v5 v6 = liftIO $ createWindowFFI v1 v2 v3 v4 v5 v6
 {-# INLINE createWindow #-}
@@ -1135,3 +1150,27 @@
 setClipboardText :: MonadIO m => CString -> m CInt
 setClipboardText v1 = liftIO $ setClipboardTextFFI v1
 {-# INLINE setClipboardText #-}
+
+vkLoadLibrary :: MonadIO m => CString -> m CInt
+vkLoadLibrary v1 = liftIO $ setClipboardTextFFI v1
+{-# INLINE vkLoadLibrary #-}
+
+vkGetVkGetInstanceProcAddr :: MonadIO m => m (FunPtr VkGetInstanceProcAddrFunc)
+vkGetVkGetInstanceProcAddr = liftIO vkGetVkGetInstanceProcAddrFFI
+{-# INLINE vkGetVkGetInstanceProcAddr #-}
+
+vkUnloadLibrary :: MonadIO m => m ()
+vkUnloadLibrary = liftIO vkUnloadLibraryFFI
+{-# INLINE vkUnloadLibrary #-}
+
+vkGetInstanceExtensions :: MonadIO m => Window -> Ptr CUInt -> Ptr CString -> m Bool
+vkGetInstanceExtensions v1 v2 v3 = liftIO $ vkGetInstanceExtensionsFFI v1 v2 v3
+{-# INLINE vkGetInstanceExtensions #-}
+
+vkCreateSurface :: MonadIO m => Window -> VkInstance -> Ptr VkSurfaceKHR -> m Bool
+vkCreateSurface v1 v2 v3 = liftIO $ vkCreateSurfaceFFI v1 v2 v3
+{-# INLINE vkCreateSurface #-}
+
+vkGetDrawableSize :: MonadIO m => Window -> Ptr CInt -> Ptr CInt -> m ()
+vkGetDrawableSize v1 v2 v3 = liftIO $ vkGetDrawableSizeFFI v1 v2 v3
+{-# INLINE vkGetDrawableSize #-}
diff --git a/src/SDL/Video.hs b/src/SDL/Video.hs
--- a/src/SDL/Video.hs
+++ b/src/SDL/Video.hs
@@ -12,6 +12,7 @@
   , createWindow
   , defaultWindow
   , WindowConfig(..)
+  , WindowGraphicsContext(..)
   , WindowMode(..)
   , WindowPosition(..)
   , destroyWindow
@@ -103,9 +104,9 @@
 -- Throws 'SDLException' on failure.
 createWindow :: MonadIO m => Text -> WindowConfig -> m Window
 createWindow title config = liftIO $ do
-  case windowOpenGL config of
-    Just glcfg -> setGLAttributes glcfg
-    Nothing    -> return ()
+  case windowGraphicsContext config of
+    OpenGLContext glcfg -> setGLAttributes glcfg
+    _                   -> return ()
 
   BS.useAsCString (Text.encodeUtf8 title) $ \title' -> do
     let create = Raw.createWindow title'
@@ -120,9 +121,10 @@
       , if windowHighDPI config then Raw.SDL_WINDOW_ALLOW_HIGHDPI else 0
       , if windowInputGrabbed config then Raw.SDL_WINDOW_INPUT_GRABBED else 0
       , toNumber $ windowMode config
-      , if isJust $ windowOpenGL config then Raw.SDL_WINDOW_OPENGL else 0
+      , if ctxIsOpenGL (windowGraphicsContext config) then Raw.SDL_WINDOW_OPENGL else 0
       , if windowResizable config then Raw.SDL_WINDOW_RESIZABLE else 0
       , if windowVisible config then 0 else Raw.SDL_WINDOW_HIDDEN
+      , if windowGraphicsContext config == VulkanContext then Raw.SDL_WINDOW_VULKAN else 0
       ]
     setGLAttributes (OpenGLConfig (V4 r g b a) d s ms p) = do
       let (msk, v0, v1, flg) = case p of
@@ -152,42 +154,59 @@
 --
 -- @
 -- 'defaultWindow' = 'WindowConfig'
---   { 'windowBorder'       = True
---   , 'windowHighDPI'      = False
---   , 'windowInputGrabbed' = False
---   , 'windowMode'         = 'Windowed'
---   , 'windowOpenGL'       = Nothing
---   , 'windowPosition'     = 'Wherever'
---   , 'windowResizable'    = False
---   , 'windowInitialSize'  = V2 800 600
---   , 'windowVisible'      = True
+--   { 'windowBorder'          = True
+--   , 'windowHighDPI'         = False
+--   , 'windowInputGrabbed'    = False
+--   , 'windowMode'            = 'Windowed'
+--   , 'windowGraphicsContext' = NoGraphicsContext
+--   , 'windowPosition'        = 'Wherever'
+--   , 'windowResizable'       = False
+--   , 'windowInitialSize'     = V2 800 600
+--   , 'windowVisible'         = True
 --   }
 -- @
 defaultWindow :: WindowConfig
 defaultWindow = WindowConfig
-  { windowBorder       = True
-  , windowHighDPI      = False
-  , windowInputGrabbed = False
-  , windowMode         = Windowed
-  , windowOpenGL       = Nothing
-  , windowPosition     = Wherever
-  , windowResizable    = False
-  , windowInitialSize  = V2 800 600
-  , windowVisible      = True
+  { windowBorder          = True
+  , windowHighDPI         = False
+  , windowInputGrabbed    = False
+  , windowMode            = Windowed
+  , windowGraphicsContext = NoGraphicsContext
+  , windowPosition        = Wherever
+  , windowResizable       = False
+  , windowInitialSize     = V2 800 600
+     , windowVisible      = True
   }
 
 data WindowConfig = WindowConfig
-  { windowBorder       :: Bool               -- ^ Defaults to 'True'.
-  , windowHighDPI      :: Bool               -- ^ Defaults to 'False'. Can not be changed after window creation.
-  , windowInputGrabbed :: Bool               -- ^ Defaults to 'False'. Whether the mouse shall be confined to the window.
-  , windowMode         :: WindowMode         -- ^ Defaults to 'Windowed'.
-  , windowOpenGL       :: Maybe OpenGLConfig -- ^ Defaults to 'Nothing'. Can not be changed after window creation.
-  , windowPosition     :: WindowPosition     -- ^ Defaults to 'Wherever'.
-  , windowResizable    :: Bool               -- ^ Defaults to 'False'. Whether the window can be resized by the user. It is still possible to programatically change the size by changing 'windowSize'.
-  , windowInitialSize  :: V2 CInt            -- ^ Defaults to @(800, 600)@. If you set 'windowHighDPI' flag, window size in screen coordinates may differ from the size in pixels. Use 'glGetDrawableSize' to get size in pixels.
-  , windowVisible      :: Bool               -- ^ Defaults to 'True'.
+  { windowBorder          :: Bool                  -- ^ Defaults to 'True'.
+  , windowHighDPI         :: Bool                  -- ^ Defaults to 'False'. Can not be changed after window creation.
+  , windowInputGrabbed    :: Bool                  -- ^ Defaults to 'False'. Whether the mouse shall be confined to the window.
+  , windowMode            :: WindowMode            -- ^ Defaults to 'Windowed'.
+  , windowGraphicsContext :: WindowGraphicsContext -- ^ Defaults to 'NoGraphicsContext'. Can not be changed after window creation.
+  , windowPosition        :: WindowPosition        -- ^ Defaults to 'Wherever'.
+  , windowResizable       :: Bool                  -- ^ Defaults to 'False'. Whether the window can be resized by the user. It is still possible to programatically change the size by changing 'windowSize'.
+  , windowInitialSize     :: V2 CInt               -- ^ Defaults to @(800, 600)@. If you set 'windowHighDPI' flag, window size in screen coordinates may differ from the size in pixels. Use 'glGetDrawableSize' or 'SDL.Video.Vulkan.vkGetDrawableSize' to get size in pixels.
+  , windowVisible         :: Bool                  -- ^ Defaults to 'True'.
   } deriving (Eq, Generic, Ord, Read, Show, Typeable)
 
+-- | Configuration of additional graphics context that will be created for window.
+--
+--   Can not be changed after window creation.
+data WindowGraphicsContext
+  = NoGraphicsContext          -- ^ Window will be created without any additional graphics context.
+  | OpenGLContext OpenGLConfig -- ^ Window will be created with OpenGL support with parameters from 'OpenGLConfig'.
+  | VulkanContext              -- ^ Window will be created with Vulkan support.
+                               --   The following functions will be implicitly called by SDL C library:
+                               --
+                               --     1. analogue of 'SDL.Video.Vulkan.vkLoadLibrary' 'Nothing' will be called automatically before first window creation;
+                               --     2. analogue of 'SDL.Video.Vulkan.vkUnloadLibrary' will be called after last window destruction.
+  deriving (Eq, Generic, Ord, Read, Show, Typeable)
+
+ctxIsOpenGL :: WindowGraphicsContext -> Bool
+ctxIsOpenGL (OpenGLContext _) = True
+ctxIsOpenGL _                 = False
+
 data WindowMode
   = Fullscreen        -- ^ Real fullscreen with a video mode change
   | FullscreenDesktop -- ^ Fake fullscreen that takes the size of the desktop
@@ -294,7 +313,8 @@
 
 -- | Get or set the size of a window's client area. Values beyond the maximum supported size are clamped.
 --
--- If window was created with 'windowHighDPI' flag, this size may differ from the size in pixels. Use 'glGetDrawableSize' to get size in pixels.
+-- If window was created with 'windowHighDPI' flag, this size may differ from the size in pixels.
+-- Use 'glGetDrawableSize' or 'SDL.Video.Vulkan.vkGetDrawableSize' to get size in pixels.
 --
 -- This 'StateVar' can be modified using '$=' and the current value retrieved with 'get'.
 --
@@ -339,7 +359,7 @@
 
 -- | Retrieve the configuration of the given window.
 --
--- Note that 'Nothing' will be returned instead of potential OpenGL parameters
+-- Note that 'NoGraphicsContext' will be returned instead of potential OpenGL parameters
 -- used during the creation of the window.
 getWindowConfig :: MonadIO m => Window -> m WindowConfig
 getWindowConfig (Window w) = do
@@ -349,16 +369,17 @@
     wPos  <- getWindowAbsolutePosition (Window w)
 
     return WindowConfig {
-        windowBorder       = wFlags .&. Raw.SDL_WINDOW_BORDERLESS == 0
-      , windowHighDPI      = wFlags .&. Raw.SDL_WINDOW_ALLOW_HIGHDPI > 0
-      , windowInputGrabbed = wFlags .&. Raw.SDL_WINDOW_INPUT_GRABBED > 0
-      , windowMode         = fromNumber wFlags
-        -- Should we store the openGL config that was used to create the window?
-      , windowOpenGL       = Nothing
-      , windowPosition     = Absolute (P wPos)
-      , windowResizable    = wFlags .&. Raw.SDL_WINDOW_RESIZABLE > 0
-      , windowInitialSize  = wSize
-      , windowVisible      = wFlags .&. Raw.SDL_WINDOW_SHOWN > 0
+        windowBorder          = wFlags .&. Raw.SDL_WINDOW_BORDERLESS == 0
+      , windowHighDPI         = wFlags .&. Raw.SDL_WINDOW_ALLOW_HIGHDPI > 0
+      , windowInputGrabbed    = wFlags .&. Raw.SDL_WINDOW_INPUT_GRABBED > 0
+      , windowMode            = fromNumber wFlags
+        -- Should we store the OpenGL config that was used to create the window?
+      , windowGraphicsContext = if wFlags .&. Raw.SDL_WINDOW_VULKAN > 0
+                                  then VulkanContext else NoGraphicsContext
+      , windowPosition        = Absolute (P wPos)
+      , windowResizable       = wFlags .&. Raw.SDL_WINDOW_RESIZABLE > 0
+      , windowInitialSize     = wSize
+      , windowVisible         = wFlags .&. Raw.SDL_WINDOW_SHOWN > 0
     }
 
 -- | Get the pixel format that is used for the given window.
diff --git a/src/SDL/Video/Vulkan.hs b/src/SDL/Video/Vulkan.hs
new file mode 100644
--- /dev/null
+++ b/src/SDL/Video/Vulkan.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE LambdaCase #-}
+
+module SDL.Video.Vulkan (
+  -- * Vulkan types
+  VkInstance, VkSurfaceKHR, VkGetInstanceProcAddrFunc,
+  -- * Vulkan loader
+  vkLoadLibrary, vkUnloadLibrary, vkGetVkGetInstanceProcAddr,
+  -- * Vulkan surface
+  vkGetInstanceExtensions, vkCreateSurface,
+  -- * Querying for the drawable size
+  vkGetDrawableSize
+) where
+
+import Control.Monad.IO.Class (MonadIO, liftIO)
+import Foreign hiding (throwIf_, throwIfNeg_)
+import Foreign.C.Types (CInt)
+import Foreign.C.String (CString, withCString)
+import SDL.Vect (V2 (V2))
+import SDL.Internal.Exception (throwIf_, throwIfNeg_)
+import SDL.Internal.Types (Window (Window))
+import SDL.Raw.Types (VkInstance, VkSurfaceKHR, VkGetInstanceProcAddrFunc)
+import qualified SDL.Raw as Raw
+
+#if !MIN_VERSION_base(4,8,0)
+import Control.Applicative
+#endif
+
+-- | Dynamically load a Vulkan loader library.
+--
+-- If a filePath is 'Nothing', SDL will use the value of the environment variable
+-- SDL_VULKAN_LIBRARY, if set, otherwise it loads the default Vulkan
+-- loader library.
+--
+-- This function should be called after initializing the video driver
+-- (i.e. 'SDL.Init.initialize' ['SDL.Init.InitVideo']), but before
+-- creating any windows with 'SDL.Video.windowGraphicsContext' = 'SDL.Video.VulkanContext'.
+--
+-- If no Vulkan loader library is loaded, analogue of 'vkLoadLibrary' 'Nothing'
+-- will be automatically called by SDL C library upon creation of the first Vulkan window.
+--
+-- Throws 'SDL.Exception.SDLException' if there are no working Vulkan drivers installed.
+vkLoadLibrary :: MonadIO m => Maybe FilePath -> m ()
+vkLoadLibrary = \case
+    Nothing       -> liftIO . testNeg $ Raw.vkLoadLibrary nullPtr
+    Just filePath -> liftIO . withCString filePath $ testNeg . Raw.vkLoadLibrary
+  where
+    testNeg = throwIfNeg_ "SDL.Video.Vulkan.vkLoadLibrary" "SDL_Vulkan_LoadLibrary"
+
+-- | Unload the Vulkan loader library previously loaded by 'vkLoadLibrary'.
+--
+-- Analogue of this function will be automatically called by SDL C library
+-- after destruction of the last window with
+-- 'SDL.Video.windowGraphicsContext' = 'SDL.Video.VulkanContext'.
+vkUnloadLibrary :: MonadIO m => m ()
+vkUnloadLibrary = Raw.vkUnloadLibrary
+
+foreign import ccall "dynamic" mkVkGetInstanceProcAddrFunc ::
+  FunPtr VkGetInstanceProcAddrFunc -> VkGetInstanceProcAddrFunc
+
+-- | Get the vkGetInstanceProcAddr function, which can be used to obtain another Vulkan functions
+-- (see <https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html>).
+--
+-- The 'vkGetVkGetInstanceProcAddr' function should be called after either calling 'vkLoadLibrary'
+-- function or creating first Vulkan window.
+vkGetVkGetInstanceProcAddr :: (Functor m, MonadIO m) => m VkGetInstanceProcAddrFunc
+vkGetVkGetInstanceProcAddr = mkVkGetInstanceProcAddrFunc <$> Raw.vkGetVkGetInstanceProcAddr
+
+-- | Get the names of the Vulkan instance extensions needed to create
+-- a surface with 'vkCreateSurface'.
+--
+-- The extension names queried here must be enabled when calling vkCreateInstance
+-- (see <https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkCreateInstance.html>),
+-- otherwise 'vkCreateSurface' will fail.
+--
+-- Window should have been created with 'SDL.Video.windowGraphicsContext' = 'SDL.Video.VulkanContext'.
+--
+-- Throws 'SDL.Exception.SDLException' on failure.
+vkGetInstanceExtensions :: MonadIO m => Window -> m [CString]
+vkGetInstanceExtensions (Window w) = liftIO . alloca $ \countPtr -> do
+  throwIf_ not "SDL.Video.Vulkan.vkGetInstanceExtensions (1)" "SDL_Vulkan_GetInstanceExtensions" $
+    Raw.vkGetInstanceExtensions w countPtr nullPtr
+  count <- fromIntegral <$> peek countPtr
+  allocaArray count $ \sPtr ->
+    throwIf_ not "SDL.Video.Vulkan.vkGetInstanceExtensions (2)" "SDL_Vulkan_GetInstanceExtensions"
+      (Raw.vkGetInstanceExtensions w countPtr sPtr) >> peekArray count sPtr
+
+-- | Create a Vulkan rendering surface for a window.
+--
+-- Window should have been created with 'SDL.Video.windowGraphicsContext' = 'SDL.Video.VulkanContext'.
+--
+-- Instance should have been created with the extensions returned
+-- by 'vkGetInstanceExtensions' enabled.
+--
+-- Throws 'SDL.Exception.SDLException' on failure.
+vkCreateSurface :: MonadIO m => Window -> VkInstance -> m VkSurfaceKHR
+vkCreateSurface (Window w) vkInstance = liftIO . alloca $ \vkSurfacePtr ->
+  throwIf_ not "SDL.Video.Vulkan.vkCreateSurface" "SDL_Vulkan_CreateSurface"
+    (Raw.vkCreateSurface w vkInstance vkSurfacePtr) >> peek vkSurfacePtr
+
+-- | Get the size of a window's underlying drawable area in pixels (for use
+-- with setting viewport, scissor & etc).
+--
+-- It may differ from 'SDL.Video.windowSize' if window was created with 'SDL.Video.windowHighDPI' flag.
+vkGetDrawableSize :: MonadIO m => Window -> m (V2 CInt)
+vkGetDrawableSize (Window w) = liftIO . alloca $ \wptr ->
+  alloca $ \hptr -> do
+    Raw.vkGetDrawableSize w wptr hptr
+    V2 <$> peek wptr <*> peek hptr
