--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <vulkan/vulkan.h>
+#include "gphgfx.h"
+
+#define VER_MAJOR 0
+#define VER_MINOR 1
+
+static const char *vk_strerror(VkResult res);
+
+static VkInstance vk;
+
+int ggfx_init(const char *appname, unsigned int flags)
+{
+ VkResult res;
+ VkInstanceCreateInfo iinf = {0};
+ VkApplicationInfo appinf = {0};
+ VkLayerProperties *lprop = 0;
+ VkExtensionProperties *iext;
+ uint32_t i, j, num_inst_layers, num_inst_ext, lprop_count, iext_count;
+ char **inst_layers = 0, **inst_ext = 0;
+
+ static const char *debug_layers[] = {
+ "VK_LAYER_LUNARG_device_limits",
+ "VK_LAYER_LUNARG_image",
+ "VK_LAYER_LUNARG_object_tracker",
+ "VK_LAYER_LUNARG_core_validation",
+ "VK_LAYER_LUNARG_parameter_validation",
+ "VK_LAYER_LUNARG_swapchain",
+ "VK_LAYER_GOOGLE_threading",
+ "VK_LAYER_GOOGLE_unique_objects",
+ 0
+ };
+ static const char *extensions[] = {
+ "VK_KHR_surface",
+ "VK_KHR_xlib_surface",
+ 0
+ };
+
+ vkEnumerateInstanceLayerProperties(&lprop_count, 0);
+ if(lprop_count > 0) {
+ if(!(lprop = malloc(lprop_count * sizeof *lprop))) {
+ perror("ggfx_init: failed to allocate layer property list");
+ return -1;
+ }
+ vkEnumerateInstanceLayerProperties(&lprop_count, lprop);
+
+ if(flags & GGFX_INIT_DEBUG) {
+ if(!(inst_layers = malloc(lprop_count * sizeof *inst_layers))) {
+ perror("ggfx_init: failed to allocate layer properties");
+ return -1;
+ }
+ }
+
+ printf("%d available instance layers\n", lprop_count);
+ num_inst_layers = 0;
+ for(i=0; i<lprop_count; i++) {
+ char use = ' ';
+ if(inst_layers) {
+ for(j=0; debug_layers[j]; j++) {
+ if(strcmp(lprop[i].layerName, debug_layers[j]) == 0) {
+ inst_layers[num_inst_layers++] = lprop[i].layerName;
+ use = '*';
+ break;
+ }
+ }
+
+ }
+ printf(" [%c] %s: %s\n", use, lprop[i].layerName, lprop[i].description);
+ }
+ }
+
+ vkEnumerateInstanceExtensionProperties(0, &iext_count, 0);
+ if(iext_count > 0) {
+ if(!(iext = malloc(iext_count * sizeof *iext))) {
+ perror("ggfx_init: failed to allocate instance extensions property list");
+ return -1;
+ }
+ vkEnumerateInstanceExtensionProperties(0, &iext_count, iext);
+
+ if(!(inst_ext = malloc(iext_count * sizeof *inst_ext))) {
+ perror("ggfx_init: failed to allocate instance extension properties");
+ return -1;
+ }
+
+ printf("%d available instance extensions\n", iext_count);
+ num_inst_ext = 0;
+ for(i=0; i<iext_count; i++) {
+ char use = ' ';
+ for(j=0; extensions[j]; j++) {
+ if(strcmp(iext[i].extensionName, extensions[j]) == 0) {
+ inst_ext[num_inst_ext++] = iext[i].extensionName;
+ use = '*';
+ break;
+ }
+ }
+ printf(" [%c] %s\n", use, iext[i].extensionName);
+ }
+ }
+
+
+ appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ appinf.pApplicationName = appname ? appname : "unknown";
+ appinf.applicationVersion = 1;
+ appinf.pEngineName = "gph-gfx";
+ appinf.engineVersion = VK_MAKE_VERSION(VER_MAJOR, VER_MINOR, 0);
+
+ iinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ iinf.pApplicationInfo = &appinf;
+ iinf.ppEnabledLayerNames = (const char**)inst_layers;
+ iinf.enabledLayerCount = num_inst_layers;
+ iinf.ppEnabledExtensionNames = (const char**)inst_ext;
+ iinf.enabledExtensionCount = num_inst_ext;
+
+ if((res = vkCreateInstance(&iinf, 0, &vk)) != 0) {
+ fprintf(stderr, "ggfx_init: failed to create vulkan instance: %s\n", vk_strerror(res));
+ return -1;
+ }
+
+ return 0;
+}
+
+void ggfx_shutdown(void)
+{
+ if(!vk) return;
+
+ vkDestroyInstance(vk, 0);
+ vk = 0;
+}
+
+static const char *vk_strerror(VkResult res)
+{
+ switch(res) {
+ case VK_SUCCESS: return "success";
+ case VK_NOT_READY: return "not ready";
+ case VK_TIMEOUT: return "timeout";
+ case VK_EVENT_SET: return "event set";
+ case VK_EVENT_RESET: return "event reset";
+ case VK_INCOMPLETE: return "incomplete";
+ case VK_ERROR_OUT_OF_HOST_MEMORY: return "out of host memory";
+ case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "out of device memory";
+ case VK_ERROR_INITIALIZATION_FAILED: return "init failed";
+ case VK_ERROR_DEVICE_LOST: return "device lost";
+ case VK_ERROR_MEMORY_MAP_FAILED: return "map failed";
+ case VK_ERROR_LAYER_NOT_PRESENT: return "layer not present";
+ case VK_ERROR_EXTENSION_NOT_PRESENT: return "extension not present";
+ case VK_ERROR_FEATURE_NOT_PRESENT: return "feature not present";
+ case VK_ERROR_INCOMPATIBLE_DRIVER: return "incompatible driver";
+ case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects";
+ case VK_ERROR_FORMAT_NOT_SUPPORTED: return "format not supported";
+ case VK_ERROR_FRAGMENTED_POOL: return "framgented pool";
+ case VK_ERROR_OUT_OF_POOL_MEMORY: return "out of pool memory";
+ case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "invalid external handle";
+ case VK_ERROR_FRAGMENTATION: return "fragmentation";
+ case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "invalid opaque capture address";
+ case VK_ERROR_SURFACE_LOST_KHR: return "surface lost";
+ case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "native window in use";
+ case VK_SUBOPTIMAL_KHR: return "suboptimal";
+ case VK_ERROR_OUT_OF_DATE_KHR: return "out of date";
+ case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "incompatible display";
+ case VK_ERROR_VALIDATION_FAILED_EXT: return "validation failed";
+ case VK_ERROR_INVALID_SHADER_NV: return "invalid shader";
+ case VK_ERROR_INCOMPATIBLE_VERSION_KHR: return "incompatible version";
+ case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "invalid DRM format modifier plane layout";
+ case VK_ERROR_NOT_PERMITTED_EXT: return "not permitted";
+ case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "fullscreen exclusive mode lost";
+ case VK_THREAD_IDLE_KHR: return "thread idle";
+ case VK_THREAD_DONE_KHR: return "thread done";
+ case VK_OPERATION_DEFERRED_KHR: return "operation deferred";
+ case VK_OPERATION_NOT_DEFERRED_KHR: return "operation not deferred";
+ case VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT: return "pipeline compile required";
+
+ case VK_ERROR_UNKNOWN:
+ default:
+ break;
+ }
+
+ return "unknown";
+}