| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841 |
- #include "core/VulkanWrapper.hpp"
- #include <cstring>
- #include "GLFW.hpp"
- #include "core/VulkanBase.hpp"
- #include "core/WindowManager.hpp"
- import Core.File;
- import Core.UniquePointer;
- import Core.List;
- import Core.Logger;
- import Core.Types;
- import Core.Math;
- import Core.Array;
- import Core.Vector;
- namespace Vulkan = Core::Vulkan;
- using Core::List;
- using Core::Vulkan::VertexBuffer;
- using Vulkan::CommandBuffer;
- using Vulkan::Queue;
- using Vulkan::SwapchainImages;
- using Vulkan::SwapchainResult;
- #define WRAPPER_DESTRUCT(Type, ...) \
- using Core::Vulkan::Type; \
- Type::~Type() { \
- if(device != VK_NULL_HANDLE) { \
- vkDestroy##Type##__VA_ARGS__(device, handle, nullptr); \
- } \
- device = VK_NULL_HANDLE; \
- handle = VK_NULL_HANDLE; \
- }
- WRAPPER_DESTRUCT(ImageView)
- WRAPPER_DESTRUCT(Framebuffer)
- WRAPPER_DESTRUCT(Semaphore)
- WRAPPER_DESTRUCT(Fence)
- WRAPPER_DESTRUCT(Swapchain, KHR)
- WRAPPER_DESTRUCT(ShaderModule)
- WRAPPER_DESTRUCT(PipelineLayout)
- WRAPPER_DESTRUCT(Pipeline)
- WRAPPER_DESTRUCT(CommandPool)
- WRAPPER_DESTRUCT(RenderPass)
- bool ImageView::init(VkDevice d, VkImage image, VkFormat format) {
- ImageView::~ImageView();
- VkImageViewCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
- .image = image,
- .viewType = VK_IMAGE_VIEW_TYPE_2D,
- .format = format,
- .subresourceRange = {
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1}};
- VK_CHECK_TRUE(vkCreateImageView(d, &info, nullptr, &handle));
- device = d;
- return false;
- }
- bool Framebuffer::init(
- const ImageView& iv, VkRenderPass rp, u32 width, u32 height) {
- Framebuffer::~Framebuffer();
- VkFramebufferCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
- .renderPass = rp,
- .attachmentCount = 1,
- .pAttachments = iv,
- .width = width,
- .height = height,
- .layers = 1};
- VK_CHECK_TRUE(vkCreateFramebuffer(iv.device, &info, nullptr, &handle));
- device = iv.device;
- return false;
- }
- bool Semaphore::init(VkDevice d) {
- Semaphore::~Semaphore();
- VkSemaphoreCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
- VK_CHECK_TRUE(vkCreateSemaphore(d, &info, nullptr, &handle));
- device = d;
- return false;
- }
- bool Fence::init(VkDevice d) {
- Fence::~Fence();
- 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;
- }
- void Fence::reset() {
- VK_CHECK_VOID(vkResetFences(device, 1, &handle));
- }
- void Fence::waitFor(u64 timeout) {
- VK_CHECK_VOID(vkWaitForFences(device, 1, &handle, true, timeout));
- }
- 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) {
- return Core::min(c, caps->maxImageCount);
- }
- return c;
- }
- bool Swapchain::init(Data& d) {
- Swapchain::~Swapchain();
- VkSurfaceCapabilitiesKHR caps = {};
- if(d.base.getSurfaceCapabilities(caps)) {
- return true;
- }
- VkSwapchainCreateInfoKHR ci = {
- .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
- .surface = d.base,
- .minImageCount = getSwapImageCount(&caps),
- .imageFormat = d.surfaceFormat.format,
- .imageColorSpace = d.surfaceFormat.colorSpace,
- .imageExtent = d.size,
- .imageArrayLayers = 1,
- .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
- .imageSharingMode = d.sharingMode,
- .queueFamilyIndexCount = static_cast<u32>(d.queueFamilies.getLength()),
- .pQueueFamilyIndices = &d.queueFamilies[0],
- .preTransform = caps.currentTransform,
- .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
- .presentMode = d.presentMode,
- .clipped = VK_TRUE,
- .oldSwapchain = VK_NULL_HANDLE};
- VK_CHECK_TRUE(vkCreateSwapchainKHR(d.base, &ci, nullptr, &handle));
- device = d.base;
- return false;
- }
- SwapchainResult Swapchain::nextImage(
- u32& imageIndex, Semaphore& s, u64 timeout) {
- VkResult r = vkAcquireNextImageKHR(
- device, handle, timeout, s, VK_NULL_HANDLE, &imageIndex);
- if(r == VK_SUBOPTIMAL_KHR) {
- return SwapchainResult::RECREATE;
- } else if(r == VK_ERROR_OUT_OF_DATE_KHR) {
- return SwapchainResult::ERROR_RECREATE;
- }
- VK_CHECK(SwapchainResult::ERROR, r);
- return SwapchainResult::SUCCESS;
- }
- bool ShaderModule::init(VkDevice d, const char* path) {
- ShaderModule::~ShaderModule();
- List<char> f;
- if(Core::readFile(f, path)) {
- return true;
- }
- size_t l = f.getLength() - 1;
- if((l % 4) != 0) {
- VK_REPORT_ERROR("Shader size is not a multiple of 4");
- return true;
- }
- 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;
- }
- bool PipelineLayout::init(VkDevice d) {
- PipelineLayout::~PipelineLayout();
- VkPipelineLayoutCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
- VK_CHECK_TRUE(vkCreatePipelineLayout(d, &info, nullptr, &handle));
- device = d;
- return false;
- }
- bool SwapchainImages::init(const Swapchain& s, VkFormat format) {
- u32 c = 0;
- VK_CHECK_TRUE(vkGetSwapchainImagesKHR(s.device, s.handle, &c, nullptr));
- images.resize(c);
- imageViews.resize(c);
- renderFinishedSemaphore.resize(c);
- VK_CHECK_TRUE(vkGetSwapchainImagesKHR(s.device, s.handle, &c, &images[0]));
- for(u32 x = 0; x < c; x++) {
- if(imageViews[x].init(s.device, images[x], format)) {
- return true;
- } else if(renderFinishedSemaphore[x].init(s.device)) {
- return true;
- }
- }
- return false;
- }
- bool RenderPass::init(VkDevice d, VkFormat format) {
- RenderPass::~RenderPass();
- VkAttachmentDescription c = {
- .format = 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(d, &info, nullptr, &handle));
- device = d;
- return false;
- }
- Pipeline::Pipeline() : viewport{.maxDepth = 1.0f}, scissor{} {
- }
- void Pipeline::updateSize(u32 width, u32 height) {
- viewport.width = static_cast<float>(width);
- viewport.height = static_cast<float>(height);
- scissor.extent.width = width;
- scissor.extent.height = height;
- }
- bool Pipeline::init(
- PipelineLayout& pl, RenderPass& rp,
- const List<VkVertexInputBindingDescription>& bd,
- const List<VkVertexInputAttributeDescription>& ad) {
- Pipeline::~Pipeline();
- ShaderModule vertexShaderModule;
- ShaderModule fragmentShaderModule;
- if(vertexShaderModule.init(pl.device, "shaders/vertex.spv") ||
- fragmentShaderModule.init(pl.device, "shaders/fragment.spv")) {
- return true;
- }
- 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,
- .vertexBindingDescriptionCount = static_cast<u32>(bd.getLength()),
- .pVertexBindingDescriptions = &bd[0],
- .vertexAttributeDescriptionCount = static_cast<u32>(ad.getLength()),
- .pVertexAttributeDescriptions = &ad[0]};
- VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
- .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
- .primitiveRestartEnable = false};
- 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 = pl,
- .renderPass = rp,
- .subpass = 0,
- .basePipelineHandle = VK_NULL_HANDLE,
- .basePipelineIndex = -1};
- VK_CHECK_TRUE(vkCreateGraphicsPipelines(
- pl.device, VK_NULL_HANDLE, 1, &info, nullptr, &handle));
- device = pl.device;
- return false;
- }
- bool CommandPool::init(VkDevice d, u32 queueFamily) {
- CommandPool::~CommandPool();
- VkCommandPoolCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
- .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
- .queueFamilyIndex = queueFamily};
- VK_CHECK_TRUE(vkCreateCommandPool(d, &info, nullptr, &handle));
- device = d;
- return false;
- }
- bool CommandBuffer::init(CommandPool& cp) {
- CommandBuffer::~CommandBuffer();
- VkCommandBufferAllocateInfo info = {
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
- .commandPool = cp,
- .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
- .commandBufferCount = 1};
- VK_CHECK_TRUE(vkAllocateCommandBuffers(cp.device, &info, &handle));
- device = cp.device;
- return false;
- }
- void CommandBuffer::reset() {
- VK_CHECK_VOID(vkResetCommandBuffer(handle, 0));
- }
- void CommandBuffer::begin() {
- VkCommandBufferBeginInfo info = {
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
- VK_CHECK_VOID(vkBeginCommandBuffer(handle, &info));
- }
- void CommandBuffer::end() {
- VK_CHECK_VOID(vkEndCommandBuffer(handle));
- }
- void CommandBuffer::beginRenderPass(
- RenderPass& rp, Framebuffer& f, const VkExtent2D& size) {
- VkClearValue v = {.color = {.float32 = {0.0f, 0.0f, 0.0f, 1.0f}}};
- VkRenderPassBeginInfo info = {
- .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
- .renderPass = rp,
- .framebuffer = f,
- .renderArea = {.offset = {0, 0}, .extent = size},
- .clearValueCount = 1,
- .pClearValues = &v};
- vkCmdBeginRenderPass(handle, &info, VK_SUBPASS_CONTENTS_INLINE);
- }
- void CommandBuffer::endRenderPass() {
- vkCmdEndRenderPass(handle);
- }
- void CommandBuffer::bindPipeline(Pipeline& p) {
- vkCmdBindPipeline(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, p);
- vkCmdSetViewport(handle, 0, 1, &p.viewport);
- vkCmdSetScissor(handle, 0, 1, &p.scissor);
- }
- void CommandBuffer::draw(u32 vertices) {
- vkCmdDraw(handle, vertices, 1, 0, 0);
- }
- bool Queue::init(VkDevice d, u32 queueFamily) {
- vkGetDeviceQueue(d, queueFamily, 0, &handle);
- return handle == VK_NULL_HANDLE;
- }
- void Queue::submit(
- CommandBuffer& cb, Fence& f, Semaphore& wait, Semaphore& signal,
- VkPipelineStageFlags flags) {
- VkSubmitInfo info = {
- .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
- .waitSemaphoreCount = 1,
- .pWaitSemaphores = wait,
- .pWaitDstStageMask = &flags,
- .commandBufferCount = 1,
- .pCommandBuffers = cb,
- .signalSemaphoreCount = 1,
- .pSignalSemaphores = signal};
- VK_CHECK_VOID(vkQueueSubmit(handle, 1, &info, f));
- }
- SwapchainResult Queue::present(Semaphore& signal, Swapchain& s, u32 index) {
- VkPresentInfoKHR info = {
- .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
- .waitSemaphoreCount = 1,
- .pWaitSemaphores = signal,
- .swapchainCount = 1,
- .pSwapchains = s,
- .pImageIndices = &index};
- VkResult r = vkQueuePresentKHR(handle, &info);
- if(r == VK_SUBOPTIMAL_KHR) {
- return SwapchainResult::RECREATE;
- } else if(r == VK_ERROR_OUT_OF_DATE_KHR) {
- return SwapchainResult::ERROR_RECREATE;
- }
- VK_CHECK(SwapchainResult::ERROR, r);
- return SwapchainResult::SUCCESS;
- }
- VertexBuffer::VertexBuffer() : BaseWrapper<VkBuffer>(), memory(VK_NULL_HANDLE) {
- }
- VertexBuffer::~VertexBuffer() {
- if(device != VK_NULL_HANDLE) {
- vkDestroyBuffer(device, handle, nullptr);
- vkFreeMemory(device, memory, nullptr);
- }
- device = VK_NULL_HANDLE;
- handle = VK_NULL_HANDLE;
- }
- bool VertexBuffer::init(Base& b, size_t size, const void* data) {
- VkBufferCreateInfo info = {
- .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
- .size = size,
- .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
- .sharingMode = VK_SHARING_MODE_EXCLUSIVE};
- VK_CHECK_TRUE(vkCreateBuffer(b, &info, nullptr, &handle));
- device = b;
- VkMemoryRequirements m;
- vkGetBufferMemoryRequirements(device, handle, &m);
- VkMemoryAllocateInfo aInfo = {
- .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
- .allocationSize = m.size,
- .memoryTypeIndex = b.findMemoryType(
- m.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)};
- VK_CHECK_TRUE(vkAllocateMemory(device, &aInfo, nullptr, &memory));
- VK_CHECK_TRUE(vkBindBufferMemory(device, handle, memory, 0));
- void* destination = nullptr;
- VK_CHECK_TRUE(vkMapMemory(device, memory, 0, size, 0, &destination));
- memcpy(destination, data, size);
- vkUnmapMemory(device, memory);
- return false;
- }
- struct VulkanDummy {
- Core::Vulkan::Base base{};
- struct BaseData {
- u32 graphicsFamily = 0;
- u32 presentFamily = 0;
- VkSurfaceFormatKHR surfaceFormat{};
- VkPresentModeKHR presentMode{};
- };
- BaseData baseData{};
- Queue graphicsQueue{};
- Queue presentQueue{};
- VkExtent2D swapchainSize{};
- Swapchain swapchain{};
- SwapchainImages images{};
- PipelineLayout pipelineLayout{};
- RenderPass renderPass{};
- Pipeline pipeline{};
- List<Vulkan::Framebuffer> framebuffers{};
- CommandPool commandPool{};
- size_t currentFrame = 0;
- struct Frame {
- CommandBuffer commandBuffer{};
- Semaphore imageAvailableSemaphore{};
- Fence inFlightFence{};
- };
- Core::Array<Frame, 2> frames{};
- struct Vertex {
- Core::Vector2 position;
- Core::Vector3 color;
- static auto getBindingDescription() {
- VkVertexInputBindingDescription d = {
- .binding = 0,
- .stride = sizeof(Vertex),
- .inputRate = VK_VERTEX_INPUT_RATE_VERTEX};
- return d;
- }
- static auto getAttributeDescriptions() {
- Core::Array<VkVertexInputAttributeDescription, 2> d = {
- {{.location = 0,
- .binding = 0,
- .format = VK_FORMAT_R32G32_SFLOAT,
- .offset = offsetof(Vertex, position)},
- {.location = 1,
- .binding = 0,
- .format = VK_FORMAT_R32G32B32_SFLOAT,
- .offset = offsetof(Vertex, color)}}};
- return d;
- }
- };
- VertexBuffer vertexBuffer{};
- 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;
- }
- 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 getSwapchainSize(VkExtent2D* size) {
- VkSurfaceCapabilitiesKHR c = {};
- if(base.getSurfaceCapabilities(c)) {
- return true;
- }
- if(c.currentExtent.width != 0xFFFF'FFFFu &&
- c.currentExtent.height != 0xFFFF'FFFFu) {
- *size = c.currentExtent;
- Core::logInfo("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) {
- Core::logError("Could not get framebuffer size");
- return true;
- }
- Core::logInfo("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);
- Core::logInfo("Swapchain size: #x#", size->width, size->height);
- return false;
- }
- bool initSwapchain() {
- Vulkan::Swapchain::Data d = {
- .base = base,
- .surfaceFormat = baseData.surfaceFormat,
- .presentMode = baseData.presentMode};
- if(getSwapchainSize(&d.size)) {
- Core::logError("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 swapchain.init(d);
- }
- bool initDevice() {
- bool same = baseData.graphicsFamily == baseData.presentFamily;
- List<Vulkan::DeviceQueueData> data;
- data.add(baseData.graphicsFamily, 1.0f);
- if(!same) {
- data.add(baseData.presentFamily, 1.0f);
- }
- List<const char*> extensions;
- extensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
- if(base.initDevice(data, extensions)) {
- return true;
- } else if(graphicsQueue.init(base, baseData.graphicsFamily)) {
- Core::logError("Cannot get device graphics queue");
- return true;
- } else if(presentQueue.init(base, baseData.presentFamily)) {
- Core::logError("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);
- Core::logInfo("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) {
- Core::logInfo("> ... has no graphics family");
- points = -1000;
- }
- d.presentFamily = b.findSurfaceQueueFamily();
- if(d.presentFamily == Vulkan::INVALID_QUEUE_FAMILY) {
- Core::logInfo("> ... has no present family");
- points = -1000;
- }
- if(!b.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
- Core::logInfo("> ... has no swapchain support");
- points = -1000;
- }
- if(b.findSurfaceFormat(d.surfaceFormat, getSurfaceFormatPoints)) {
- Core::logInfo("> ... has no matching surface format");
- points = -1000;
- } else {
- points += getSurfaceFormatPoints(d.surfaceFormat);
- }
- if(b.findSurfacePresentMode(
- d.presentMode, getSurfacePresentModePoints)) {
- Core::logInfo("> ... has no matching present mode");
- points = -1000;
- } else {
- points += getSurfacePresentModePoints(d.presentMode);
- }
- Core::logInfo("> Final points: #", points);
- return points;
- }
- bool initPhysicalDevice() {
- Core::logInfo("Searching for physical devices ...");
- if(base.findPhysicalDevice(baseData, getDevicePoints)) {
- Core::logError("No matching physical device was found");
- return true;
- }
- VkPhysicalDeviceProperties p;
- base.getPhysicalDeviceProperties(p);
- Core::logInfo("Best Device: #", p.deviceName);
- return false;
- }
- bool initSwapchainImages() {
- if(images.init(swapchain, baseData.surfaceFormat.format)) {
- Core::logError("Could not get swapchain images");
- return true;
- }
- Core::logInfo("Found # images", images.images.getLength());
- return false;
- }
- bool initPipeline() {
- pipeline.updateSize(swapchainSize.width, swapchainSize.height);
- List<VkVertexInputBindingDescription> bd;
- bd.add(Vertex::getBindingDescription());
- List<VkVertexInputAttributeDescription> ad;
- for(auto a : Vertex::getAttributeDescriptions()) {
- ad.add(a);
- }
- return pipeline.init(pipelineLayout, renderPass, bd, ad);
- }
- bool initFramebuffers() {
- framebuffers.resize(images.imageViews.getLength());
- size_t i = 0;
- for(Framebuffer& f : framebuffers) {
- if(f.init(
- images.imageViews[i++], renderPass, swapchainSize.width,
- swapchainSize.height)) {
- return true;
- }
- }
- return false;
- }
- void fillCommandBuffer(CommandBuffer& cb, u32 index) {
- cb.begin();
- cb.beginRenderPass(renderPass, framebuffers[index], swapchainSize);
- cb.bindPipeline(pipeline);
- VkDeviceSize offset = 0;
- vkCmdBindVertexBuffers(cb, 0, 1, vertexBuffer, &offset);
- cb.draw(3);
- cb.endRenderPass();
- cb.end();
- }
- bool initFrames() {
- for(Frame& f : frames) {
- if(f.commandBuffer.init(commandPool) ||
- f.imageAvailableSemaphore.init(base) ||
- f.inFlightFence.init(base)) {
- return true;
- }
- }
- return false;
- }
- bool initVertexBuffer() {
- List<Vertex> l;
- l.add(Core::Vector2{-0.5f, -0.5f}, Core::Vector3{1.0, 1.0, 1.0});
- l.add(Core::Vector2{0.5f, 0.0f}, Core::Vector3{0.0, 1.0, 1.0});
- l.add(Core::Vector2{0.0f, 0.5f}, Core::Vector3{1.0, 1.0, 0.0});
- return vertexBuffer.init(base, sizeof(l[0]) * l.getLength(), &l[0]);
- }
- bool init() {
- return base.init() || initPhysicalDevice() || initDevice() ||
- initSwapchain() || initSwapchainImages() ||
- pipelineLayout.init(base) ||
- renderPass.init(base, baseData.surfaceFormat.format) ||
- initPipeline() || initFramebuffers() ||
- commandPool.init(base, baseData.graphicsFamily) ||
- initFrames() || initVertexBuffer();
- }
- bool recreateSwapchain() {
- Core::logInfo("Recreate swapchain");
- base.waitForIdle();
- if(initSwapchain() || initSwapchainImages() || initFramebuffers()) {
- return true;
- }
- pipeline.updateSize(swapchainSize.width, swapchainSize.height);
- return false;
- }
- bool render() {
- Frame& f = frames[currentFrame];
- f.inFlightFence.waitFor();
- u32 imageIndex = 0;
- switch(swapchain.nextImage(imageIndex, f.imageAvailableSemaphore)) {
- case SwapchainResult::SUCCESS: break;
- case SwapchainResult::RECREATE: break;
- case SwapchainResult::ERROR_RECREATE: return recreateSwapchain();
- case SwapchainResult::ERROR: return true;
- }
- // https://docs.vulkan.org/guide/latest/swapchain_semaphore_reuse.html
- Semaphore& renderSemaphore = images.renderFinishedSemaphore[imageIndex];
- f.inFlightFence.reset();
- f.commandBuffer.reset();
- fillCommandBuffer(f.commandBuffer, imageIndex);
- graphicsQueue.submit(
- f.commandBuffer, f.inFlightFence, f.imageAvailableSemaphore,
- renderSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
- bool recreate = false;
- switch(presentQueue.present(renderSemaphore, swapchain, imageIndex)) {
- case SwapchainResult::SUCCESS: break;
- case SwapchainResult::RECREATE:
- case SwapchainResult::ERROR_RECREATE: recreate = true;
- case SwapchainResult::ERROR: break;
- }
- currentFrame = (currentFrame + 1) % frames.getLength();
- if(recreate || Core::Window::hasSizeChanged()) {
- recreateSwapchain();
- }
- return false;
- }
- };
- static Core::UniquePointer<VulkanDummy> dummy;
- bool Vulkan::init() {
- dummy = new VulkanDummy();
- return dummy->init();
- }
- void Vulkan::render() {
- dummy->render();
- }
- void Vulkan::destroy() {
- dummy->base.waitForIdle();
- dummy = nullptr;
- }
|