|
@@ -8,6 +8,7 @@
|
|
|
|
|
|
namespace Vulkan = Core::Vulkan;
|
|
|
using Vulkan::CommandBuffer;
|
|
|
+using Vulkan::Queue;
|
|
|
using Vulkan::SwapchainImages;
|
|
|
|
|
|
#define WRAPPER_DESTRUCT(Type, ...) \
|
|
@@ -25,6 +26,9 @@ 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) {
|
|
|
VkImageViewCreateInfo info = {
|
|
@@ -75,6 +79,14 @@ bool Fence::init(VkDevice 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;
|
|
|
|
|
@@ -112,6 +124,12 @@ bool Swapchain::init(Data& d) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+bool Swapchain::nextImage(u32& imageIndex, Semaphore& s, u64 timeout) {
|
|
|
+ VK_CHECK_TRUE(vkAcquireNextImageKHR(
|
|
|
+ device, handle, timeout, s, VK_NULL_HANDLE, &imageIndex));
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
bool ShaderModule::init(VkDevice d, const char* path) {
|
|
|
List<char> f;
|
|
|
if(Core::readFile(f, path)) {
|
|
@@ -153,17 +171,252 @@ bool SwapchainImages::init(const Swapchain& s, VkFormat format) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-bool CommandBuffer::init(VkDevice d, VkCommandPool cp) {
|
|
|
+bool RenderPass::init(VkDevice d, VkFormat format) {
|
|
|
+ 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) {
|
|
|
+ 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};
|
|
|
+
|
|
|
+ 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) {
|
|
|
+ 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) {
|
|
|
VkCommandBufferAllocateInfo info = {
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
|
.commandPool = cp,
|
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
|
.commandBufferCount = 1};
|
|
|
- VK_CHECK_TRUE(vkAllocateCommandBuffers(d, &info, &handle));
|
|
|
- device = d;
|
|
|
+ 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));
|
|
|
+}
|
|
|
+
|
|
|
+void 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};
|
|
|
+ VK_CHECK_VOID(vkQueuePresentKHR(handle, &info));
|
|
|
+}
|
|
|
+
|
|
|
struct VulkanDummy {
|
|
|
Core::Vulkan::Base base{};
|
|
|
|
|
@@ -175,21 +428,16 @@ struct VulkanDummy {
|
|
|
};
|
|
|
|
|
|
BaseData baseData{};
|
|
|
- VkQueue graphicsQueue{};
|
|
|
- VkQueue presentQueue{};
|
|
|
+ Queue graphicsQueue{};
|
|
|
+ Queue presentQueue{};
|
|
|
VkExtent2D swapchainSize{};
|
|
|
Swapchain swapchain{};
|
|
|
SwapchainImages images{};
|
|
|
- ShaderModule vertexShaderModule{};
|
|
|
- ShaderModule fragmentShaderModule{};
|
|
|
PipelineLayout pipelineLayout{};
|
|
|
- VkRenderPass renderPass{};
|
|
|
- VkViewport viewport{};
|
|
|
- VkRect2D scissor{};
|
|
|
- VkPipeline pipeline{};
|
|
|
+ RenderPass renderPass{};
|
|
|
+ Pipeline pipeline{};
|
|
|
Core::List<Vulkan::Framebuffer> framebuffers{};
|
|
|
- VkCommandPool commandPool{};
|
|
|
- static constexpr size_t MAX_FRAMES = 2;
|
|
|
+ CommandPool commandPool{};
|
|
|
size_t currentFrame = 0;
|
|
|
bool shouldWait = false;
|
|
|
|
|
@@ -200,7 +448,7 @@ struct VulkanDummy {
|
|
|
Fence inFlightFence{};
|
|
|
};
|
|
|
|
|
|
- Frame frames[MAX_FRAMES];
|
|
|
+ Core::Array<Frame, 2> frames{};
|
|
|
|
|
|
static int getSurfaceFormatPoints(const VkSurfaceFormatKHR& sf) {
|
|
|
if(sf.format == VK_FORMAT_B8G8R8A8_UNORM &&
|
|
@@ -279,18 +527,10 @@ struct VulkanDummy {
|
|
|
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) {
|
|
|
+ } else if(graphicsQueue.init(base, baseData.graphicsFamily)) {
|
|
|
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) {
|
|
|
+ } else if(presentQueue.init(base, baseData.presentFamily)) {
|
|
|
LOG_ERROR("Cannot get device present queue");
|
|
|
return true;
|
|
|
}
|
|
@@ -360,118 +600,9 @@ struct VulkanDummy {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- bool initShaders() {
|
|
|
- return vertexShaderModule.init(base, "shaders/vertex.spv") ||
|
|
|
- fragmentShaderModule.init(base, "shaders/fragment.spv");
|
|
|
- }
|
|
|
-
|
|
|
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;
|
|
|
+ pipeline.updateSize(swapchainSize.width, swapchainSize.height);
|
|
|
+ return pipeline.init(pipelineLayout, renderPass);
|
|
|
}
|
|
|
|
|
|
bool initFramebuffers() {
|
|
@@ -487,80 +618,21 @@ struct VulkanDummy {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- 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 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 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;
|
|
|
+ void fillCommandBuffer(CommandBuffer& cb, u32 index) {
|
|
|
+ cb.begin();
|
|
|
+ cb.beginRenderPass(renderPass, framebuffers[index], swapchainSize);
|
|
|
+ cb.bindPipeline(pipeline);
|
|
|
+ cb.draw(6);
|
|
|
+ cb.endRenderPass();
|
|
|
+ cb.end();
|
|
|
}
|
|
|
|
|
|
bool initFrames() {
|
|
|
- for(size_t i = 0; i < MAX_FRAMES; i++) {
|
|
|
- if(frames[i].commandBuffer.init(base, commandPool) ||
|
|
|
- frames[i].imageAvailableSemaphore.init(base) ||
|
|
|
- frames[i].renderFinishedSemaphore.init(base) ||
|
|
|
- frames[i].inFlightFence.init(base)) {
|
|
|
+ for(Frame& f : frames) {
|
|
|
+ if(f.commandBuffer.init(commandPool) ||
|
|
|
+ f.imageAvailableSemaphore.init(base) ||
|
|
|
+ f.renderFinishedSemaphore.init(base) ||
|
|
|
+ f.inFlightFence.init(base)) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
@@ -569,64 +641,36 @@ struct VulkanDummy {
|
|
|
|
|
|
bool init() {
|
|
|
return base.init() || initPhysicalDevice() || initDevice() ||
|
|
|
- initSwapchain() || initSwapchainImages() || initShaders() ||
|
|
|
- pipelineLayout.init(base) || initRenderPass() ||
|
|
|
- initPipeline() || initFramebuffers() || initCommandPool() ||
|
|
|
- initFrames();
|
|
|
+ initSwapchain() || initSwapchainImages() ||
|
|
|
+ pipelineLayout.init(base) ||
|
|
|
+ renderPass.init(base, baseData.surfaceFormat.format) ||
|
|
|
+ initPipeline() || initFramebuffers() ||
|
|
|
+ commandPool.init(base, baseData.graphicsFamily) || initFrames();
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
- }
|
|
|
+ Frame& f = frames[currentFrame];
|
|
|
+ f.inFlightFence.waitFor();
|
|
|
+ f.inFlightFence.reset();
|
|
|
|
|
|
- void destroy() {
|
|
|
- if(static_cast<VkDevice>(base) != VK_NULL_HANDLE) {
|
|
|
- vkDeviceWaitIdle(base);
|
|
|
- vkDestroyCommandPool(base, commandPool, nullptr);
|
|
|
- vkDestroyPipeline(base, pipeline, nullptr);
|
|
|
- vkDestroyRenderPass(base, renderPass, nullptr);
|
|
|
+ u32 imageIndex = 0;
|
|
|
+ if(swapchain.nextImage(imageIndex, f.imageAvailableSemaphore)) {
|
|
|
+ return true;
|
|
|
}
|
|
|
+ f.commandBuffer.reset();
|
|
|
+ fillCommandBuffer(f.commandBuffer, imageIndex);
|
|
|
+
|
|
|
+ graphicsQueue.submit(
|
|
|
+ f.commandBuffer, f.inFlightFence, f.imageAvailableSemaphore,
|
|
|
+ f.renderFinishedSemaphore,
|
|
|
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
|
|
|
+
|
|
|
+ presentQueue.present(f.renderFinishedSemaphore, swapchain, imageIndex);
|
|
|
+ currentFrame = (currentFrame + 1) % frames.getLength();
|
|
|
+ return false;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -643,7 +687,7 @@ void Vulkan::render() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void Vulkan::destroy(void) {
|
|
|
- dummy->destroy();
|
|
|
+void Vulkan::destroy() {
|
|
|
+ dummy->base.waitForIdle();
|
|
|
dummy = nullptr;
|
|
|
}
|