1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! Functions to make Vulkan and SDL work together.
//!
//! This is only a basic level of functionality that lets you "turn it on". For
//! a full Vulkan experience you'll need a vulkan bindings crate such as
//! [ash](https:docs.rs/ash), or similar.

use crate::{c_char, c_int, c_uint, c_void, stdinc::*, video::*};

/// Vulkan instance pointer.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VkInstance(*mut u8);
impl Default for VkInstance {
  #[inline]
  #[must_use]
  fn default() -> Self {
    unsafe { core::mem::zeroed() }
  }
}

/// Vulkan surface handle.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VkSurfaceKHR(u64);

/// Alternate type name in some docs.
pub type SDL_vulkanInstance = VkInstance;

/// Alternate type name in some docs.
pub type SDL_vulkanSurface = VkSurfaceKHR;

extern "C" {
  /// Dynamically load a Vulkan loader library.
  ///
  /// * \[in\] `path` The platform dependent Vulkan loader library name, or
  ///   `NULL`.
  ///
  /// **Returns:** `0` on success, or `-1` if the library couldn't be loaded.
  ///
  /// If `path` is `NULL`, SDL will use the value of the environment variable
  /// `SDL_VULKAN_LIBRARY`, if set, otherwise it loads the default Vulkan
  /// loader library.
  ///
  /// This should be called after initializing the video driver, but *before*
  /// creating any Vulkan windows. If no Vulkan loader library is loaded, the
  /// default library will be loaded upon creation of the first Vulkan window.
  ///
  /// It is fairly common for Vulkan applications to link with `libvulkan`
  /// instead of explicitly loading it at run time. This will work with
  /// SDL provided the application links to a dynamic library and both it
  /// and SDL use the same search path.
  ///
  /// If you specify a non-NULL `path`, an application should retrieve all
  /// of the Vulkan functions it uses from the dynamic library using
  /// [`SDL_Vulkan_GetVkGetInstanceProcAddr`] unless you can guarantee
  /// `path` points to the same vulkan loader library the application
  /// linked to.
  ///
  /// On Apple devices, if `path` is NULL, SDL will attempt to find
  /// the `vkGetInstanceProcAddr` address within all the mach-o images of
  /// the current process. This is because it is fairly common for Vulkan
  /// applications to link with `libvulkan` (and historically MoltenVK was
  /// provided as a static library). If it is not found then, on macOS, SDL
  /// will attempt to load `vulkan.framework/vulkan`, `libvulkan.1.dylib`,
  /// followed by `libvulkan.dylib`, in that order.
  /// On iOS SDL will attempt to load `libvulkan.dylib` only. Applications
  /// using a dynamic framework or .dylib must ensure it is included in its
  /// application bundle.
  ///
  /// On non-Apple devices, application linking with a static `libvulkan` is
  /// not supported. Either do not link to the Vulkan loader or link to a
  /// dynamic library version.
  ///
  /// This function will fail if there are no working Vulkan drivers
  /// installed.
  ///
  /// See Also: [`SDL_Vulkan_GetVkGetInstanceProcAddr`],
  /// [`SDL_Vulkan_UnloadLibrary`]
  pub fn SDL_Vulkan_LoadLibrary(path: *const c_char) -> c_int;

  /// Get the address of the `vkGetInstanceProcAddr` function.
  ///
  /// This should be called after either calling [`SDL_Vulkan_LoadLibrary`]
  /// or creating an [`SDL_Window`] with the [`SDL_WINDOW_VULKAN`] flag.
  pub fn SDL_Vulkan_GetVkGetInstanceProcAddr() -> *mut c_void;

  /// Unload the Vulkan loader library previously loaded by
  /// [`SDL_Vulkan_LoadLibrary`].
  ///
  /// See Also: [`SDL_Vulkan_LoadLibrary`]
  pub fn SDL_Vulkan_UnloadLibrary();

  /// Get the names of the Vulkan instance extensions needed to create a surface
  /// with [`SDL_Vulkan_CreateSurface`].
  ///
  /// * \[in\] `window` Window for which the required Vulkan instance extensions
  ///   should be retrieved (or `NULL`).
  /// * \[in,out\] `pCount` pointer to a `c_uint` related to the number of
  ///   required Vulkan instance extensions (see below).
  /// * \[out\] `pNames` pointer to an array to be filled with the required
  ///   Vulkan instance extensions (or `NULL`).
  ///
  /// **Returns:** `SDL_TRUE` on success, `SDL_FALSE` on error.
  ///
  /// If `pNames` is `NULL`, then the number of required Vulkan instance
  /// extensions is returned in `pCount`. Otherwise, `pCount` must point to a
  /// variable set to the number of elements in the `pNames` array, and on
  /// return the variable is overwritten with the number of names actually
  /// written to `pNames`. If `pCount` is less than the number of required
  /// extensions, at most `pCount` structures will be written. If `pCount` is
  /// smaller than the number of required extensions, `SDL_FALSE` will be
  /// returned instead of `SDL_TRUE`, to indicate that not all the required
  /// extensions were returned.
  ///
  /// If `window` is not `NULL`, it will be checked against its creation flags
  /// to ensure that the Vulkan flag is present. This parameter will be removed
  /// in a future major release.
  ///
  /// The returned list of extensions will contain `VK_KHR_surface` and zero or
  /// more platform specific extensions
  ///
  /// The extension names queried here must be enabled when calling
  /// [`VkCreateInstance`], otherwise surface creation will fail.
  ///
  /// `window` should have been created with the [`SDL_WINDOW_VULKAN`] flag, or
  /// be `NULL`.
  ///
  /// ```c
  /// unsigned int count;
  /// // get count of required extensions
  /// if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, NULL))
  ///     handle_error();
  ///
  /// static const char *const additionalExtensions[] =
  /// {
  ///     VK_EXT_DEBUG_REPORT_EXTENSION_NAME, // example additional extension
  /// };
  /// size_t additionalExtensionsCount = sizeof(additionalExtensions) / sizeof(additionalExtensions[0]);
  /// size_t extensionCount = count + additionalExtensionsCount;
  /// const char **names = malloc(sizeof(const char *) * extensionCount);
  /// if(!names)
  ///     handle_error();
  ///
  /// // get names of required extensions
  /// if(!SDL_Vulkan_GetInstanceExtensions(NULL, &count, names))
  ///     handle_error();
  ///
  /// // copy additional extensions after required extensions
  /// for(size_t i = 0; i < additionalExtensionsCount; i++)
  ///     names[i + count] = additionalExtensions[i];
  ///
  /// VkInstanceCreateInfo instanceCreateInfo = {};
  /// instanceCreateInfo.enabledExtensionCount = extensionCount;
  /// instanceCreateInfo.ppEnabledExtensionNames = names;
  /// // fill in rest of instanceCreateInfo
  ///
  /// VkInstance instance;
  /// // create the Vulkan instance
  /// VkResult result = vkCreateInstance(&instanceCreateInfo, NULL, &instance);
  /// free(names);
  /// ```
  ///
  /// See Also: [`SDL_Vulkan_CreateSurface`]
  pub fn SDL_Vulkan_GetInstanceExtensions(
    window: *mut SDL_Window, pCount: *mut c_uint, pNames: *mut *const c_char,
  ) -> SDL_bool;
  // TODO: convert the above example to rust

  /// Create a Vulkan rendering surface for a window.
  ///
  /// * \[in\] `window` SDL_Window to which to attach the rendering surface.
  /// * \[in\] `instance` handle to the Vulkan instance to use.
  /// * \[out\] `surface` pointer to a VkSurfaceKHR handle to receive the handle
  ///   of the newly created surface.
  ///
  /// **Returns:** `SDL_TRUE` on success, `SDL_FALSE` on error.
  ///
  /// ```c
  /// VkInstance instance;
  /// SDL_Window *window;
  ///
  /// // create instance and window
  ///
  /// // create the Vulkan surface
  /// VkSurfaceKHR surface;
  /// if(!SDL_Vulkan_CreateSurface(window, instance, &surface))
  ///     handle_error();
  /// ```
  ///
  /// `window` should have been created with the `SDL_WINDOW_VULKAN` flag.
  ///
  /// `instance` should have been created with the extensions returned by
  /// [`SDL_Vulkan_CreateSurface`] enabled.
  ///
  /// See Also: [`SDL_Vulkan_GetInstanceExtensions`]
  pub fn SDL_Vulkan_CreateSurface(
    window: *mut SDL_Window, instance: VkInstance, surface: *mut VkSurfaceKHR,
  ) -> SDL_bool;

  /// Get the size of a window's underlying drawable in pixels (for use with
  /// setting viewport, scissor & etc).
  ///
  /// * `window` The `SDL_Window` from which the drawable size should be
  ///   queried.
  /// * `w` Pointer to variable for storing the width in pixels, may be `NULL`.
  /// * `h` Pointer to variable for storing the height in pixels, may be `NULL`.
  ///
  /// This may differ from [`SDL_GetWindowSize`] if we're rendering to a
  /// high-DPI drawable, i.e. the window was created with
  /// [`SDL_WINDOW_ALLOW_HIGHDPI`] on a platform with high-DPI support (Apple
  /// calls this "Retina"), and not disabled
  /// by the [`SDL_HINT_VIDEO_HIGHDPI_DISABLED`] hint.
  ///
  /// On macOS high-DPI support must be enabled for an application by
  /// setting `NSHighResolutionCapable` to true in its `Info.plist`.
  ///
  /// See Also: [`SDL_GetWindowSize`] and [`SDL_CreateWindow`]
  pub fn SDL_Vulkan_GetDrawableSize(
    window: *mut SDL_Window, w: *mut c_int, h: *mut c_int,
  );
}