From b5dcebe55ea7bc88b78ad834511ab33acfe79f4e Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Wed, 17 Oct 2018 09:28:47 -0400 Subject: [PATCH] Add offscreen rendering --- include/renderer.h | 13 ++-- include/worldpass.h | 7 +++ src/renderer.cpp | 143 ++++++++++++++++++++++++++++++++------------ src/worldpass.cpp | 52 ++++++++++++++-- 4 files changed, 168 insertions(+), 47 deletions(-) diff --git a/include/renderer.h b/include/renderer.h index 7d66552..1ef2ffb 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -9,11 +9,16 @@ struct RenderTarget { VkSwapchainKHR swapchain = nullptr; VkExtent2D extent = {}; - uint32_t numImages = 0; + uint32_t numImages = 0, currentImage = 0; - VkImage* images = nullptr; - VkImageView* imageViews = nullptr; - VkFramebuffer* framebuffers = nullptr; + VkImage* swapchainImages = nullptr; + VkImageView* swapchainImageViews = nullptr; + VkFramebuffer* swapchainFramebuffers = nullptr; + + VkImage* offscreenImages = nullptr; + VkDeviceMemory* offscreenMemory = nullptr; + VkImageView* offscreenImageViews = nullptr; + VkFramebuffer* offscreenFramebuffers = nullptr; VkCommandBuffer* commandBuffers = nullptr; diff --git a/include/worldpass.h b/include/worldpass.h index c107e5b..25d14c9 100644 --- a/include/worldpass.h +++ b/include/worldpass.h @@ -13,9 +13,16 @@ public: void render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target); + VkRenderPass getRenderPass() const { + return renderPass_; + } + private: + void createRenderPass(); void createPipeline(); + VkRenderPass renderPass_ = nullptr; + VkPipelineLayout pipelineLayout_ = nullptr; VkPipeline pipeline_ = nullptr; diff --git a/src/renderer.cpp b/src/renderer.cpp index 7193ee1..039b962 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -42,13 +42,12 @@ Renderer::~Renderer() { } void Renderer::render(World& world, RenderTarget* target) { - uint32_t imageIndex = 0; - vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &imageIndex); + vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &target->currentImage); - vkWaitForFences(device_, 1, &target->fences[imageIndex], true, UINT64_MAX); - vkResetFences(device_, 1, &target->fences[imageIndex]); + vkWaitForFences(device_, 1, &target->fences[target->currentImage], true, UINT64_MAX); + vkResetFences(device_, 1, &target->fences[target->currentImage]); - const VkCommandBuffer commandBuffer = target->commandBuffers[imageIndex]; + const VkCommandBuffer commandBuffer = target->commandBuffers[target->currentImage]; VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -67,11 +66,13 @@ void Renderer::render(World& world, RenderTarget* target) { vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + worldPass_->render(commandBuffer, world, target); + VkClearValue clearColor = {}; VkRenderPassBeginInfo renderPassBeginInfo = {}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBeginInfo.framebuffer = target->framebuffers[imageIndex]; + renderPassBeginInfo.framebuffer = target->swapchainFramebuffers[target->currentImage]; renderPassBeginInfo.renderPass = presentationRenderPass_; renderPassBeginInfo.renderArea.extent = target->extent; renderPassBeginInfo.clearValueCount = 1; @@ -79,8 +80,6 @@ void Renderer::render(World& world, RenderTarget* target) { vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - worldPass_->render(commandBuffer, world, target); - vkCmdEndRenderPass(commandBuffer); vkEndCommandBuffer(commandBuffer); @@ -97,7 +96,7 @@ void Renderer::render(World& world, RenderTarget* target) { submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &target->renderFinishedSemaphore; - vkQueueSubmit(graphicsQueue_, 1, &submitInfo, target->fences[imageIndex]); + vkQueueSubmit(graphicsQueue_, 1, &submitInfo, target->fences[target->currentImage]); VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -105,7 +104,7 @@ void Renderer::render(World& world, RenderTarget* target) { presentInfo.pWaitSemaphores = &target->renderFinishedSemaphore; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &target->swapchain; - presentInfo.pImageIndices = &imageIndex; + presentInfo.pImageIndices = &target->currentImage; vkQueuePresentKHR(graphicsQueue_, &presentInfo); } @@ -167,35 +166,101 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa target->numImages = swapchainImageCount; - target->images = new VkImage[swapchainImageCount]; - vkGetSwapchainImagesKHR(device_, target->swapchain, &swapchainImageCount, target->images); + target->swapchainImages = new VkImage[swapchainImageCount]; + vkGetSwapchainImagesKHR(device_, target->swapchain, &swapchainImageCount, target->swapchainImages); - target->imageViews = new VkImageView[swapchainImageCount]; + // create frame resources + target->swapchainImageViews = new VkImageView[swapchainImageCount]; + target->swapchainFramebuffers = new VkFramebuffer[swapchainImageCount]; + target->offscreenImages = new VkImage[swapchainImageCount]; + target->offscreenMemory = new VkDeviceMemory[swapchainImageCount]; + target->offscreenImageViews = new VkImageView[swapchainImageCount]; + target->offscreenFramebuffers = new VkFramebuffer[swapchainImageCount]; for(uint32_t i = 0; i < swapchainImageCount; i++) { - VkImageViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = target->images[i]; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = VK_FORMAT_B8G8R8A8_SRGB; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.layerCount = 1; + // swapchain image view + { + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = target->swapchainImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = VK_FORMAT_B8G8R8A8_SRGB; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.layerCount = 1; - vkCreateImageView(device_, &createInfo, nullptr, &target->imageViews[i]); - } + vkCreateImageView(device_, &createInfo, nullptr, &target->swapchainImageViews[i]); + } - target->framebuffers = new VkFramebuffer[swapchainImageCount]; - for(uint32_t i = 0; i < swapchainImageCount; i++) { - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = presentationRenderPass_; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = &target->imageViews[i]; - framebufferInfo.width = target->extent.width; - framebufferInfo.height = target->extent.height; - framebufferInfo.layers = 1; + // swapchain framebuffer + { + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = presentationRenderPass_; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &target->swapchainImageViews[i]; + framebufferInfo.width = target->extent.width; + framebufferInfo.height = target->extent.height; + framebufferInfo.layers = 1; - vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->framebuffers[i]); + vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->swapchainFramebuffers[i]); + } + + // offscreen image + { + VkImageCreateInfo imageCreateInfo = {}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; + imageCreateInfo.extent.width = target->extent.width; + imageCreateInfo.extent.height = target->extent.height; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + + vkCreateImage(device_, &imageCreateInfo, nullptr, &target->offscreenImages[i]); + + VkMemoryRequirements memoryRequirements = {}; + vkGetImageMemoryRequirements(device_, target->offscreenImages[i], &memoryRequirements); + + VkMemoryAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memoryRequirements.size; + allocateInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(device_, &allocateInfo, nullptr, &target->offscreenMemory[i]); + vkBindImageMemory(device_, target->offscreenImages[i], target->offscreenMemory[i], 0); + } + + // offscreen image view + { + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = target->offscreenImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.layerCount = 1; + + vkCreateImageView(device_, &createInfo, nullptr, &target->offscreenImageViews[i]); + } + + // offscreen framebuffer + { + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = worldPass_->getRenderPass(); + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &target->offscreenImageViews[i]; + framebufferInfo.width = target->extent.width; + framebufferInfo.height = target->extent.height; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->offscreenFramebuffers[i]); + } } VkCommandBufferAllocateInfo allocateInfo = {}; @@ -242,13 +307,13 @@ void Renderer::destroyRenderTarget(RenderTarget* target) { delete[] target->commandBuffers; for(uint32_t i = 0; i < target->numImages; i++) { - vkDestroyFramebuffer(device_, target->framebuffers[i], nullptr); - vkDestroyImageView(device_, target->imageViews[i], nullptr); + vkDestroyFramebuffer(device_, target->swapchainFramebuffers[i], nullptr); + vkDestroyImageView(device_, target->swapchainImageViews[i], nullptr); } - delete[] target->framebuffers; - delete[] target->imageViews; - delete[] target->images; + delete[] target->swapchainFramebuffers; + delete[] target->swapchainImageViews; + delete[] target->swapchainImages; vkDestroySwapchainKHR(device_, target->swapchain, nullptr); diff --git a/src/worldpass.cpp b/src/worldpass.cpp index 9033f91..8ec4d01 100644 --- a/src/worldpass.cpp +++ b/src/worldpass.cpp @@ -8,6 +8,7 @@ #include "mesh.h" WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) { + createRenderPass(); createPipeline(); } @@ -17,6 +18,18 @@ WorldPass::~WorldPass() { } void WorldPass::render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target) { + VkClearValue clearColor = {}; + + VkRenderPassBeginInfo renderPassBeginInfo = {}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.framebuffer = target->offscreenFramebuffers[target->currentImage]; + renderPassBeginInfo.renderPass = renderPass_; + renderPassBeginInfo.renderArea.extent = target->extent; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); for(const auto& mesh : world.meshes) { @@ -32,6 +45,37 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, RenderTarget vkCmdDrawIndexed(commandBuffer, mesh->indices.size(), 1, 0, 0, 0); } + + vkCmdEndRenderPass(commandBuffer); +} + +void WorldPass::createRenderPass() { + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = VK_FORMAT_R32G32B32A32_SFLOAT; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + + vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_); } void WorldPass::createPipeline() { @@ -62,12 +106,12 @@ void WorldPass::createPipeline() { normalAttributeDescription.location = 1; normalAttributeDescription.offset = offsetof(Vertex, normal); normalAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT; - + const std::array attributes = { - positionAttributeDescription, + positionAttributeDescription, normalAttributeDescription }; - + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.vertexBindingDescriptionCount = 1; @@ -137,7 +181,7 @@ void WorldPass::createPipeline() { pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; pipelineInfo.layout = pipelineLayout_; - pipelineInfo.renderPass = renderer_.getRenderPass(); + pipelineInfo.renderPass = renderPass_; vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_);