|
@@ -1,488 +1,546 @@
|
|
|
#include "core/VulkanWrapper.hpp"
|
|
|
|
|
|
-#include <core/Array.hpp>
|
|
|
-#include <core/Logger.hpp>
|
|
|
-#include <core/Utility.hpp>
|
|
|
+#include <core/File.hpp>
|
|
|
+#include <core/UniquePointer.hpp>
|
|
|
|
|
|
#include "GLFW.hpp"
|
|
|
#include "VulkanUtils.hpp"
|
|
|
#include "core/VulkanBase.hpp"
|
|
|
-#include "core/VulkanUtility.hpp"
|
|
|
|
|
|
namespace Vulkan = Core::Vulkan;
|
|
|
|
|
|
-static Core::Vulkan::Base base;
|
|
|
-
|
|
|
-struct BaseData {
|
|
|
- u32 graphicsFamily = 0;
|
|
|
- u32 presentFamily = 0;
|
|
|
- VkSurfaceFormatKHR surfaceFormat{};
|
|
|
- VkPresentModeKHR presentMode{};
|
|
|
-};
|
|
|
-
|
|
|
-static BaseData baseData;
|
|
|
-static VkQueue graphicsQueue;
|
|
|
-static VkQueue presentQueue;
|
|
|
-static VkExtent2D swapchainSize;
|
|
|
-static VkSwapchainKHR swapchain;
|
|
|
-static VulkanSwapchainImages images;
|
|
|
-static VkShaderModule vertexShaderModule;
|
|
|
-static VkShaderModule fragmentShaderModule;
|
|
|
-static VkPipelineLayout pipelineLayout;
|
|
|
-static VkRenderPass renderPass;
|
|
|
-static VkViewport viewport;
|
|
|
-static VkRect2D scissor;
|
|
|
-static VkPipeline pipeline;
|
|
|
-static Core::List<VkFramebuffer> framebuffers;
|
|
|
-static VkCommandPool commandPool;
|
|
|
-static constexpr size_t MAX_FRAMES = 2;
|
|
|
-static size_t currentFrame = 0;
|
|
|
-
|
|
|
-typedef struct {
|
|
|
- VkCommandBuffer commandBuffer;
|
|
|
- VkSemaphore imageAvailableSemaphore;
|
|
|
- VkSemaphore renderFinishedSemaphore;
|
|
|
- VkFence inFlightFence;
|
|
|
-} Frame;
|
|
|
-
|
|
|
-static Frame frames[MAX_FRAMES];
|
|
|
-
|
|
|
-static int getSurfaceFormatPoints(const VkSurfaceFormatKHR& sf) {
|
|
|
- if(sf.format == VK_FORMAT_B8G8R8A8_UNORM &&
|
|
|
- sf.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
|
- return 10;
|
|
|
+#define WRAPPER_DESTRUCT(Type, ...) \
|
|
|
+ using Core::Vulkan::Type; \
|
|
|
+ Type::~Type() { \
|
|
|
+ if(device != VK_NULL_HANDLE) { \
|
|
|
+ vkDestroy##Type##__VA_ARGS__(device, handle, nullptr); \
|
|
|
+ } \
|
|
|
}
|
|
|
- return 1;
|
|
|
+
|
|
|
+WRAPPER_DESTRUCT(ImageView)
|
|
|
+WRAPPER_DESTRUCT(Framebuffer)
|
|
|
+WRAPPER_DESTRUCT(Semaphore)
|
|
|
+WRAPPER_DESTRUCT(Fence)
|
|
|
+WRAPPER_DESTRUCT(Swapchain, KHR)
|
|
|
+WRAPPER_DESTRUCT(ShaderModule)
|
|
|
+WRAPPER_DESTRUCT(PipelineLayout)
|
|
|
+
|
|
|
+bool Semaphore::init(VkDevice d) {
|
|
|
+ VkSemaphoreCreateInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
|
|
+ VK_CHECK_TRUE(vkCreateSemaphore(d, &info, nullptr, &handle));
|
|
|
+ device = d;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-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;
|
|
|
+bool Fence::init(VkDevice d) {
|
|
|
+ VkFenceCreateInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
|
|
+ .flags = VK_FENCE_CREATE_SIGNALED_BIT};
|
|
|
+ VK_CHECK_TRUE(vkCreateFence(d, &info, nullptr, &handle));
|
|
|
+ device = d;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-static bool getSwapchainSize(VkExtent2D* size) {
|
|
|
- VkSurfaceCapabilitiesKHR c = {0};
|
|
|
- if(base.getSurfaceCapabilities(c)) {
|
|
|
+bool ShaderModule::init(VkDevice d, const char* path) {
|
|
|
+ List<char> f;
|
|
|
+ if(Core::readFile(f, path)) {
|
|
|
return true;
|
|
|
}
|
|
|
- if(c.currentExtent.width != 0xFFFF'FFFFu &&
|
|
|
- c.currentExtent.height != 0xFFFF'FFFFu) {
|
|
|
- *size = c.currentExtent;
|
|
|
- LOG_INFO("Swapchain size: #x#", size->width, size->height);
|
|
|
- return false;
|
|
|
- }
|
|
|
- int w = 0;
|
|
|
- int h = 0;
|
|
|
- glfwGetFramebufferSize(Core::Window::get(), &w, &h);
|
|
|
- if(w <= 0 || h <= 0) {
|
|
|
- LOG_ERROR("Could not get framebuffer size");
|
|
|
+ size_t l = f.getLength() - 1;
|
|
|
+ if((l % 4) != 0) {
|
|
|
+ VK_REPORT_ERROR("Shader size is not a multiple of 4");
|
|
|
return true;
|
|
|
}
|
|
|
- LOG_INFO("Framebuffer size: #x#", w, h);
|
|
|
- size->width = Core::clamp(
|
|
|
- static_cast<u32>(w), c.minImageExtent.width, c.maxImageExtent.width);
|
|
|
- size->height = Core::clamp(
|
|
|
- static_cast<u32>(h), c.minImageExtent.height, c.maxImageExtent.height);
|
|
|
- LOG_INFO("Swapchain size: #x#", size->width, size->height);
|
|
|
+ VkShaderModuleCreateInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
|
+ .codeSize = l,
|
|
|
+ .pCode = reinterpret_cast<u32*>(static_cast<void*>(&f[0]))};
|
|
|
+ VK_CHECK_TRUE(vkCreateShaderModule(d, &info, nullptr, &handle));
|
|
|
+ device = d;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool initSwapchain() {
|
|
|
- VulkanSwapchainData d = {
|
|
|
- .base = base,
|
|
|
- .surfaceFormat = baseData.surfaceFormat,
|
|
|
- .presentMode = baseData.presentMode};
|
|
|
- if(getSwapchainSize(&d.size)) {
|
|
|
- LOG_ERROR("Could not retrieve any swapchain size");
|
|
|
- return true;
|
|
|
- }
|
|
|
- swapchainSize = d.size;
|
|
|
- d.queueFamilies.add(baseData.graphicsFamily);
|
|
|
- if(baseData.graphicsFamily != baseData.presentFamily) {
|
|
|
- d.queueFamilies.add(baseData.presentFamily);
|
|
|
- d.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
|
- } else {
|
|
|
- d.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
- }
|
|
|
- return initVulkanSwapchain(&swapchain, &d);
|
|
|
+bool PipelineLayout::init(VkDevice d) {
|
|
|
+ VkPipelineLayoutCreateInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
|
+ VK_CHECK_TRUE(vkCreatePipelineLayout(d, &info, nullptr, &handle));
|
|
|
+ device = d;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
-static bool initDevice() {
|
|
|
- bool same = baseData.graphicsFamily == baseData.presentFamily;
|
|
|
- Core::List<Vulkan::DeviceQueueData> data;
|
|
|
- data.add(baseData.graphicsFamily, 1.0f);
|
|
|
- if(!same) {
|
|
|
- data.add(baseData.presentFamily, 1.0f);
|
|
|
+struct VulkanDummy {
|
|
|
+ Core::Vulkan::Base base{};
|
|
|
+
|
|
|
+ struct BaseData {
|
|
|
+ u32 graphicsFamily = 0;
|
|
|
+ u32 presentFamily = 0;
|
|
|
+ VkSurfaceFormatKHR surfaceFormat{};
|
|
|
+ VkPresentModeKHR presentMode{};
|
|
|
};
|
|
|
- Core::List<const char*> extensions;
|
|
|
- extensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
|
- if(base.initDevice(data, extensions)) {
|
|
|
- return true;
|
|
|
+
|
|
|
+ BaseData baseData{};
|
|
|
+ VkQueue graphicsQueue{};
|
|
|
+ VkQueue presentQueue{};
|
|
|
+ VkExtent2D swapchainSize{};
|
|
|
+ Swapchain swapchain{};
|
|
|
+ VulkanSwapchainImages images{};
|
|
|
+ ShaderModule vertexShaderModule{};
|
|
|
+ ShaderModule fragmentShaderModule{};
|
|
|
+ PipelineLayout pipelineLayout{};
|
|
|
+ VkRenderPass renderPass{};
|
|
|
+ VkViewport viewport{};
|
|
|
+ VkRect2D scissor{};
|
|
|
+ VkPipeline pipeline{};
|
|
|
+ Core::List<Vulkan::Framebuffer> framebuffers{};
|
|
|
+ VkCommandPool commandPool{};
|
|
|
+ static constexpr size_t MAX_FRAMES = 2;
|
|
|
+ size_t currentFrame = 0;
|
|
|
+ bool shouldWait = false;
|
|
|
+
|
|
|
+ struct Frame {
|
|
|
+ VkCommandBuffer commandBuffer{};
|
|
|
+ Semaphore imageAvailableSemaphore{};
|
|
|
+ Semaphore renderFinishedSemaphore{};
|
|
|
+ Fence inFlightFence{};
|
|
|
+ };
|
|
|
+
|
|
|
+ Frame frames[MAX_FRAMES];
|
|
|
+
|
|
|
+ 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;
|
|
|
}
|
|
|
- vkGetDeviceQueue(base, baseData.graphicsFamily, 0, &graphicsQueue);
|
|
|
- if(graphicsQueue == VK_NULL_HANDLE) {
|
|
|
- LOG_ERROR("Cannot get device graphics queue");
|
|
|
- return true;
|
|
|
+
|
|
|
+ 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;
|
|
|
}
|
|
|
- if(same) {
|
|
|
- presentQueue = graphicsQueue;
|
|
|
+
|
|
|
+ bool getSwapchainSize(VkExtent2D* size) {
|
|
|
+ VkSurfaceCapabilitiesKHR c = {0};
|
|
|
+ if(base.getSurfaceCapabilities(c)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if(c.currentExtent.width != 0xFFFF'FFFFu &&
|
|
|
+ c.currentExtent.height != 0xFFFF'FFFFu) {
|
|
|
+ *size = c.currentExtent;
|
|
|
+ LOG_INFO("Swapchain size: #x#", size->width, size->height);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ int w = 0;
|
|
|
+ int h = 0;
|
|
|
+ glfwGetFramebufferSize(Core::Window::get(), &w, &h);
|
|
|
+ if(w <= 0 || h <= 0) {
|
|
|
+ LOG_ERROR("Could not get framebuffer size");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ LOG_INFO("Framebuffer size: #x#", w, h);
|
|
|
+ size->width = Core::clamp(
|
|
|
+ static_cast<u32>(w), c.minImageExtent.width,
|
|
|
+ c.maxImageExtent.width);
|
|
|
+ size->height = Core::clamp(
|
|
|
+ static_cast<u32>(h), c.minImageExtent.height,
|
|
|
+ c.maxImageExtent.height);
|
|
|
+ LOG_INFO("Swapchain size: #x#", size->width, size->height);
|
|
|
return false;
|
|
|
}
|
|
|
- vkGetDeviceQueue(base, baseData.presentFamily, 0, &presentQueue);
|
|
|
- if(presentQueue == VK_NULL_HANDLE) {
|
|
|
- LOG_ERROR("Cannot get device present queue");
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
|
|
|
-static int getDevicePoints(Vulkan::Base& b, BaseData& d) {
|
|
|
- int points = 0;
|
|
|
- VkPhysicalDeviceProperties p;
|
|
|
- b.getPhysicalDeviceProperties(p);
|
|
|
- LOG_INFO("Checking '#'", p.deviceName);
|
|
|
- switch(p.deviceType) {
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: points += 100; break;
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: points += 50; break;
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: points += 20; break;
|
|
|
- default: break;
|
|
|
- }
|
|
|
- d.graphicsFamily = b.findQueueFamily(VK_QUEUE_GRAPHICS_BIT);
|
|
|
- if(d.graphicsFamily == Vulkan::INVALID_QUEUE_FAMILY) {
|
|
|
- LOG_INFO("> ... has no graphics family");
|
|
|
- points = -1;
|
|
|
+ bool initSwapchain() {
|
|
|
+ VulkanSwapchainData d = {
|
|
|
+ .base = base,
|
|
|
+ .surfaceFormat = baseData.surfaceFormat,
|
|
|
+ .presentMode = baseData.presentMode};
|
|
|
+ if(getSwapchainSize(&d.size)) {
|
|
|
+ LOG_ERROR("Could not retrieve any swapchain size");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ swapchainSize = d.size;
|
|
|
+ d.queueFamilies.add(baseData.graphicsFamily);
|
|
|
+ if(baseData.graphicsFamily != baseData.presentFamily) {
|
|
|
+ d.queueFamilies.add(baseData.presentFamily);
|
|
|
+ d.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
|
+ } else {
|
|
|
+ d.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
+ }
|
|
|
+ return initVulkanSwapchain(swapchain, &d);
|
|
|
}
|
|
|
- d.presentFamily = b.findSurfaceQueueFamily();
|
|
|
- if(d.presentFamily == Vulkan::INVALID_QUEUE_FAMILY) {
|
|
|
- LOG_INFO("> ... has no present family");
|
|
|
- points = -1;
|
|
|
+
|
|
|
+ bool initDevice() {
|
|
|
+ bool same = baseData.graphicsFamily == baseData.presentFamily;
|
|
|
+ Core::List<Vulkan::DeviceQueueData> data;
|
|
|
+ data.add(baseData.graphicsFamily, 1.0f);
|
|
|
+ if(!same) {
|
|
|
+ data.add(baseData.presentFamily, 1.0f);
|
|
|
+ };
|
|
|
+ Core::List<const char*> extensions;
|
|
|
+ extensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
|
+ if(base.initDevice(data, extensions)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ vkGetDeviceQueue(base, baseData.graphicsFamily, 0, &graphicsQueue);
|
|
|
+ if(graphicsQueue == VK_NULL_HANDLE) {
|
|
|
+ LOG_ERROR("Cannot get device graphics queue");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if(same) {
|
|
|
+ presentQueue = graphicsQueue;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ vkGetDeviceQueue(base, baseData.presentFamily, 0, &presentQueue);
|
|
|
+ if(presentQueue == VK_NULL_HANDLE) {
|
|
|
+ LOG_ERROR("Cannot get device present queue");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
- if(!b.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
|
|
|
- LOG_INFO("> ... has no swapchain support");
|
|
|
- points = -1;
|
|
|
+
|
|
|
+ static int getDevicePoints(Vulkan::Base& b, BaseData& d) {
|
|
|
+ int points = 0;
|
|
|
+ VkPhysicalDeviceProperties p;
|
|
|
+ b.getPhysicalDeviceProperties(p);
|
|
|
+ LOG_INFO("Checking '#'", p.deviceName);
|
|
|
+ switch(p.deviceType) {
|
|
|
+ case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: points += 100; break;
|
|
|
+ case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: points += 50; break;
|
|
|
+ case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: points += 20; break;
|
|
|
+ default: break;
|
|
|
+ }
|
|
|
+ d.graphicsFamily = b.findQueueFamily(VK_QUEUE_GRAPHICS_BIT);
|
|
|
+ if(d.graphicsFamily == Vulkan::INVALID_QUEUE_FAMILY) {
|
|
|
+ LOG_INFO("> ... has no graphics family");
|
|
|
+ points = -1;
|
|
|
+ }
|
|
|
+ d.presentFamily = b.findSurfaceQueueFamily();
|
|
|
+ if(d.presentFamily == Vulkan::INVALID_QUEUE_FAMILY) {
|
|
|
+ LOG_INFO("> ... has no present family");
|
|
|
+ points = -1;
|
|
|
+ }
|
|
|
+ if(!b.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
|
|
|
+ LOG_INFO("> ... has no swapchain support");
|
|
|
+ points = -1;
|
|
|
+ }
|
|
|
+ if(b.findSurfaceFormat(d.surfaceFormat, getSurfaceFormatPoints)) {
|
|
|
+ LOG_INFO("> ... has no matching surface format");
|
|
|
+ points = -1;
|
|
|
+ } else {
|
|
|
+ points += getSurfaceFormatPoints(d.surfaceFormat);
|
|
|
+ }
|
|
|
+ if(b.findSurfacePresentMode(
|
|
|
+ d.presentMode, getSurfacePresentModePoints)) {
|
|
|
+ LOG_INFO("> ... has no matching present mode");
|
|
|
+ points = -1;
|
|
|
+ } else {
|
|
|
+ points += getSurfacePresentModePoints(d.presentMode);
|
|
|
+ }
|
|
|
+ LOG_INFO("> Final points: #", points);
|
|
|
+ return points;
|
|
|
}
|
|
|
- if(b.findSurfaceFormat(d.surfaceFormat, getSurfaceFormatPoints)) {
|
|
|
- LOG_INFO("> ... has no matching surface format");
|
|
|
- points = -1;
|
|
|
- } else {
|
|
|
- points += getSurfaceFormatPoints(d.surfaceFormat);
|
|
|
+
|
|
|
+ bool initPhysicalDevice() {
|
|
|
+ LOG_INFO("Searching for physical devices ...");
|
|
|
+ if(base.findPhysicalDevice(baseData, getDevicePoints)) {
|
|
|
+ LOG_ERROR("No matching physical device was found");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ VkPhysicalDeviceProperties p;
|
|
|
+ base.getPhysicalDeviceProperties(p);
|
|
|
+ LOG_INFO("Best Device: #", p.deviceName);
|
|
|
+ return false;
|
|
|
}
|
|
|
- if(b.findSurfacePresentMode(d.presentMode, getSurfacePresentModePoints)) {
|
|
|
- LOG_INFO("> ... has no matching present mode");
|
|
|
- points = -1;
|
|
|
- } else {
|
|
|
- points += getSurfacePresentModePoints(d.presentMode);
|
|
|
+
|
|
|
+ bool initSwapchainImages() {
|
|
|
+ if(initVulkanSwapchainImages(
|
|
|
+ images, base, swapchain, baseData.surfaceFormat.format)) {
|
|
|
+ LOG_ERROR("Could not get swapchain images");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ LOG_INFO("Found # images", images.images.getLength());
|
|
|
+ return false;
|
|
|
}
|
|
|
- LOG_INFO("> Final points: #", points);
|
|
|
- return points;
|
|
|
-}
|
|
|
|
|
|
-static bool initPhysicalDevice() {
|
|
|
- LOG_INFO("Searching for physical devices ...");
|
|
|
- if(base.findPhysicalDevice(baseData, getDevicePoints)) {
|
|
|
- LOG_ERROR("No matching physical device was found");
|
|
|
- return true;
|
|
|
+ bool initShaders() {
|
|
|
+ return vertexShaderModule.init(base, "shaders/vertex.spv") ||
|
|
|
+ fragmentShaderModule.init(base, "shaders/fragment.spv");
|
|
|
}
|
|
|
- VkPhysicalDeviceProperties p;
|
|
|
- base.getPhysicalDeviceProperties(p);
|
|
|
- LOG_INFO("Best Device: #", p.deviceName);
|
|
|
- return false;
|
|
|
-}
|
|
|
|
|
|
-static bool initSwapchainImages() {
|
|
|
- if(initVulkanSwapchainImages(
|
|
|
- images, base, swapchain, baseData.surfaceFormat.format)) {
|
|
|
- LOG_ERROR("Could not get swapchain images");
|
|
|
- return true;
|
|
|
+ bool initPipeline() {
|
|
|
+ VkPipelineShaderStageCreateInfo stages[2] = {
|
|
|
+ {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
+ .stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
+ .module = vertexShaderModule,
|
|
|
+ .pName = "main"},
|
|
|
+ {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
+ .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
+ .module = fragmentShaderModule,
|
|
|
+ .pName = "main"}};
|
|
|
+
|
|
|
+ VkPipelineVertexInputStateCreateInfo vertexInputState = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
|
|
|
+
|
|
|
+ VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
|
|
|
+ .sType =
|
|
|
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
|
+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
|
+ .primitiveRestartEnable = false};
|
|
|
+
|
|
|
+ viewport = {
|
|
|
+ .x = 0.0f,
|
|
|
+ .y = 0.0f,
|
|
|
+ .width = static_cast<float>(swapchainSize.width),
|
|
|
+ .height = static_cast<float>(swapchainSize.height),
|
|
|
+ .minDepth = 0.0f,
|
|
|
+ .maxDepth = 1.0f};
|
|
|
+ scissor = {.offset = {0, 0}, .extent = swapchainSize};
|
|
|
+ VkPipelineViewportStateCreateInfo viewportState = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
|
+ .viewportCount = 1,
|
|
|
+ .pViewports = &viewport,
|
|
|
+ .scissorCount = 1,
|
|
|
+ .pScissors = &scissor};
|
|
|
+
|
|
|
+ VkPipelineRasterizationStateCreateInfo rasterizationState = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
|
+ .depthClampEnable = false,
|
|
|
+ .rasterizerDiscardEnable = false,
|
|
|
+ .polygonMode = VK_POLYGON_MODE_FILL,
|
|
|
+ .cullMode = VK_CULL_MODE_BACK_BIT,
|
|
|
+ .frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
|
+ .depthBiasEnable = false,
|
|
|
+ .depthBiasConstantFactor = 0.0f,
|
|
|
+ .depthBiasClamp = 0.0f,
|
|
|
+ .depthBiasSlopeFactor = 0.0f,
|
|
|
+ .lineWidth = 1.0f};
|
|
|
+
|
|
|
+ VkPipelineMultisampleStateCreateInfo multisampleState = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
|
+ .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
+ .sampleShadingEnable = false,
|
|
|
+ .minSampleShading = 1.0f,
|
|
|
+ .pSampleMask = nullptr,
|
|
|
+ .alphaToCoverageEnable = false,
|
|
|
+ .alphaToOneEnable = false};
|
|
|
+
|
|
|
+ VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
|
|
+ .blendEnable = false,
|
|
|
+ .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
|
+ .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
|
+ .colorBlendOp = VK_BLEND_OP_ADD,
|
|
|
+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
|
+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
|
+ .alphaBlendOp = VK_BLEND_OP_ADD,
|
|
|
+ .colorWriteMask =
|
|
|
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
|
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
|
|
|
+
|
|
|
+ VkPipelineColorBlendStateCreateInfo colorBlendState = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
|
+ .logicOpEnable = false,
|
|
|
+ .logicOp = VK_LOGIC_OP_COPY,
|
|
|
+ .attachmentCount = 1,
|
|
|
+ .pAttachments = &colorBlendAttachmentState,
|
|
|
+ .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}};
|
|
|
+
|
|
|
+ Core::Array<VkDynamicState, 2> dynamicStates = {
|
|
|
+ {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}};
|
|
|
+
|
|
|
+ VkPipelineDynamicStateCreateInfo dynamicState = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
|
+ .dynamicStateCount = dynamicStates.getLength(),
|
|
|
+ .pDynamicStates = dynamicStates.begin()};
|
|
|
+
|
|
|
+ VkGraphicsPipelineCreateInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
|
+ .stageCount = 2,
|
|
|
+ .pStages = stages,
|
|
|
+ .pVertexInputState = &vertexInputState,
|
|
|
+ .pInputAssemblyState = &inputAssemblyState,
|
|
|
+ .pTessellationState = nullptr,
|
|
|
+ .pViewportState = &viewportState,
|
|
|
+ .pRasterizationState = &rasterizationState,
|
|
|
+ .pMultisampleState = &multisampleState,
|
|
|
+ .pDepthStencilState = nullptr,
|
|
|
+ .pColorBlendState = &colorBlendState,
|
|
|
+ .pDynamicState = &dynamicState,
|
|
|
+ .layout = pipelineLayout,
|
|
|
+ .renderPass = renderPass,
|
|
|
+ .subpass = 0,
|
|
|
+ .basePipelineHandle = VK_NULL_HANDLE,
|
|
|
+ .basePipelineIndex = -1};
|
|
|
+
|
|
|
+ VK_CHECK_TRUE(vkCreateGraphicsPipelines(
|
|
|
+ base, VK_NULL_HANDLE, 1, &info, nullptr, &pipeline));
|
|
|
+ return false;
|
|
|
}
|
|
|
- LOG_INFO("Found # images", images.images.getLength());
|
|
|
- return false;
|
|
|
-}
|
|
|
|
|
|
-static bool initShaders() {
|
|
|
- return initVulkanShaderModule(
|
|
|
- &vertexShaderModule, base, "shaders/vertex.spv") ||
|
|
|
- initVulkanShaderModule(
|
|
|
- &fragmentShaderModule, base, "shaders/fragment.spv");
|
|
|
-}
|
|
|
+ bool initRenderPass() {
|
|
|
+ VkAttachmentDescription c = {
|
|
|
+ .format = baseData.surfaceFormat.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};
|
|
|
+ VkSubpassDependency dependency = {
|
|
|
+ .srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
|
+ .dstSubpass = 0,
|
|
|
+ .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
+ .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
+ .srcAccessMask = 0,
|
|
|
+ .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
+ };
|
|
|
+ VkRenderPassCreateInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
|
+ .attachmentCount = 1,
|
|
|
+ .pAttachments = &c,
|
|
|
+ .subpassCount = 1,
|
|
|
+ .pSubpasses = &subpass,
|
|
|
+ .dependencyCount = 1,
|
|
|
+ .pDependencies = &dependency};
|
|
|
+ VK_CHECK_TRUE(vkCreateRenderPass(base, &info, nullptr, &renderPass));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
-static bool initPipeline() {
|
|
|
- VkPipelineShaderStageCreateInfo stages[2] = {
|
|
|
- {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
- .stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
- .module = vertexShaderModule,
|
|
|
- .pName = "main"},
|
|
|
- {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
- .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
- .module = fragmentShaderModule,
|
|
|
- .pName = "main"}};
|
|
|
-
|
|
|
- VkPipelineVertexInputStateCreateInfo vertexInputState = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
|
|
|
-
|
|
|
- VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
|
- .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
|
- .primitiveRestartEnable = false};
|
|
|
-
|
|
|
- viewport = {
|
|
|
- .x = 0.0f,
|
|
|
- .y = 0.0f,
|
|
|
- .width = static_cast<float>(swapchainSize.width),
|
|
|
- .height = static_cast<float>(swapchainSize.height),
|
|
|
- .minDepth = 0.0f,
|
|
|
- .maxDepth = 1.0f};
|
|
|
- scissor = {.offset = {0, 0}, .extent = swapchainSize};
|
|
|
- VkPipelineViewportStateCreateInfo viewportState = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
|
- .viewportCount = 1,
|
|
|
- .pViewports = &viewport,
|
|
|
- .scissorCount = 1,
|
|
|
- .pScissors = &scissor};
|
|
|
-
|
|
|
- VkPipelineRasterizationStateCreateInfo rasterizationState = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
|
- .depthClampEnable = false,
|
|
|
- .rasterizerDiscardEnable = false,
|
|
|
- .polygonMode = VK_POLYGON_MODE_FILL,
|
|
|
- .cullMode = VK_CULL_MODE_BACK_BIT,
|
|
|
- .frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
|
- .depthBiasEnable = false,
|
|
|
- .depthBiasConstantFactor = 0.0f,
|
|
|
- .depthBiasClamp = 0.0f,
|
|
|
- .depthBiasSlopeFactor = 0.0f,
|
|
|
- .lineWidth = 1.0f};
|
|
|
-
|
|
|
- VkPipelineMultisampleStateCreateInfo multisampleState = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
|
- .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
- .sampleShadingEnable = false,
|
|
|
- .minSampleShading = 1.0f,
|
|
|
- .pSampleMask = nullptr,
|
|
|
- .alphaToCoverageEnable = false,
|
|
|
- .alphaToOneEnable = false};
|
|
|
-
|
|
|
- VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
|
|
- .blendEnable = false,
|
|
|
- .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
|
- .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
|
- .colorBlendOp = VK_BLEND_OP_ADD,
|
|
|
- .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
|
- .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
|
- .alphaBlendOp = VK_BLEND_OP_ADD,
|
|
|
- .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
|
- VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
|
|
|
-
|
|
|
- VkPipelineColorBlendStateCreateInfo colorBlendState = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
|
- .logicOpEnable = false,
|
|
|
- .logicOp = VK_LOGIC_OP_COPY,
|
|
|
- .attachmentCount = 1,
|
|
|
- .pAttachments = &colorBlendAttachmentState,
|
|
|
- .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}};
|
|
|
-
|
|
|
- Core::Array<VkDynamicState, 2> dynamicStates = {
|
|
|
- {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}};
|
|
|
-
|
|
|
- VkPipelineDynamicStateCreateInfo dynamicState = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
|
- .dynamicStateCount = dynamicStates.getLength(),
|
|
|
- .pDynamicStates = dynamicStates.begin()};
|
|
|
-
|
|
|
- VkGraphicsPipelineCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
|
- .stageCount = 2,
|
|
|
- .pStages = stages,
|
|
|
- .pVertexInputState = &vertexInputState,
|
|
|
- .pInputAssemblyState = &inputAssemblyState,
|
|
|
- .pTessellationState = nullptr,
|
|
|
- .pViewportState = &viewportState,
|
|
|
- .pRasterizationState = &rasterizationState,
|
|
|
- .pMultisampleState = &multisampleState,
|
|
|
- .pDepthStencilState = nullptr,
|
|
|
- .pColorBlendState = &colorBlendState,
|
|
|
- .pDynamicState = &dynamicState,
|
|
|
- .layout = pipelineLayout,
|
|
|
- .renderPass = renderPass,
|
|
|
- .subpass = 0,
|
|
|
- .basePipelineHandle = VK_NULL_HANDLE,
|
|
|
- .basePipelineIndex = -1};
|
|
|
-
|
|
|
- VK_CHECK_TRUE(vkCreateGraphicsPipelines(
|
|
|
- base, VK_NULL_HANDLE, 1, &info, nullptr, &pipeline));
|
|
|
- return false;
|
|
|
-}
|
|
|
+ bool initCommandPool() {
|
|
|
+ VkCommandPoolCreateInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
+ .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
|
|
+ .queueFamilyIndex = baseData.graphicsFamily};
|
|
|
+ VK_CHECK_TRUE(vkCreateCommandPool(base, &info, nullptr, &commandPool));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
-static bool initRenderPass() {
|
|
|
- VkAttachmentDescription c = {
|
|
|
- .format = baseData.surfaceFormat.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};
|
|
|
- VkSubpassDependency dependency = {
|
|
|
- .srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
|
- .dstSubpass = 0,
|
|
|
- .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
- .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
- .srcAccessMask = 0,
|
|
|
- .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
- };
|
|
|
- VkRenderPassCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
|
- .attachmentCount = 1,
|
|
|
- .pAttachments = &c,
|
|
|
- .subpassCount = 1,
|
|
|
- .pSubpasses = &subpass,
|
|
|
- .dependencyCount = 1,
|
|
|
- .pDependencies = &dependency};
|
|
|
- VK_CHECK_TRUE(vkCreateRenderPass(base, &info, nullptr, &renderPass));
|
|
|
- return false;
|
|
|
-}
|
|
|
+ bool fillCommandBuffer(VkCommandBuffer cb, u32 index) {
|
|
|
+ VkCommandBufferBeginInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
|
+ VK_CHECK_TRUE(vkBeginCommandBuffer(cb, &info));
|
|
|
+ VkClearValue v = {.color = {.float32 = {0.0f, 0.5f, 0.0f, 1.0f}}};
|
|
|
+ VkRenderPassBeginInfo rInfo = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
|
+ .renderPass = renderPass,
|
|
|
+ .framebuffer = framebuffers[index],
|
|
|
+ .renderArea = {.offset = {0, 0}, .extent = swapchainSize},
|
|
|
+ .clearValueCount = 1,
|
|
|
+ .pClearValues = &v};
|
|
|
+ vkCmdBeginRenderPass(cb, &rInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
+ vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
|
+ vkCmdSetViewport(cb, 0, 1, &viewport);
|
|
|
+ vkCmdSetScissor(cb, 0, 1, &scissor);
|
|
|
+ vkCmdDraw(cb, 3, 1, 0, 0);
|
|
|
+ vkCmdEndRenderPass(cb);
|
|
|
+ VK_CHECK_TRUE(vkEndCommandBuffer(cb));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
-static bool initCommandPool() {
|
|
|
- VkCommandPoolCreateInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
- .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
|
|
- .queueFamilyIndex = baseData.graphicsFamily};
|
|
|
- VK_CHECK_TRUE(vkCreateCommandPool(base, &info, nullptr, &commandPool));
|
|
|
- return false;
|
|
|
-}
|
|
|
+ bool initFrames() {
|
|
|
+ for(size_t i = 0; i < MAX_FRAMES; i++) {
|
|
|
+ if(initCommandVulkanBuffer(
|
|
|
+ &frames[i].commandBuffer, base, commandPool) ||
|
|
|
+ frames[i].imageAvailableSemaphore.init(base) ||
|
|
|
+ frames[i].renderFinishedSemaphore.init(base) ||
|
|
|
+ frames[i].inFlightFence.init(base)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
-static bool fillCommandBuffer(VkCommandBuffer cb, u32 index) {
|
|
|
- VkCommandBufferBeginInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
|
- VK_CHECK_TRUE(vkBeginCommandBuffer(cb, &info));
|
|
|
- VkClearValue v = {.color = {.float32 = {0.0f, 0.5f, 0.0f, 1.0f}}};
|
|
|
- VkRenderPassBeginInfo rInfo = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
|
- .renderPass = renderPass,
|
|
|
- .framebuffer = framebuffers[index],
|
|
|
- .renderArea = {.offset = {0, 0}, .extent = swapchainSize},
|
|
|
- .clearValueCount = 1,
|
|
|
- .pClearValues = &v};
|
|
|
- vkCmdBeginRenderPass(cb, &rInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
- vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
|
- vkCmdSetViewport(cb, 0, 1, &viewport);
|
|
|
- vkCmdSetScissor(cb, 0, 1, &scissor);
|
|
|
- vkCmdDraw(cb, 3, 1, 0, 0);
|
|
|
- vkCmdEndRenderPass(cb);
|
|
|
- VK_CHECK_TRUE(vkEndCommandBuffer(cb));
|
|
|
- return false;
|
|
|
-}
|
|
|
+ bool init() {
|
|
|
+ return base.init() || initPhysicalDevice() || initDevice() ||
|
|
|
+ initSwapchain() || initSwapchainImages() || initShaders() ||
|
|
|
+ pipelineLayout.init(base) || initRenderPass() ||
|
|
|
+ initPipeline() ||
|
|
|
+ initVulkanFramebuffers(
|
|
|
+ framebuffers, images.imageViews, renderPass,
|
|
|
+ swapchainSize.width, swapchainSize.height) ||
|
|
|
+ initCommandPool() || initFrames();
|
|
|
+ }
|
|
|
|
|
|
-static bool initFrames() {
|
|
|
- for(size_t i = 0; i < MAX_FRAMES; i++) {
|
|
|
- if(initCommandVulkanBuffer(
|
|
|
- &frames[i].commandBuffer, base, commandPool) ||
|
|
|
- initVulkanSemaphore(&frames[i].imageAvailableSemaphore, base) ||
|
|
|
- initVulkanSemaphore(&frames[i].renderFinishedSemaphore, base) ||
|
|
|
- initVulkanFence(&frames[i].inFlightFence, base)) {
|
|
|
- return true;
|
|
|
+ bool render() {
|
|
|
+ if(shouldWait) {
|
|
|
+ return false;
|
|
|
}
|
|
|
+ Frame* f = frames + currentFrame;
|
|
|
+ VK_CHECK_TRUE(
|
|
|
+ vkWaitForFences(base, 1, f->inFlightFence, true, UINT64_MAX));
|
|
|
+ VK_CHECK_TRUE(vkResetFences(base, 1, f->inFlightFence));
|
|
|
+
|
|
|
+ uint32_t imageIndex = 0;
|
|
|
+ VK_CHECK_TRUE(vkAcquireNextImageKHR(
|
|
|
+ base, swapchain, UINT64_MAX, f->imageAvailableSemaphore,
|
|
|
+ VK_NULL_HANDLE, &imageIndex));
|
|
|
+
|
|
|
+ vkResetCommandBuffer(f->commandBuffer, 0);
|
|
|
+ fillCommandBuffer(f->commandBuffer, imageIndex);
|
|
|
+
|
|
|
+ VkSemaphore waitSemaphores[] = {f->imageAvailableSemaphore};
|
|
|
+ VkPipelineStageFlags waitStages[] = {
|
|
|
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
|
|
+ VkSemaphore signalSemaphores[] = {f->renderFinishedSemaphore};
|
|
|
+ VkSubmitInfo info = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
+ .waitSemaphoreCount = 1,
|
|
|
+ .pWaitSemaphores = waitSemaphores,
|
|
|
+ .pWaitDstStageMask = waitStages,
|
|
|
+ .commandBufferCount = 1,
|
|
|
+ .pCommandBuffers = &f->commandBuffer,
|
|
|
+ .signalSemaphoreCount = 1,
|
|
|
+ .pSignalSemaphores = signalSemaphores};
|
|
|
+ VK_CHECK_TRUE(vkQueueSubmit(graphicsQueue, 1, &info, f->inFlightFence));
|
|
|
+
|
|
|
+ VkPresentInfoKHR presentInfo = {
|
|
|
+ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
|
|
+ .waitSemaphoreCount = 1,
|
|
|
+ .pWaitSemaphores = signalSemaphores,
|
|
|
+ .swapchainCount = 1,
|
|
|
+ .pSwapchains = swapchain,
|
|
|
+ .pImageIndices = &imageIndex};
|
|
|
+
|
|
|
+ VK_CHECK_TRUE(vkQueuePresentKHR(presentQueue, &presentInfo));
|
|
|
+ currentFrame = (currentFrame + 1) % MAX_FRAMES;
|
|
|
+ return false;
|
|
|
}
|
|
|
- return false;
|
|
|
-}
|
|
|
|
|
|
-bool Vulkan::init() {
|
|
|
- return base.init() || initPhysicalDevice() || initDevice() ||
|
|
|
- initSwapchain() || initSwapchainImages() || initShaders() ||
|
|
|
- initVulkanPipelineLayout(&pipelineLayout, base) ||
|
|
|
- initRenderPass() || initPipeline() ||
|
|
|
- initVulkanFramebuffers(
|
|
|
- framebuffers, images, base, renderPass, swapchainSize.width,
|
|
|
- swapchainSize.height) ||
|
|
|
- initCommandPool() || initFrames();
|
|
|
-}
|
|
|
+ void destroy() {
|
|
|
+ if(static_cast<VkDevice>(base) != VK_NULL_HANDLE) {
|
|
|
+ vkDeviceWaitIdle(base);
|
|
|
+ vkDestroyCommandPool(base, commandPool, nullptr);
|
|
|
+ vkDestroyPipeline(base, pipeline, nullptr);
|
|
|
+ vkDestroyRenderPass(base, renderPass, nullptr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
-static bool shouldWait = false;
|
|
|
+static Core::UniquePointer<VulkanDummy> dummy;
|
|
|
|
|
|
-static bool render() {
|
|
|
- if(shouldWait) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- Frame* f = frames + currentFrame;
|
|
|
- VK_CHECK_TRUE(
|
|
|
- vkWaitForFences(base, 1, &f->inFlightFence, true, UINT64_MAX));
|
|
|
- VK_CHECK_TRUE(vkResetFences(base, 1, &f->inFlightFence));
|
|
|
-
|
|
|
- uint32_t imageIndex = 0;
|
|
|
- VK_CHECK_TRUE(vkAcquireNextImageKHR(
|
|
|
- base, swapchain, UINT64_MAX, f->imageAvailableSemaphore, VK_NULL_HANDLE,
|
|
|
- &imageIndex));
|
|
|
-
|
|
|
- vkResetCommandBuffer(f->commandBuffer, 0);
|
|
|
- fillCommandBuffer(f->commandBuffer, imageIndex);
|
|
|
-
|
|
|
- VkSemaphore waitSemaphores[] = {f->imageAvailableSemaphore};
|
|
|
- VkPipelineStageFlags waitStages[] = {
|
|
|
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
|
|
- VkSemaphore signalSemaphores[] = {f->renderFinishedSemaphore};
|
|
|
- VkSubmitInfo info = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
- .waitSemaphoreCount = 1,
|
|
|
- .pWaitSemaphores = waitSemaphores,
|
|
|
- .pWaitDstStageMask = waitStages,
|
|
|
- .commandBufferCount = 1,
|
|
|
- .pCommandBuffers = &f->commandBuffer,
|
|
|
- .signalSemaphoreCount = 1,
|
|
|
- .pSignalSemaphores = signalSemaphores};
|
|
|
- VK_CHECK_TRUE(vkQueueSubmit(graphicsQueue, 1, &info, f->inFlightFence));
|
|
|
-
|
|
|
- VkPresentInfoKHR presentInfo = {
|
|
|
- .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
|
|
- .waitSemaphoreCount = 1,
|
|
|
- .pWaitSemaphores = signalSemaphores,
|
|
|
- .swapchainCount = 1,
|
|
|
- .pSwapchains = &swapchain,
|
|
|
- .pImageIndices = &imageIndex};
|
|
|
-
|
|
|
- VK_CHECK_TRUE(vkQueuePresentKHR(presentQueue, &presentInfo));
|
|
|
- currentFrame = (currentFrame + 1) % MAX_FRAMES;
|
|
|
- return false;
|
|
|
+bool Vulkan::init() {
|
|
|
+ dummy = new VulkanDummy();
|
|
|
+ return dummy->init();
|
|
|
}
|
|
|
|
|
|
void Vulkan::render() {
|
|
|
- if(::render()) {
|
|
|
- shouldWait = true;
|
|
|
+ if(dummy->render()) {
|
|
|
+ dummy->shouldWait = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void Vulkan::destroy(void) {
|
|
|
- if(static_cast<VkDevice>(base) != VK_NULL_HANDLE) {
|
|
|
- vkDeviceWaitIdle(base);
|
|
|
- for(size_t i = 0; i < MAX_FRAMES; i++) {
|
|
|
- Frame* f = frames + i;
|
|
|
- destroyVulkanFence(f->inFlightFence, base);
|
|
|
- destroyVulkanSemaphore(f->imageAvailableSemaphore, base);
|
|
|
- destroyVulkanSemaphore(f->renderFinishedSemaphore, base);
|
|
|
- }
|
|
|
- vkDestroyCommandPool(base, commandPool, nullptr);
|
|
|
- destroyVulkanFramebuffers(framebuffers, base);
|
|
|
- vkDestroyPipeline(base, pipeline, nullptr);
|
|
|
- vkDestroyRenderPass(base, renderPass, nullptr);
|
|
|
- }
|
|
|
- destroyVulkanPipelineLayout(pipelineLayout, base);
|
|
|
- destroyVulkanShaderModule(vertexShaderModule, base);
|
|
|
- destroyVulkanShaderModule(fragmentShaderModule, base);
|
|
|
- destroyVulkanSwapchainImages(images, base);
|
|
|
- destroyVulkanSwapchain(swapchain, base);
|
|
|
- base.destroy();
|
|
|
- // frees the memory before the static objects are gone
|
|
|
- images.images = List<VkImage>();
|
|
|
- images.imageViews = List<VkImageView>();
|
|
|
- framebuffers = List<VkFramebuffer>();
|
|
|
+ dummy->destroy();
|
|
|
+ dummy = nullptr;
|
|
|
}
|