summaryrefslogtreecommitdiff
path: root/bk.c
diff options
context:
space:
mode:
Diffstat (limited to 'bk.c')
-rw-r--r--bk.c754
1 files changed, 754 insertions, 0 deletions
diff --git a/bk.c b/bk.c
new file mode 100644
index 0000000..6b669f4
--- /dev/null
+++ b/bk.c
@@ -0,0 +1,754 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_vulkan.h>
+#include <vulkan/vulkan.h>
+
+#define ERRFQ(...) \
+ do { \
+ fprintf(stderr, __VA_ARGS__); \
+ exit(1); \
+ } while(0)
+
+#define ERRQ(str) \
+ do { \
+ fputs((str), stderr); \
+ fputc('\n', stderr); \
+ exit(1); \
+ } while(0)
+
+uint8_t *read_file(const char *path, size_t size)
+{
+ FILE *file = fopen(path, "rb");
+ if (!file) {
+ return NULL;
+ }
+ fseek(file, 0, SEEK_END);
+ size_t len = ftell(file);
+ rewind(file);
+ uint8_t *buf = malloc(len);
+ fread(buf, len, 1, file);
+ fclose(file);
+ *size = len;
+ return buf;
+}
+
+/*
+ * Modifications for Vulkan:
+ * Row-column flipped
+ * Negative y
+ * Expect coordinates on range [0, 1]
+ */
+void perspective_init(float matrix[4][4],
+ const float fov,
+ const float aspect,
+ const float znear,
+ const float zfar)
+{
+ memset(matrix, 0, 16*sizeof(float));
+ const float f = 1.0f / tanf(0.5*fov);
+ matrix[0][0] = f / aspect;
+ matrix[1][1] = -f;
+ matrix[2][2] = -znear/(zfar - znear) - 1.0f;
+ matrix[3][2] = -zfar*znear/(zfar - znear);
+ matrix[2][3] = -1.0f;
+}
+
+void identity_init(float matrix[4][4])
+{
+ memset(matrix, 0, 16*sizeof(float));
+ matrix[0][0] = 1.0f;
+ matrix[1][1] = 1.0f;
+ matrix[2][2] = 1.0f;
+ matrix[3][3] = 1.0f;
+}
+
+struct Uniform {
+ float model[4][4];
+ float view[4][4];
+ float proj[4][4];
+};
+
+static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objType,
+ uint64_t obj,
+ size_t location,
+ int32_t code,
+ const char *layerPrefix,
+ const char *msg,
+ void *userData
+ )
+{
+ fprintf(stderr, "Validation layer: %s\n", msg);
+ return VK_FALSE;
+}
+
+VkResult CreateDebugReportCallbackEXT(
+ VkInstance instance,
+ const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkDebugReportCallbackEXT *pCallback
+ )
+{
+ PFN_vkCreateDebugReportCallbackEXT func = (void*)vkGetInstanceProcAddr(instance,
+ "vkCreateDebugReportCallbackEXT");
+ if (func) {
+ return func(instance, pCreateInfo, pAllocator, pCallback);
+ } else {
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ }
+}
+
+void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
+ const VkAllocationCallbacks *pAllocator)
+{
+ PFN_vkDestroyDebugReportCallbackEXT func = (void*)vkGetInstanceProcAddr(instance,
+ "vkDestroyDebugReportCallbackEXT");
+ if (func) {
+ func(instance, callback, pAllocator);
+ }
+}
+
+SDL_Window *win;
+VkInstance instance;
+VkDebugReportCallbackEXT callback;
+VkSurfaceKHR surface;
+VkPhysicalDevice physicalDevice;
+uint32_t qIndex;
+uint32_t nImages;
+VkDevice device;
+VkSurfaceFormatKHR format;
+VkCommandPool cmdPool;
+VkCommandBuffer cmdBuffers;
+VkSwapchainKHR swapchain;
+VkImage *scImages;
+VkImageView *scImageViews;
+VkImage depthImage;
+VkDeviceMemory depthMem;
+VkImageView depthView;
+VkExtent2D extent;
+VkQueue graphicsQueue;
+VkQueue presentQueue;
+
+static void createInstance()
+{
+ VkApplicationInfo appInfo = {
+ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ .pApplicationName = "VulkanGame",
+ .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
+ .pEngineName = "VulkanGameEngine",
+ .engineVersion = VK_MAKE_VERSION(1, 0, 0),
+ .apiVersion = VK_API_VERSION_1_0
+ };
+
+ unsigned i, nRequired;
+ if (!SDL_Vulkan_GetInstanceExtensions(win, &nRequired, NULL)) {
+ ERRFQ("Could not get number of instance extensions\n");
+ }
+ static const char *const additional[] = {
+ VK_EXT_DEBUG_REPORT_EXTENSION_NAME
+ };
+ const unsigned nAdditional = sizeof(additional) / sizeof(additional[0]);
+ const uint32_t nExtensions = nRequired + nAdditional;
+ const char **extensions = malloc(sizeof(const char*) * nExtensions);
+ if (!SDL_Vulkan_GetInstanceExtensions(win, &nRequired, extensions)) {
+ /* OS will handle memory freeing */
+ ERRQ(SDL_GetError());
+ }
+ for (i = 0; i < nAdditional; ++i) {
+ extensions[nRequired + i] = additional[i];
+ }
+
+ /* Just printing verbosely */
+ for (i = 0; i < nExtensions; ++i) {
+ printf("%s\n", extensions[i]);
+ }
+ printf("\n");
+
+#if 1
+ const uint32_t nLayers = 1;
+ static const char *const layers[] = {
+ "VK_LAYER_LUNARG_standard_validation"
+ };
+#endif
+ VkInstanceCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ .pApplicationInfo = &appInfo,
+ .enabledExtensionCount = nExtensions,
+ .ppEnabledExtensionNames = extensions,
+#if 1
+ .enabledLayerCount = nLayers,
+ .ppEnabledLayerNames = layers
+#endif
+ };
+ VkResult result;
+ if ((result = vkCreateInstance(&createInfo, NULL, &instance)) != VK_SUCCESS) {
+ /* OS will handle memory freeing */
+ ERRFQ("Could not create Vulkan instance: %d\n", result);
+ }
+ free(extensions);
+}
+
+static void createDebugReporter()
+{
+ VkDebugReportCallbackCreateInfoEXT createInfo = {
+ .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
+ .flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
+ .pfnCallback = debugCallback
+ };
+ if (CreateDebugReportCallbackEXT(instance, &createInfo, NULL, &callback) != VK_SUCCESS) {
+ ERRQ("Could not create debug reporter");
+ }
+}
+
+static void selectPhysicalDevice(const char *hint)
+{
+ uint32_t nDevices;
+ vkEnumeratePhysicalDevices(instance, &nDevices, NULL);
+ if (!nDevices) {
+ ERRQ("No physical devices found");
+ }
+ VkPhysicalDevice *devices = malloc(nDevices * sizeof(*devices));
+ vkEnumeratePhysicalDevices(instance, &nDevices, devices);
+
+ /* Just printing verbosely */
+ for (uint32_t i = 0; i < nDevices; ++i) {
+ VkPhysicalDeviceProperties props;
+ vkGetPhysicalDeviceProperties(devices[i], &props);
+ printf("%s\n", props.deviceName);
+ }
+
+ /* FIXME: Blindly choosing the first device */
+ physicalDevice = devices[0];
+
+ uint32_t nQueueFamilies = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &nQueueFamilies, NULL);
+ VkQueueFamilyProperties *qprops = malloc(nQueueFamilies * sizeof(*qprops));
+ vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &nQueueFamilies, qprops);
+
+ for (qIndex = 0; qIndex < nQueueFamilies; ++qIndex) {
+ if (qprops[qIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ break;
+ }
+ }
+ if (qIndex >= nQueueFamilies || nQueueFamilies <= 0) {
+ ERRQ("No queue families capable of graphics");
+ }
+
+ VkBool32 canSurface;
+ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, qIndex, surface, &canSurface);
+ if (!canSurface) {
+ /* Strange devices may be accommodated for but not for now */
+ ERRQ("Graphics device cannot output a surface");
+ }
+
+ VkBool32 canSwapchain = 0;
+ uint32_t nExtensions;
+ vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, NULL);
+ VkExtensionProperties *availableExtensions = malloc(nExtensions * sizeof(*availableExtensions));
+ vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, availableExtensions);
+
+ for (uint32_t i = 0; i < nExtensions; ++i) {
+ if (!strcmp(availableExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+ canSwapchain = 1;
+ break;
+ }
+ }
+ if (!canSwapchain) {
+ ERRQ("Graphics device not swapchain capable");
+ }
+ free(availableExtensions);
+ free(qprops);
+ free(devices);
+}
+
+static void createLogicalDevice()
+{
+ VkPhysicalDeviceFeatures features;
+ vkGetPhysicalDeviceFeatures(physicalDevice, &features);
+ float qPriority = 1.0f;
+ VkDeviceQueueCreateInfo qCreateInfo = {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .queueFamilyIndex = qIndex,
+ .queueCount = 1,
+ .pQueuePriorities = &qPriority
+ };
+
+ const char *const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
+ VkDeviceCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .pQueueCreateInfos = &qCreateInfo,
+ .queueCreateInfoCount = 1,
+ .pEnabledFeatures = &features,
+ .enabledExtensionCount = 1,
+ .ppEnabledExtensionNames = &swapchainName
+ };
+
+ if (vkCreateDevice(physicalDevice, &createInfo, NULL, &device)) {
+ ERRQ("Could not create logical device");
+ }
+}
+
+static void destroyLogicalDevice()
+{
+ vkDestroyDevice(device, NULL);
+}
+
+static void createCommandPool()
+{
+ VkCommandPoolCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .queueFamilyIndex = qIndex
+ };
+ VkResult result;
+ if ((result = vkCreateCommandPool(device, &createInfo, NULL, &cmdPool)) != VK_SUCCESS) {
+ ERRFQ("Could not create command pool: %d\n", result);
+ }
+}
+
+static void destroyCommandPool()
+{
+ vkDestroyCommandPool(device, cmdPool, NULL);
+}
+
+static void createCommandBuffers()
+{
+ VkCommandBufferAllocateInfo allocInfo = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .commandPool = cmdPool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandBufferCount = 1
+ };
+ VkResult result;
+ if ((result = vkAllocateCommandBuffers(device, &allocInfo, &cmdBuffers)) != VK_SUCCESS) {
+ ERRFQ("Could not create command buffers: %d\n", result);
+ }
+}
+
+static void destroyCommandBuffers()
+{
+ vkFreeCommandBuffers(device, cmdPool, 1, &cmdBuffers);
+}
+
+static void createSwapchain()
+{
+ struct {
+ VkSurfaceCapabilitiesKHR capabilities;
+ VkSurfaceFormatKHR *formats;
+ VkPresentModeKHR *presentModes;
+ } sc = {0};
+
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &sc.capabilities);
+ uint32_t nFormats;
+ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &nFormats, NULL);
+ if (!nFormats) {
+ ERRQ("No surface formats available");
+ }
+ sc.formats = malloc(nFormats * sizeof(*sc.formats));
+ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &nFormats, sc.formats);
+
+ uint32_t nPresentModes;
+ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &nPresentModes, NULL);
+ if (!nPresentModes) {
+ ERRQ("No surface present modes available");
+ }
+ sc.presentModes = malloc(nPresentModes * sizeof(*sc.presentModes));
+ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &nPresentModes, sc.presentModes);
+
+ for (uint32_t i = 0; i < nFormats; ++i) {
+ VkSurfaceFormatKHR want = {
+ VK_FORMAT_B8G8R8A8_UNORM, // BGRA
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
+ };
+ if (sc.formats[i].format == VK_FORMAT_UNDEFINED) {
+ format = want;
+ fprintf(stderr, "Obtained wanted surface format on first try\n");
+ break;
+ }
+ if (sc.formats[i].format == want.format && sc.formats[i].colorSpace == want.colorSpace) {
+ format = want;
+ fprintf(stderr, "Obtained wanted format on try %d/%d\n", i+1, nFormats);
+ break;
+ }
+ }
+
+ /* FIXME: Just assuming this is available */
+ VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
+
+ int width, height;
+ SDL_Vulkan_GetDrawableSize(win, &width, &height);
+ extent.width = width;
+ extent.height = height;
+
+ nImages = sc.capabilities.minImageCount + 1;
+ if (sc.capabilities.maxImageCount > 0 && nImages > sc.capabilities.maxImageCount) {
+ /* Clamp to max image count if too many requested */
+ nImages = sc.capabilities.maxImageCount;
+ }
+
+ VkSwapchainCreateInfoKHR createInfo = {
+ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ .surface = surface,
+ .minImageCount = nImages,
+ .imageFormat = format.format,
+ .imageExtent = extent,
+ .imageArrayLayers = 1,
+ .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, // assuming same family
+ .preTransform = sc.capabilities.currentTransform,
+ .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ .presentMode = presentMode,
+ .clipped = VK_TRUE,
+ .oldSwapchain = VK_NULL_HANDLE
+ };
+
+ VkResult result;
+ if ((result = vkCreateSwapchainKHR(device, &createInfo, NULL, &swapchain)) != VK_SUCCESS) {
+ ERRFQ("Could not create swapchain: %d\n", result);
+ }
+ free(sc.presentModes);
+ free(sc.formats);
+}
+
+static void destroySwapchain()
+{
+ if (swapchain) {
+ vkDestroySwapchainKHR(device, swapchain, NULL);
+ }
+ swapchain = NULL;
+}
+
+/* Allocates and reallocates memory */
+static void createSwapchainImages()
+{
+ vkGetSwapchainImagesKHR(device, swapchain, &nImages, NULL);
+ scImages = realloc(scImages, nImages * sizeof(*scImages));
+ vkGetSwapchainImagesKHR(device, swapchain, &nImages, scImages);
+ scImageViews = realloc(scImageViews, nImages * sizeof(*scImageViews));
+
+ for (uint32_t i = 0; i < nImages; ++i) {
+ VkImageViewCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .image = scImages[i],
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
+ .format = format.format,
+ .components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .components.a = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .subresourceRange.baseMipLevel = 0,
+ .subresourceRange.levelCount = 1,
+ .subresourceRange.baseArrayLayer = 0,
+ .subresourceRange.layerCount = 1
+
+ };
+ if (vkCreateImageView(device, &createInfo, NULL, &scImageViews[i]) != VK_SUCCESS) {
+ ERRQ("Could not create swapchain image views");
+ }
+ }
+}
+
+static void destroySwapchainImages()
+{
+ for (uint32_t i = 0; i < nImages; ++i) {
+ vkDestroyImageView(device, scImageViews[i], NULL);
+ }
+ free(scImageViews);
+ free(scImages);
+ scImageViews = NULL;
+ scImages = NULL;
+}
+
+static void createDepthBuffer()
+{
+ VkImageCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+ .imageType = VK_IMAGE_TYPE_2D,
+ .format = VK_FORMAT_D32_SFLOAT,
+ .extent.width = extent.width,
+ .extent.height = extent.height,
+ .extent.depth = 1,
+ .mipLevels = 1,
+ .arrayLayers = 1,
+ .samples = VK_SAMPLE_COUNT_1_BIT,
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ };
+ VkResult result;
+ if ((result = vkCreateImage(device, &createInfo, NULL, &depthImage)) != VK_SUCCESS) {
+ ERRFQ("Could not create depth image: %d\n", result);
+ }
+ VkPhysicalDeviceMemoryProperties memProps;
+ vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);
+ VkMemoryRequirements memReq;
+ vkGetImageMemoryRequirements(device, depthImage, &memReq);
+ uint32_t typeFilter = memReq.memoryTypeBits;
+ uint32_t memType;
+ uint32_t props = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ for (memType = 0; memType < memProps.memoryTypeCount; ++memType) {
+ if (typeFilter & (1<<memType) && (memProps.memoryTypes[memType].propertyFlags & props) == props) {
+ break;
+ }
+ }
+ VkMemoryAllocateInfo allocInfo = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = memReq.size,
+ .memoryTypeIndex = memType
+ };
+ if ((result = vkAllocateMemory(device, &allocInfo, NULL, &depthMem)) != VK_SUCCESS) {
+ ERRFQ("Could not allocate depth buffer memory: %d\n", result);
+ }
+ if ((result = vkBindImageMemory(device, depthImage, depthMem, 0)) != VK_SUCCESS) {
+ ERRFQ("Could not bind depth buffer image memory: %d\n", result);
+ }
+
+ VkImageViewCreateInfo viewInfo = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .image = depthImage,
+ .format = VK_FORMAT_D32_SFLOAT,
+ .components.r = VK_COMPONENT_SWIZZLE_R,
+ .components.g = VK_COMPONENT_SWIZZLE_G,
+ .components.b = VK_COMPONENT_SWIZZLE_B,
+ .components.a = VK_COMPONENT_SWIZZLE_A,
+ .subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
+ .subresourceRange.baseMipLevel = 0,
+ .subresourceRange.levelCount = 1,
+ .subresourceRange.baseArrayLayer = 0,
+ .subresourceRange.layerCount = 1,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
+ };
+ if ((result = vkCreateImageView(device, &viewInfo, NULL, &depthView)) != VK_SUCCESS) {
+ ERRFQ("Could not create depth buffer image view: %d\n", result);
+ }
+}
+
+static void destroyDepthBuffer()
+{
+ vkDestroyImageView(device, depthView, NULL);
+ vkFreeMemory(device, depthMem, NULL);
+ vkDestroyImage(device, depthImage, NULL);
+}
+
+void initVulkan()
+{
+ createInstance();
+ createDebugReporter();
+ if (!SDL_Vulkan_CreateSurface(win, instance, &surface)) {
+ ERRQ(SDL_GetError());
+ }
+}
+
+void deinitVulkan()
+{
+ vkDestroySurfaceKHR(instance, surface, NULL);
+ DestroyDebugReportCallbackEXT(instance, callback, NULL);
+ vkDestroyInstance(instance, NULL);
+}
+
+void beginVulkan()
+{
+ selectPhysicalDevice(NULL);
+ createLogicalDevice();
+ createCommandPool();
+ createCommandBuffers();
+ vkGetDeviceQueue(device, qIndex, 0, &graphicsQueue);
+ vkGetDeviceQueue(device, qIndex, 0, &presentQueue);
+ createSwapchain();
+ createSwapchainImages();
+ createDepthBuffer();
+}
+
+void endVulkan()
+{
+ destroyDepthBuffer();
+ destroySwapchainImages();
+ destroySwapchain();
+ destroyCommandBuffers();
+ destroyCommandPool();
+ destroyLogicalDevice();
+}
+
+struct Uniform uniData;
+VkBuffer uniBuffer;
+VkDeviceMemory uniMem;
+
+static void createUniformBuffer()
+{
+ VkBufferCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ .size = sizeof(struct Uniform),
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE
+ };
+
+ VkResult result;
+ if ((result = vkCreateBuffer(device, &createInfo, NULL, &uniBuffer)) != VK_SUCCESS) {
+ ERRFQ("Could not create uniform buffer: %d\n", result);
+ }
+
+ VkPhysicalDeviceMemoryProperties memProps;
+ vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);
+ VkMemoryRequirements memReq;
+ vkGetBufferMemoryRequirements(device, uniBuffer, &memReq);
+ uint32_t typeFilter = memReq.memoryTypeBits;
+ uint32_t memType;
+ uint32_t props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ for (memType = 0; memType < memProps.memoryTypeCount; ++memType) {
+ if (typeFilter & (1<<memType) && (memProps.memoryTypes[memType].propertyFlags & props) == props) {
+ break;
+ }
+ }
+
+ VkMemoryAllocateInfo allocInfo = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = memReq.size,
+ .memoryTypeIndex = memType
+ };
+
+ if ((result = vkAllocateMemory(device, &allocInfo, NULL, &uniMem)) != VK_SUCCESS) {
+ ERRFQ("Could not allocate uniform buffer memory: %d\n", result);
+ }
+
+ if ((result = vkBindBufferMemory(device, uniBuffer, uniMem, 0)) != VK_SUCCESS) {
+ ERRFQ("Could not bind uniform buffer memory: %d\n", result);
+ }
+}
+
+static void populateUniformBuffer()
+{
+ identity_init(uniData.model);
+ identity_init(uniData.view);
+ identity_init(uniData.proj);
+ VkResult result;
+ void *data;
+ if ((result = vkMapMemory(device, uniMem, 0, sizeof(uniData), 0, &data)) != VK_SUCCESS) {
+ ERRFQ("Could not map uniform buffer memory: %d\n", result);
+ }
+ memcpy(data, &uniData, sizeof(uniData));
+ vkUnmapMemory(device, uniMem);
+}
+
+VkDescriptorSetLayout descriptorSetLayout;
+
+static void createDescriptorSetLayout()
+{
+ VkDescriptorSetLayoutBinding layoutBinding = {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT
+ };
+ VkDescriptorSetLayoutCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_CREATE_INFO,
+ .bindingCount = 1,
+ .pBindings = &layoutBinding
+ };
+ VkResult result;
+ if ((result = vkCreateDescriptorSetLayout(device, &createInfo, NULL, descriptorSetLayout)) != VK_SUCCESS) {
+ ERRFQ("Could not create descriptor set layout: %d\n", result);
+ }
+}
+
+static void createPipelineLayout()
+{
+ VkPipelineLayoutCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .pushConstantRangeCount = 0,
+ .setLayoutCount = 1, // number of descriptor sets
+ .pSetLayouts = &descriptorSetLayout
+ };
+ VkResult result;
+ if ((result = vkCreatePipelineLayout(device, &createInfo, NULL, &pipelineLayout)) != VK_SUCCESS) {
+ ERRFQ("Could not create pipeline layout: %d\n", result);
+ }
+}
+
+VkShaderModule vShaderModule;
+VkShaderModule fShaderModule;
+
+static void createShaderModules()
+{
+ size_t vertLen, fragLen;
+ uint8_t *vertCode = read_file("vert.spv", &vertLen);
+ if (!vertCode) {
+ ERRQ("Could not read vert.spv");
+ }
+ uint8_t *fragCode = read_file("frag.spv", &fragLen);
+ if (!fragCode) {
+ ERRQ("Could not read frag.spv");
+ }
+
+ VkShaderModuleCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+ .codeSize = vertLen,
+ .pCode = (void*)vertCode
+ };
+
+ VkResult result;
+ if ((result = vkCreateShaderModule(device, &createInfo, NULL, &vShaderModule)) != VK_SUCCESS) {
+ ERRFQ("Could not create vertex shader module: %d\n", result);
+ }
+
+ createInfo.codeSize = fraglen;
+ createInfo.pCode = (void*)fragCode;
+ if ((result = vkCreateShaderModule(device, &createInfo, NULL, &fShaderModule)) != VK_SUCCESS) {
+ ERRFQ("Could not create fragment shader module: %d\n", result);
+ }
+
+ free(vertCode);
+ free(fragCode);
+}
+
+static void createGraphicsPipeline
+
+void setupScene()
+{
+ createUniformBuffer();
+ populateUniformBuffer();
+ createDescriptorSetLayout();
+ createPipelineLayout();
+ createShaderModules();
+}
+
+int main(int argc, char **argv)
+{
+ if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
+ ERRQ(SDL_GetError());
+ }
+ if (SDL_Vulkan_LoadLibrary(NULL)) {
+ ERRQ(SDL_GetError());
+ }
+ win = SDL_CreateWindow(
+ "Vulkan Window",
+ SDL_WINDOWPOS_CENTERED,
+ SDL_WINDOWPOS_CENTERED,
+ 1280,
+ 720,
+ SDL_WINDOW_VULKAN
+ );
+ if (!win) {
+ ERRQ(SDL_GetError());
+ }
+ initVulkan();
+ beginVulkan();
+
+ SDL_Event e;
+ while (1) {
+ while (SDL_PollEvent(&e)) {
+ if (e.type == SDL_QUIT) {
+ goto quit;
+ }
+ }
+ }
+quit:
+ endVulkan();
+ deinitVulkan();
+ SDL_DestroyWindow(win);
+ SDL_Vulkan_UnloadLibrary();
+ SDL_Quit();
+ return 0;
+}