|
@@ -2,220 +2,139 @@
|
|
|
|
|
|
#include <core/Logger.h>
|
|
|
#include <core/Utility.h>
|
|
|
-#include <stdio.h>
|
|
|
|
|
|
-#include "core/internal/GLFW.h"
|
|
|
+#include "GLFW.h"
|
|
|
+#include "VulkanUtils.h"
|
|
|
|
|
|
-typedef struct {
|
|
|
- VkPhysicalDevice physical;
|
|
|
- VkDevice logical;
|
|
|
- u32 graphicsFamily;
|
|
|
- VkQueue graphicsQueue;
|
|
|
-} Device;
|
|
|
+// VkCommandPool commandPool;
|
|
|
+// VkCommandBuffer* commandsBuffers;
|
|
|
+// VkFramebuffer* framebuffers;
|
|
|
+// VkSemaphore semaphore;
|
|
|
+// VkSemaphore renderSemaphore;
|
|
|
+// VkRenderPass renderPass;
|
|
|
|
|
|
-typedef struct {
|
|
|
- VkFormat format;
|
|
|
- VkSwapchainKHR handle;
|
|
|
- u32 amount;
|
|
|
- VkImage* images;
|
|
|
- VkImageView* imageViews;
|
|
|
- VkCommandPool commandPool;
|
|
|
- VkCommandBuffer* commandsBuffers;
|
|
|
- VkFramebuffer* framebuffers;
|
|
|
-} Swapchain;
|
|
|
+static VkPhysicalDevice physicalDevice;
|
|
|
+static u32 graphicsFamily = 0;
|
|
|
+static u32 presentFamily = 0;
|
|
|
+static VkDevice device;
|
|
|
+static VkQueue graphicsQueue;
|
|
|
+static VkQueue presentQueue;
|
|
|
+static VkSurfaceFormatKHR surfaceFormat;
|
|
|
+static VkSurfaceKHR surface;
|
|
|
+static VkSwapchainKHR swapchain;
|
|
|
+static VulkanSwapchainImages images;
|
|
|
|
|
|
-typedef struct {
|
|
|
- // basic setup
|
|
|
- VkInstance instance;
|
|
|
- VkSurfaceKHR surface;
|
|
|
-#ifdef DEBUG_VULKAN
|
|
|
- VkDebugUtilsMessengerEXT debugMessenger;
|
|
|
- VkDebugReportCallbackEXT debugReportCallback;
|
|
|
-#endif
|
|
|
- // render setup
|
|
|
- Device device;
|
|
|
- VkSemaphore semaphore;
|
|
|
- VkSemaphore renderSemaphore;
|
|
|
- Swapchain swapchain;
|
|
|
- VkRenderPass renderPass;
|
|
|
- u32 width;
|
|
|
- u32 height;
|
|
|
-} VulkanData;
|
|
|
-
|
|
|
-static VulkanData vk = {0};
|
|
|
-
|
|
|
-#define VK_ERROR_CASE(error) \
|
|
|
- case error: return #error
|
|
|
-
|
|
|
-static const char* getVulkanErrorString(VkResult r) {
|
|
|
- switch(r) {
|
|
|
- VK_ERROR_CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
- VK_ERROR_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
|
|
- VK_ERROR_CASE(VK_ERROR_INITIALIZATION_FAILED);
|
|
|
- VK_ERROR_CASE(VK_ERROR_LAYER_NOT_PRESENT);
|
|
|
- VK_ERROR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
|
|
|
- VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
|
|
|
- default: return "unknown";
|
|
|
+static int getSurfaceFormatPoints(const VkSurfaceFormatKHR* sf) {
|
|
|
+ if(sf->format == VK_FORMAT_B8G8R8A8_UNORM &&
|
|
|
+ sf->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
|
+ return 10;
|
|
|
}
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
-#define VK_ASSERT(a) \
|
|
|
- do { \
|
|
|
- VkResult vkResult = (a); \
|
|
|
- if(vkResult != VK_SUCCESS) { \
|
|
|
- LOG_ERROR("Vulkan error: %s\n", getVulkanErrorString(vkResult)); \
|
|
|
- return true; \
|
|
|
- } \
|
|
|
- } while(false)
|
|
|
-
|
|
|
-static PFN_vkVoidFunction getVulkanFunction(const char* name) {
|
|
|
- return vkGetInstanceProcAddr(vk.instance, name);
|
|
|
+static int getSurfacePresentModePoints(VkPresentModeKHR m) {
|
|
|
+ if(m == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
|
+ return 5;
|
|
|
+ } else if(m == VK_PRESENT_MODE_FIFO_KHR) {
|
|
|
+ return 2;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-#define GET_VULKAN_FUNCTION(name) ((PFN_##name)getVulkanFunction(#name))
|
|
|
-
|
|
|
-static bool initInstance() {
|
|
|
- u32 baseCount = 0;
|
|
|
- const char** baseExtensions = glfwGetRequiredInstanceExtensions(&baseCount);
|
|
|
- if(baseExtensions == nullptr) {
|
|
|
- LOG_ERROR("Could not get required extensions from GLFW");
|
|
|
- return true;
|
|
|
+static bool getSwapchainSize(VkExtent2D* size) {
|
|
|
+ VkSurfaceCapabilitiesKHR c = {0};
|
|
|
+ VK_ASSERT(
|
|
|
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &c));
|
|
|
+ if(c.currentExtent.width != 0xFFFF'FFFFu &&
|
|
|
+ c.currentExtent.height != 0xFFFF'FFFFu) {
|
|
|
+ *size = c.currentExtent;
|
|
|
+ LOG_INFO("Swapchain size: %ux%u", size->width, size->height);
|
|
|
+ return false;
|
|
|
}
|
|
|
-#ifdef DEBUG_VULKAN
|
|
|
- u32 count = baseCount + 2;
|
|
|
- const char* extensions[32];
|
|
|
- if(count > ARRAY_LENGTH(extensions)) {
|
|
|
- LOG_ERROR("Extension buffer is too small");
|
|
|
+ int w = 0;
|
|
|
+ int h = 0;
|
|
|
+ glfwGetFramebufferSize(getWindow(), &w, &h);
|
|
|
+ if(w <= 0 || h <= 0) {
|
|
|
+ LOG_ERROR("Could not get framebuffer size");
|
|
|
return true;
|
|
|
}
|
|
|
- for(u32 i = 0; i < baseCount; i++) {
|
|
|
- extensions[i] = baseExtensions[i];
|
|
|
- }
|
|
|
- extensions[baseCount] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
|
|
|
- extensions[baseCount + 1] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
|
|
|
-#else
|
|
|
- u32 count = baseCount;
|
|
|
- const char** extensions = baseExtensions;
|
|
|
-#endif
|
|
|
- VkApplicationInfo appInfo = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
|
- .pApplicationName = "Vulkan",
|
|
|
- .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
|
|
|
- .pEngineName = "Kajetan",
|
|
|
- .engineVersion = VK_MAKE_VERSION(0, 0, 1),
|
|
|
- .apiVersion = VK_API_VERSION_1_1};
|
|
|
- VkInstanceCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
|
- .pApplicationInfo = &appInfo,
|
|
|
-#ifdef DEBUG_VULKAN
|
|
|
- .enabledLayerCount = 1,
|
|
|
- .ppEnabledLayerNames = (const char*[]){"VK_LAYER_KHRONOS_validation"},
|
|
|
-#endif
|
|
|
- .enabledExtensionCount = count,
|
|
|
- .ppEnabledExtensionNames = extensions};
|
|
|
- VK_ASSERT(vkCreateInstance(&info, nullptr, &vk.instance));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef DEBUG_VULKAN
|
|
|
-static VKAPI_ATTR VkBool32 onVulkanDebugMessenger VKAPI_CALL(
|
|
|
- VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
|
|
|
- const VkDebugUtilsMessengerCallbackDataEXT* data, void*) {
|
|
|
- LOG_WARNING("Vulkan validation layer message: %s", data->pMessage);
|
|
|
+ LOG_INFO("Framebuffer size: %dx%d", w, h);
|
|
|
+ size->width =
|
|
|
+ clampU32((u32)w, c.minImageExtent.width, c.maxImageExtent.width);
|
|
|
+ size->height =
|
|
|
+ clampU32((u32)h, c.minImageExtent.height, c.maxImageExtent.height);
|
|
|
+ LOG_INFO("Swapchain size: %ux%u", size->width, size->height);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool initDebugMessenger() {
|
|
|
- VkDebugUtilsMessengerCreateInfoEXT info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
|
|
- .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
|
|
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
|
|
|
- .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,
|
|
|
- .pfnUserCallback = onVulkanDebugMessenger};
|
|
|
- auto f = GET_VULKAN_FUNCTION(vkCreateDebugUtilsMessengerEXT);
|
|
|
- if(f == nullptr) {
|
|
|
- LOG_WARNING("Could not find debug util messenger function");
|
|
|
- return false;
|
|
|
+static bool initSwapchain() {
|
|
|
+ VulkanSwapchainData d = {
|
|
|
+ .physicalDevice = physicalDevice, .device = device, .surface = surface};
|
|
|
+ if(getSwapchainSize(&d.size)) {
|
|
|
+ LOG_ERROR("Could not retrieve any swapchain size");
|
|
|
+ return true;
|
|
|
}
|
|
|
- VK_ASSERT(f(vk.instance, &info, nullptr, &vk.debugMessenger));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static VKAPI_ATTR VkBool32 onVulkanDebugReport VKAPI_CALL(
|
|
|
- VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t,
|
|
|
- int32_t, const char* pLayerPrefix, const char* pMessage, void*) {
|
|
|
- LOG_WARNING("Vulkan debug message '%s': %s", pLayerPrefix, pMessage);
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static bool initDebugReportCallback() {
|
|
|
- VkDebugReportCallbackCreateInfoEXT info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
|
|
|
- .flags = VK_DEBUG_REPORT_WARNING_BIT_EXT |
|
|
|
- VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
|
|
|
- VK_DEBUG_REPORT_ERROR_BIT_EXT,
|
|
|
- .pfnCallback = onVulkanDebugReport};
|
|
|
- auto f = GET_VULKAN_FUNCTION(vkCreateDebugReportCallbackEXT);
|
|
|
- if(f == nullptr) {
|
|
|
- LOG_WARNING("Could not find debug report function");
|
|
|
- return false;
|
|
|
+ if(findVulkanSurfaceFormat(
|
|
|
+ &d.surfaceFormat, physicalDevice, surface, getSurfaceFormatPoints)) {
|
|
|
+ LOG_ERROR("Could not find surface format");
|
|
|
+ return true;
|
|
|
}
|
|
|
- VK_ASSERT(f(vk.instance, &info, nullptr, &vk.debugReportCallback));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static bool initDebugging() {
|
|
|
- return initDebugMessenger() || initDebugReportCallback();
|
|
|
-}
|
|
|
-
|
|
|
-static void destroyDebugMessenger() {
|
|
|
- auto f = GET_VULKAN_FUNCTION(vkDestroyDebugUtilsMessengerEXT);
|
|
|
- if(f == nullptr) {
|
|
|
- LOG_WARNING("Could not find debug util messenger destroy function");
|
|
|
- return;
|
|
|
+ surfaceFormat = d.surfaceFormat;
|
|
|
+ if(findVulkanSurfacePresentMode(
|
|
|
+ &d.presentMode, physicalDevice, surface,
|
|
|
+ getSurfacePresentModePoints)) {
|
|
|
+ LOG_ERROR("Could not find present mode");
|
|
|
+ return true;
|
|
|
}
|
|
|
- f(vk.instance, vk.debugMessenger, nullptr);
|
|
|
-}
|
|
|
-
|
|
|
-static void destroyDebugReportCallback() {
|
|
|
- auto f = GET_VULKAN_FUNCTION(vkDestroyDebugReportCallbackEXT);
|
|
|
- if(f == nullptr) {
|
|
|
- LOG_WARNING("Could not find debug report destroy function");
|
|
|
- return;
|
|
|
+ u32 queueFamilyIndices[] = {graphicsFamily, presentFamily};
|
|
|
+ if(graphicsFamily != presentFamily) {
|
|
|
+ d.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
|
+ d.queueFamilyIndexCount = 2;
|
|
|
+ d.queueFamilyIndices = queueFamilyIndices;
|
|
|
+ } else {
|
|
|
+ d.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
}
|
|
|
- f(vk.instance, vk.debugReportCallback, nullptr);
|
|
|
-}
|
|
|
-#else
|
|
|
-static bool initDebugging() {
|
|
|
- (void)getVulkanFunction;
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static void destroyDebugMessenger() {
|
|
|
+ return initVulkanSwapchain(&swapchain, &d);
|
|
|
}
|
|
|
|
|
|
-static void destroyDebugReportCallback() {
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-static u32 findQueueFamilies(VkPhysicalDevice pd, VkQueueFlags flags) {
|
|
|
- VkQueueFamilyProperties properties[32];
|
|
|
- u32 count = ARRAY_LENGTH(properties);
|
|
|
- vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, properties);
|
|
|
- for(u32 i = 0; i < count; i++) {
|
|
|
- if((properties[i].queueFlags & flags) == flags) {
|
|
|
- return i;
|
|
|
- }
|
|
|
+static bool initDevice() {
|
|
|
+ graphicsFamily =
|
|
|
+ findVulkanQueueFamily(physicalDevice, VK_QUEUE_GRAPHICS_BIT);
|
|
|
+ presentFamily = findVulkanSurfaceQueueFamily(physicalDevice, surface);
|
|
|
+ if(graphicsFamily == INVALID_VULKAN_QUEUE_FAMILY ||
|
|
|
+ presentFamily == INVALID_VULKAN_QUEUE_FAMILY) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ bool same = graphicsFamily == presentFamily;
|
|
|
+ VulkanDeviceQueueData data[] = {
|
|
|
+ {graphicsFamily, 1.0f}, {presentFamily, 1.0f}};
|
|
|
+ const char* extensions[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
|
|
+ if(initVulkanDevice(
|
|
|
+ &device, physicalDevice, data, same ? 1 : 2, extensions,
|
|
|
+ ARRAY_LENGTH(extensions))) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue);
|
|
|
+ if(graphicsQueue == VK_NULL_HANDLE) {
|
|
|
+ LOG_ERROR("Cannot get device graphics queue");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if(same) {
|
|
|
+ presentQueue = graphicsQueue;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ vkGetDeviceQueue(device, presentFamily, 0, &presentQueue);
|
|
|
+ if(presentQueue == VK_NULL_HANDLE) {
|
|
|
+ LOG_ERROR("Cannot get device present queue");
|
|
|
+ return true;
|
|
|
}
|
|
|
- return (u32)-1;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-static int getDevicePoints(Device* d) {
|
|
|
+static int getDevicePoints(VkPhysicalDevice pd) {
|
|
|
int points = 0;
|
|
|
VkPhysicalDeviceProperties p;
|
|
|
- vkGetPhysicalDeviceProperties(d->physical, &p);
|
|
|
+ vkGetPhysicalDeviceProperties(pd, &p);
|
|
|
LOG_INFO("Checking '%s'", p.deviceName);
|
|
|
switch(p.deviceType) {
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: points += 100; break;
|
|
@@ -223,358 +142,85 @@ static int getDevicePoints(Device* d) {
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: points += 20; break;
|
|
|
default: break;
|
|
|
}
|
|
|
- d->graphicsFamily = findQueueFamilies(d->physical, VK_QUEUE_GRAPHICS_BIT);
|
|
|
- if(d->graphicsFamily == (u32)-1) {
|
|
|
+ u32 gf = findVulkanQueueFamily(pd, VK_QUEUE_GRAPHICS_BIT);
|
|
|
+ if(gf == INVALID_VULKAN_QUEUE_FAMILY) {
|
|
|
LOG_INFO("> ... has no graphics family");
|
|
|
points = -1;
|
|
|
}
|
|
|
+ u32 pf = findVulkanSurfaceQueueFamily(pd, surface);
|
|
|
+ if(pf == INVALID_VULKAN_QUEUE_FAMILY) {
|
|
|
+ LOG_INFO("> ... has no present family");
|
|
|
+ points = -1;
|
|
|
+ }
|
|
|
+ if(!hasVulkanExtension(pd, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
|
|
|
+ LOG_INFO("> ... has no swapchain support");
|
|
|
+ points = -1;
|
|
|
+ }
|
|
|
+ VkSurfaceFormatKHR sf = {0};
|
|
|
+ if(findVulkanSurfaceFormat(&sf, pd, surface, getSurfaceFormatPoints)) {
|
|
|
+ LOG_INFO("> ... has no matching surface format");
|
|
|
+ points = -1;
|
|
|
+ } else {
|
|
|
+ points += getSurfaceFormatPoints(&sf);
|
|
|
+ }
|
|
|
+ VkPresentModeKHR m = 0;
|
|
|
+ if(findVulkanSurfacePresentMode(
|
|
|
+ &m, pd, surface, getSurfacePresentModePoints)) {
|
|
|
+ LOG_INFO("> ... has no matching present mode");
|
|
|
+ points = -1;
|
|
|
+ } else {
|
|
|
+ points += getSurfacePresentModePoints(m);
|
|
|
+ }
|
|
|
LOG_INFO("> Final points: %d", points);
|
|
|
return points;
|
|
|
}
|
|
|
|
|
|
static bool initPhysicalDevice() {
|
|
|
- VkPhysicalDevice devices[32];
|
|
|
- u32 c = ARRAY_LENGTH(devices);
|
|
|
- VK_ASSERT(vkEnumeratePhysicalDevices(vk.instance, &c, devices));
|
|
|
- LOG_INFO("Found %u physical devices", c);
|
|
|
- int bestPoints = 0;
|
|
|
- for(u32 i = 0; i < c; i++) {
|
|
|
- Device d = {.physical = devices[i]};
|
|
|
- int points = getDevicePoints(&d);
|
|
|
- if(points > bestPoints) {
|
|
|
- bestPoints = points;
|
|
|
- vk.device = d;
|
|
|
- }
|
|
|
- }
|
|
|
- if(bestPoints == 0) {
|
|
|
+ LOG_INFO("Searching for physical devices ...");
|
|
|
+ if(findVulkanPhysicalDevice(&physicalDevice, getDevicePoints)) {
|
|
|
LOG_ERROR("No matching physical device was found");
|
|
|
return true;
|
|
|
}
|
|
|
VkPhysicalDeviceProperties p;
|
|
|
- vkGetPhysicalDeviceProperties(vk.device.physical, &p);
|
|
|
+ vkGetPhysicalDeviceProperties(physicalDevice, &p);
|
|
|
LOG_INFO("Best Device: %s", p.deviceName);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool getDeviceQueue(Device* d, VkQueue* q) {
|
|
|
- vkGetDeviceQueue(d->logical, d->graphicsFamily, 0, q);
|
|
|
- return *q == VK_NULL_HANDLE;
|
|
|
-}
|
|
|
-
|
|
|
-static bool initDevice(Device* d) {
|
|
|
- VkPhysicalDeviceFeatures deviceFeatures = {0};
|
|
|
- vkGetPhysicalDeviceFeatures(d->physical, &deviceFeatures);
|
|
|
- VkDeviceQueueCreateInfo deviceQueueInfo = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
|
|
- .queueFamilyIndex = d->graphicsFamily,
|
|
|
- .queueCount = 1,
|
|
|
- .pQueuePriorities = (float[]){1.0f}};
|
|
|
- VkDeviceCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
|
- .queueCreateInfoCount = 1,
|
|
|
- .pQueueCreateInfos = &deviceQueueInfo,
|
|
|
- .enabledExtensionCount = 1,
|
|
|
- .ppEnabledExtensionNames =
|
|
|
- (const char*[]){VK_KHR_SWAPCHAIN_EXTENSION_NAME},
|
|
|
- .pEnabledFeatures = &deviceFeatures};
|
|
|
- VK_ASSERT(vkCreateDevice(d->physical, &info, nullptr, &d->logical));
|
|
|
- if(getDeviceQueue(d, &d->graphicsQueue)) {
|
|
|
- LOG_ERROR("Cannot get device graphics queue");
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static bool initSurface() {
|
|
|
- VK_ASSERT(glfwCreateWindowSurface(
|
|
|
- vk.instance, getWindow(), nullptr, &vk.surface));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static u32 getSwapImageCount(const VkSurfaceCapabilitiesKHR* caps) {
|
|
|
- u32 c = caps->minImageCount + 1;
|
|
|
- // according to VkSurfaceCapabilitiesKHR doc:
|
|
|
- // maxImageCount is 0 when there is no strict limit
|
|
|
- if(caps->maxImageCount != 0 && c > caps->maxImageCount) {
|
|
|
- return caps->maxImageCount;
|
|
|
- }
|
|
|
- return c;
|
|
|
-}
|
|
|
-
|
|
|
-static bool getSurfaceFormat(VkSurfaceFormatKHR* sf) {
|
|
|
- u32 c = 0;
|
|
|
- VK_ASSERT(vkGetPhysicalDeviceSurfaceFormatsKHR(
|
|
|
- vk.device.physical, vk.surface, &c, nullptr));
|
|
|
- VkSurfaceFormatKHR* formats = coreAllocate(sizeof(VkSurfaceFormatKHR) * c);
|
|
|
- VK_ASSERT(vkGetPhysicalDeviceSurfaceFormatsKHR(
|
|
|
- vk.device.physical, vk.surface, &c, formats));
|
|
|
- for(u32 i = 0; i < c; i++) {
|
|
|
- if(formats[i].format == VK_FORMAT_B8G8R8A8_UNORM &&
|
|
|
- formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
|
- *sf = formats[i];
|
|
|
- coreFree(formats);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- coreFree(formats);
|
|
|
- LOG_ERROR("Could not find any matching surface format");
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static bool getPresentMode(VkPresentModeKHR* pm) {
|
|
|
- u32 c = 0;
|
|
|
- VK_ASSERT(vkGetPhysicalDeviceSurfacePresentModesKHR(
|
|
|
- vk.device.physical, vk.surface, &c, nullptr));
|
|
|
- VkPresentModeKHR* modes = coreAllocate(sizeof(VkPresentModeKHR) * c);
|
|
|
- VK_ASSERT(vkGetPhysicalDeviceSurfacePresentModesKHR(
|
|
|
- vk.device.physical, vk.surface, &c, modes));
|
|
|
- for(u32 i = 0; i < c; i++) {
|
|
|
- if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
|
- *pm = modes[i];
|
|
|
- coreFree(modes);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- coreFree(modes);
|
|
|
- LOG_ERROR("Could not find any matching present modes");
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static bool initSwapchain() {
|
|
|
- VkSurfaceCapabilitiesKHR caps = {0};
|
|
|
- VK_ASSERT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
|
|
- vk.device.physical, vk.surface, &caps));
|
|
|
- VkSurfaceFormatKHR sf = {0};
|
|
|
- if(getSurfaceFormat(&sf)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- vk.swapchain.format = sf.format;
|
|
|
- VkPresentModeKHR pm = {0};
|
|
|
- if(getPresentMode(&pm)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- VkSwapchainCreateInfoKHR ci = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
|
|
- .surface = vk.surface,
|
|
|
- .minImageCount = getSwapImageCount(&caps),
|
|
|
- .imageFormat = sf.format,
|
|
|
- .imageColorSpace = sf.colorSpace,
|
|
|
- .imageExtent = {.width = vk.width, .height = vk.height},
|
|
|
- .imageArrayLayers = 1,
|
|
|
- .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
|
|
- VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
|
|
- .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
- .queueFamilyIndexCount = 1,
|
|
|
- .pQueueFamilyIndices = &vk.device.graphicsFamily,
|
|
|
- .preTransform = caps.currentTransform,
|
|
|
- .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
|
|
- .presentMode = pm,
|
|
|
- .clipped = VK_TRUE,
|
|
|
- .oldSwapchain = VK_NULL_HANDLE};
|
|
|
- VK_ASSERT(vkCreateSwapchainKHR(
|
|
|
- vk.device.logical, &ci, nullptr, &vk.swapchain.handle));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static bool createImageView(VkImage image, VkImageView* view) {
|
|
|
- VkImageViewCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
|
- .image = image,
|
|
|
- .viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
|
- .format = VK_FORMAT_B8G8R8A8_UNORM,
|
|
|
- .subresourceRange = {
|
|
|
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
- .baseMipLevel = 0,
|
|
|
- .levelCount = 1,
|
|
|
- .baseArrayLayer = 0,
|
|
|
- .layerCount = 1}};
|
|
|
- VK_ASSERT(vkCreateImageView(vk.device.logical, &info, nullptr, view));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static void destroySwapchainImages() {
|
|
|
- for(size_t x = 0; x < vk.swapchain.amount; x++) {
|
|
|
- vkDestroyImageView(
|
|
|
- vk.device.logical, vk.swapchain.imageViews[x], nullptr);
|
|
|
- }
|
|
|
- coreFree(vk.swapchain.images);
|
|
|
- coreFree(vk.swapchain.imageViews);
|
|
|
-}
|
|
|
-
|
|
|
static bool initSwapchainImages() {
|
|
|
- u32 c = 0;
|
|
|
- VK_ASSERT(vkGetSwapchainImagesKHR(
|
|
|
- vk.device.logical, vk.swapchain.handle, &c, nullptr));
|
|
|
- LOG_INFO("Found %u images", c);
|
|
|
- vk.swapchain.amount = c;
|
|
|
- vk.swapchain.images = coreAllocate(sizeof(VkImage) * c);
|
|
|
- vk.swapchain.imageViews = coreZeroAllocate(sizeof(VkImageView) * c);
|
|
|
- VK_ASSERT(vkGetSwapchainImagesKHR(
|
|
|
- vk.device.logical, vk.swapchain.handle, &c, vk.swapchain.images));
|
|
|
- for(u32 x = 0; x < c; x++) {
|
|
|
- if(createImageView(
|
|
|
- vk.swapchain.images[x], vk.swapchain.imageViews + x)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static bool initSemaphore(VkSemaphore* s) {
|
|
|
- VkSemaphoreCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
|
|
- VK_ASSERT(vkCreateSemaphore(vk.device.logical, &info, nullptr, s));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static void destroySemaphore(VkSemaphore s) {
|
|
|
- vkDestroySemaphore(vk.device.logical, s, nullptr);
|
|
|
-}
|
|
|
-
|
|
|
-static bool checkPresentationSupport() {
|
|
|
- VkBool32 b = false;
|
|
|
- VK_ASSERT(vkGetPhysicalDeviceSurfaceSupportKHR(
|
|
|
- vk.device.physical, vk.device.graphicsFamily, vk.surface, &b));
|
|
|
- if(!b) {
|
|
|
- LOG_ERROR("Presentation is not supported");
|
|
|
+ if(initVulkanSwapchainImages(
|
|
|
+ &images, device, swapchain, surfaceFormat.format)) {
|
|
|
+ LOG_ERROR("Could not get swapchain images");
|
|
|
return true;
|
|
|
}
|
|
|
+ LOG_INFO("Found %u images", images.amount);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool initCommandBuffers() {
|
|
|
- VkCommandPoolCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
- .queueFamilyIndex = vk.device.graphicsFamily};
|
|
|
- VK_ASSERT(vkCreateCommandPool(
|
|
|
- vk.device.logical, &info, nullptr, &vk.swapchain.commandPool));
|
|
|
- vk.swapchain.commandsBuffers =
|
|
|
- coreAllocate(sizeof(VkCommandBuffer) * vk.swapchain.amount);
|
|
|
- VkCommandBufferAllocateInfo a = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
|
- .commandPool = vk.swapchain.commandPool,
|
|
|
- .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
|
- .commandBufferCount = vk.swapchain.amount};
|
|
|
- VK_ASSERT(vkAllocateCommandBuffers(
|
|
|
- vk.device.logical, &a, vk.swapchain.commandsBuffers));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static void destroyCommandBuffers() {
|
|
|
- if(vk.swapchain.commandPool != VK_NULL_HANDLE && vk.swapchain.amount > 0) {
|
|
|
- vkFreeCommandBuffers(
|
|
|
- vk.device.logical, vk.swapchain.commandPool, vk.swapchain.amount,
|
|
|
- vk.swapchain.commandsBuffers);
|
|
|
- }
|
|
|
- coreFree(vk.swapchain.commandsBuffers);
|
|
|
- vkDestroyCommandPool(vk.device.logical, vk.swapchain.commandPool, nullptr);
|
|
|
-}
|
|
|
-
|
|
|
-static bool initRenderPass() {
|
|
|
- VkAttachmentDescription c = {
|
|
|
- .format = vk.swapchain.format,
|
|
|
- .samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
- .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
|
- .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
- .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
|
- .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
|
- .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
- .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR};
|
|
|
- VkAttachmentReference ca = {
|
|
|
- .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
|
|
- VkSubpassDescription subpass = {
|
|
|
- .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
- .colorAttachmentCount = 1,
|
|
|
- .pColorAttachments = &ca};
|
|
|
- VkRenderPassCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
|
- .attachmentCount = 1,
|
|
|
- .pAttachments = &c,
|
|
|
- .subpassCount = 1,
|
|
|
- .pSubpasses = &subpass};
|
|
|
- VK_ASSERT(
|
|
|
- vkCreateRenderPass(vk.device.logical, &info, nullptr, &vk.renderPass));
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static bool initFramebuffers() {
|
|
|
- vk.swapchain.framebuffers =
|
|
|
- coreAllocate(sizeof(VkFramebuffer) * vk.swapchain.amount);
|
|
|
- for(u32 i = 0; i < vk.swapchain.amount; i++) {
|
|
|
- VkFramebufferCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
|
- .renderPass = vk.renderPass,
|
|
|
- .attachmentCount = 1,
|
|
|
- .pAttachments = vk.swapchain.imageViews + i,
|
|
|
- .width = vk.width,
|
|
|
- .height = vk.height,
|
|
|
- .layers = 1};
|
|
|
- VK_ASSERT(vkCreateFramebuffer(
|
|
|
- vk.device.logical, &info, nullptr, vk.swapchain.framebuffers + i));
|
|
|
- }
|
|
|
- printf("%u\n", vk.swapchain.amount);
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-static void destroyFramebuffers() {
|
|
|
- for(u32 i = 0; i < vk.swapchain.amount; i++) {
|
|
|
- vkDestroyFramebuffer(
|
|
|
- vk.device.logical, vk.swapchain.framebuffers[i], nullptr);
|
|
|
- }
|
|
|
- coreFree(vk.swapchain.framebuffers);
|
|
|
-}
|
|
|
-
|
|
|
bool initVulkan() {
|
|
|
- vk.width = 400;
|
|
|
- vk.height = 300;
|
|
|
- return initInstance() || initDebugging() || initSurface() ||
|
|
|
- initPhysicalDevice() || initDevice(&vk.device) ||
|
|
|
- checkPresentationSupport() || initSwapchain() ||
|
|
|
- initSwapchainImages() || initSemaphore(&vk.semaphore) ||
|
|
|
- initSemaphore(&vk.renderSemaphore) || initCommandBuffers() ||
|
|
|
- initRenderPass() || initFramebuffers();
|
|
|
-}
|
|
|
-
|
|
|
-static bool fillCommandBuffer(u32 index) {
|
|
|
- (void)index;
|
|
|
- // VkCommandBufferBeginInfo info = {
|
|
|
- // .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
|
- // .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT};
|
|
|
- // VK_ASSERT(vkBeginCommandBuffer(vk.swapchain.commandsBuffers[index],
|
|
|
- // &info)); VkClearValue v = {.color = {.int32 = {255, 0, 0, 0}}};
|
|
|
- // VkRenderPassBeginInfo rInfo = {
|
|
|
- // .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
|
- // .renderPass = vk.renderPass,
|
|
|
- // .framebuffer = vk.swapchain.framebuffers[index],
|
|
|
- // .renderArea = {.offset = {0, 0}, .extent = {vk.width, vk.height}},
|
|
|
- // .clearValueCount = 1,
|
|
|
- // .pClearValues = &v};
|
|
|
- // vkCmdBeginRenderPass(vk.swapchain.commandsBuffers[index], &rInfo,
|
|
|
- // VK_SUBPASS_CONTENTS_INLINE);
|
|
|
- return false;
|
|
|
+ return initVulkanInstance() || initVulkanDebugging() ||
|
|
|
+ initVulkanSurface(&surface, getWindow()) || initPhysicalDevice() ||
|
|
|
+ initDevice() || initSwapchain() || initSwapchainImages();
|
|
|
+ /* || initSemaphore(&vk.semaphore) ||
|
|
|
+ initSemaphore(&vk.renderSemaphore) || initCommandBuffers() ||
|
|
|
+ initRenderPass() || initFramebuffers()*/
|
|
|
}
|
|
|
|
|
|
void renderVulkan() {
|
|
|
- for(u32 i = 0; i < vk.swapchain.amount; i++) {
|
|
|
- fillCommandBuffer(i);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
void destroyVulkan(void) {
|
|
|
- if(vk.device.logical != VK_NULL_HANDLE) {
|
|
|
- destroyFramebuffers();
|
|
|
- vkDestroyRenderPass(vk.device.logical, vk.renderPass, nullptr);
|
|
|
- destroyCommandBuffers();
|
|
|
- destroySemaphore(vk.semaphore);
|
|
|
- destroySemaphore(vk.renderSemaphore);
|
|
|
- destroySwapchainImages();
|
|
|
- vkDestroySwapchainKHR(vk.device.logical, vk.swapchain.handle, nullptr);
|
|
|
- }
|
|
|
- vkDestroyDevice(vk.device.logical, nullptr);
|
|
|
- if(vk.instance != VK_NULL_HANDLE) {
|
|
|
- vkDestroySurfaceKHR(vk.instance, vk.surface, nullptr);
|
|
|
- destroyDebugMessenger();
|
|
|
- destroyDebugReportCallback();
|
|
|
- }
|
|
|
- vkDestroyInstance(vk.instance, nullptr);
|
|
|
+ // if(vk.device.logical != VK_NULL_HANDLE) {
|
|
|
+ // destroyFramebuffers();
|
|
|
+ // vkDestroyRenderPass(vk.device.logical, vk.renderPass, nullptr);
|
|
|
+ // destroyCommandBuffers();
|
|
|
+ // destroySemaphore(vk.semaphore);
|
|
|
+ // destroySemaphore(vk.renderSemaphore);
|
|
|
+ // }
|
|
|
+ destroyVulkanSwapchainImages(&images, device);
|
|
|
+ destroyVulkanSwapchain(swapchain, device);
|
|
|
+ destroyVulkanDevice(device);
|
|
|
+ destroyVulkanSurface(surface);
|
|
|
+ destroyVulkanDebugging();
|
|
|
+ destroyVulkanInstance();
|
|
|
}
|