Index: vulkan-game-ref.cpp
===================================================================
--- vulkan-game-ref.cpp	(revision 7dcd92573b58d23f57bc86a91705890d8813242e)
+++ vulkan-game-ref.cpp	(revision 7dcd92573b58d23f57bc86a91705890d8813242e)
@@ -0,0 +1,204 @@
+#include <vulkan/vulkan.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_vulkan.h>
+
+#include <iostream>
+#include <stdexcept>
+#include <vector>
+#include <cstring>
+#include <cstdlib>
+
+using namespace std;
+
+const int SCREEN_WIDTH = 800;
+const int SCREEN_HEIGHT = 600;
+
+const vector<const char*> validationLayers = {
+    "VK_LAYER_KHRONOS_validation"
+};
+
+#ifdef NDEBUG
+const bool enableValidationLayers = false;
+#else
+const bool enableValidationLayers = true;
+#endif
+
+VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
+    auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
+    if (func != nullptr) {
+        return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
+    } else {
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+}
+
+class HelloTriangleApplication {
+public:
+    void run() {
+        initWindow();
+        initVulkan();
+        mainLoop();
+        cleanup();
+    }
+
+private:
+    SDL_Window* window;
+
+    VkInstance instance;
+    VkDebugUtilsMessengerEXT debugMessenger;
+
+    void initWindow() {
+        SDL_Init(SDL_INIT_EVERYTHING);
+
+        window = SDL_CreateWindow("Vulkan Game",
+               SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+               SCREEN_WIDTH, SCREEN_HEIGHT,
+               SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN);
+    }
+
+    void initVulkan() {
+        createInstance();
+        setupDebugMessenger();
+    }
+
+   void mainLoop() {
+      SDL_Event e;
+      bool quit = false;
+
+      while(!quit) {
+         while (SDL_PollEvent(&e)) {
+            if (e.type == SDL_QUIT) {
+               quit = true;
+            }
+            if (e.type == SDL_KEYDOWN) {
+               quit = true;
+            }
+            if (e.type == SDL_MOUSEBUTTONDOWN) {
+               quit = true;
+            }
+         }
+      }
+   }
+
+   void cleanup() {
+      vkDestroyInstance(instance, nullptr);
+
+      SDL_DestroyWindow(window);
+
+      SDL_Quit();
+   }
+
+   void createInstance() {
+      if (enableValidationLayers && !checkValidationLayerSupport()) {
+         throw runtime_error("validation layers requested, but not available!");
+      }
+
+      VkApplicationInfo appInfo = {};
+      appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+      appInfo.pApplicationName = "Hello Triangle";
+      appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
+      appInfo.pEngineName = "No Engine";
+      appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+      appInfo.apiVersion = VK_API_VERSION_1_0;
+
+      VkInstanceCreateInfo createInfo = {};
+      createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+      createInfo.pApplicationInfo = &appInfo;
+
+      auto extensions = getRequiredExtensions();
+      createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
+      createInfo.ppEnabledExtensionNames = extensions.data();
+
+      if (enableValidationLayers) {
+         createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
+         createInfo.ppEnabledLayerNames = validationLayers.data();
+      } else {
+         createInfo.enabledLayerCount = 0;
+      }
+
+      if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
+         throw runtime_error("failed to create instance!");
+      }
+   }
+
+    void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
+        createInfo = {};
+        createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
+        createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+        createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+        createInfo.pfnUserCallback = debugCallback;
+    }
+
+    void setupDebugMessenger() {
+        if (!enableValidationLayers) return;
+
+        VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
+        createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
+        createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+        createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+        createInfo.pfnUserCallback = debugCallback;
+
+        if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
+            throw runtime_error("failed to set up debug messenger!");
+        }
+    }
+
+   vector<const char*> getRequiredExtensions() {
+      uint32_t extensionCount = 0;
+      SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, nullptr);
+
+      vector<const char*> extensions(extensionCount);
+      SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, extensions.data());
+
+      if (enableValidationLayers) {
+         extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+      }
+
+      return extensions;
+   }
+
+    bool checkValidationLayerSupport() {
+        uint32_t layerCount;
+        vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
+
+        vector<VkLayerProperties> availableLayers(layerCount);
+        vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
+
+        for (const char* layerName : validationLayers) {
+            bool layerFound = false;
+
+            for (const auto& layerProperties : availableLayers) {
+                if (strcmp(layerName, layerProperties.layerName) == 0) {
+                    layerFound = true;
+                    break;
+                }
+            }
+
+            if (!layerFound) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
+        cerr << "validation layer: " << pCallbackData->pMessage << endl;
+
+        return VK_FALSE;
+    }
+};
+
+int main() {
+    HelloTriangleApplication app;
+
+    try {
+        app.run();
+    } catch (const exception& e) {
+        cerr << e.what() << endl;
+        return EXIT_FAILURE;
+    }
+
+    return EXIT_SUCCESS;
+}
