Archived
1
Fork 0

Add offscreen rendering

This commit is contained in:
Joshua Goins 2018-10-17 09:28:47 -04:00
parent 3f96161dff
commit b5dcebe55e
4 changed files with 168 additions and 47 deletions

View file

@ -9,11 +9,16 @@ struct RenderTarget {
VkSwapchainKHR swapchain = nullptr; VkSwapchainKHR swapchain = nullptr;
VkExtent2D extent = {}; VkExtent2D extent = {};
uint32_t numImages = 0; uint32_t numImages = 0, currentImage = 0;
VkImage* images = nullptr; VkImage* swapchainImages = nullptr;
VkImageView* imageViews = nullptr; VkImageView* swapchainImageViews = nullptr;
VkFramebuffer* framebuffers = nullptr; VkFramebuffer* swapchainFramebuffers = nullptr;
VkImage* offscreenImages = nullptr;
VkDeviceMemory* offscreenMemory = nullptr;
VkImageView* offscreenImageViews = nullptr;
VkFramebuffer* offscreenFramebuffers = nullptr;
VkCommandBuffer* commandBuffers = nullptr; VkCommandBuffer* commandBuffers = nullptr;

View file

@ -13,9 +13,16 @@ public:
void render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target); void render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target);
VkRenderPass getRenderPass() const {
return renderPass_;
}
private: private:
void createRenderPass();
void createPipeline(); void createPipeline();
VkRenderPass renderPass_ = nullptr;
VkPipelineLayout pipelineLayout_ = nullptr; VkPipelineLayout pipelineLayout_ = nullptr;
VkPipeline pipeline_ = nullptr; VkPipeline pipeline_ = nullptr;

View file

@ -42,13 +42,12 @@ Renderer::~Renderer() {
} }
void Renderer::render(World& world, RenderTarget* target) { void Renderer::render(World& world, RenderTarget* target) {
uint32_t imageIndex = 0; vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &target->currentImage);
vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &imageIndex);
vkWaitForFences(device_, 1, &target->fences[imageIndex], true, UINT64_MAX); vkWaitForFences(device_, 1, &target->fences[target->currentImage], true, UINT64_MAX);
vkResetFences(device_, 1, &target->fences[imageIndex]); vkResetFences(device_, 1, &target->fences[target->currentImage]);
const VkCommandBuffer commandBuffer = target->commandBuffers[imageIndex]; const VkCommandBuffer commandBuffer = target->commandBuffers[target->currentImage];
VkCommandBufferBeginInfo beginInfo = {}; VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 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); vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
worldPass_->render(commandBuffer, world, target);
VkClearValue clearColor = {}; VkClearValue clearColor = {};
VkRenderPassBeginInfo renderPassBeginInfo = {}; VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.framebuffer = target->framebuffers[imageIndex]; renderPassBeginInfo.framebuffer = target->swapchainFramebuffers[target->currentImage];
renderPassBeginInfo.renderPass = presentationRenderPass_; renderPassBeginInfo.renderPass = presentationRenderPass_;
renderPassBeginInfo.renderArea.extent = target->extent; renderPassBeginInfo.renderArea.extent = target->extent;
renderPassBeginInfo.clearValueCount = 1; renderPassBeginInfo.clearValueCount = 1;
@ -79,8 +80,6 @@ void Renderer::render(World& world, RenderTarget* target) {
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
worldPass_->render(commandBuffer, world, target);
vkCmdEndRenderPass(commandBuffer); vkCmdEndRenderPass(commandBuffer);
vkEndCommandBuffer(commandBuffer); vkEndCommandBuffer(commandBuffer);
@ -97,7 +96,7 @@ void Renderer::render(World& world, RenderTarget* target) {
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &target->renderFinishedSemaphore; submitInfo.pSignalSemaphores = &target->renderFinishedSemaphore;
vkQueueSubmit(graphicsQueue_, 1, &submitInfo, target->fences[imageIndex]); vkQueueSubmit(graphicsQueue_, 1, &submitInfo, target->fences[target->currentImage]);
VkPresentInfoKHR presentInfo = {}; VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
@ -105,7 +104,7 @@ void Renderer::render(World& world, RenderTarget* target) {
presentInfo.pWaitSemaphores = &target->renderFinishedSemaphore; presentInfo.pWaitSemaphores = &target->renderFinishedSemaphore;
presentInfo.swapchainCount = 1; presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &target->swapchain; presentInfo.pSwapchains = &target->swapchain;
presentInfo.pImageIndices = &imageIndex; presentInfo.pImageIndices = &target->currentImage;
vkQueuePresentKHR(graphicsQueue_, &presentInfo); vkQueuePresentKHR(graphicsQueue_, &presentInfo);
} }
@ -167,35 +166,101 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa
target->numImages = swapchainImageCount; target->numImages = swapchainImageCount;
target->images = new VkImage[swapchainImageCount]; target->swapchainImages = new VkImage[swapchainImageCount];
vkGetSwapchainImagesKHR(device_, target->swapchain, &swapchainImageCount, target->images); 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++) { for(uint32_t i = 0; i < swapchainImageCount; i++) {
VkImageViewCreateInfo createInfo = {}; // swapchain image view
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; {
createInfo.image = target->images[i]; VkImageViewCreateInfo createInfo = {};
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfo.format = VK_FORMAT_B8G8R8A8_SRGB; createInfo.image = target->swapchainImages[i];
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.subresourceRange.levelCount = 1; createInfo.format = VK_FORMAT_B8G8R8A8_SRGB;
createInfo.subresourceRange.layerCount = 1; 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]; // swapchain framebuffer
for(uint32_t i = 0; i < swapchainImageCount; i++) { {
VkFramebufferCreateInfo framebufferInfo = {}; VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = presentationRenderPass_; framebufferInfo.renderPass = presentationRenderPass_;
framebufferInfo.attachmentCount = 1; framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = &target->imageViews[i]; framebufferInfo.pAttachments = &target->swapchainImageViews[i];
framebufferInfo.width = target->extent.width; framebufferInfo.width = target->extent.width;
framebufferInfo.height = target->extent.height; framebufferInfo.height = target->extent.height;
framebufferInfo.layers = 1; 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 = {}; VkCommandBufferAllocateInfo allocateInfo = {};
@ -242,13 +307,13 @@ void Renderer::destroyRenderTarget(RenderTarget* target) {
delete[] target->commandBuffers; delete[] target->commandBuffers;
for(uint32_t i = 0; i < target->numImages; i++) { for(uint32_t i = 0; i < target->numImages; i++) {
vkDestroyFramebuffer(device_, target->framebuffers[i], nullptr); vkDestroyFramebuffer(device_, target->swapchainFramebuffers[i], nullptr);
vkDestroyImageView(device_, target->imageViews[i], nullptr); vkDestroyImageView(device_, target->swapchainImageViews[i], nullptr);
} }
delete[] target->framebuffers; delete[] target->swapchainFramebuffers;
delete[] target->imageViews; delete[] target->swapchainImageViews;
delete[] target->images; delete[] target->swapchainImages;
vkDestroySwapchainKHR(device_, target->swapchain, nullptr); vkDestroySwapchainKHR(device_, target->swapchain, nullptr);

View file

@ -8,6 +8,7 @@
#include "mesh.h" #include "mesh.h"
WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) { WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) {
createRenderPass();
createPipeline(); createPipeline();
} }
@ -17,6 +18,18 @@ WorldPass::~WorldPass() {
} }
void WorldPass::render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target) { 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_); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
for(const auto& mesh : world.meshes) { 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); 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() { void WorldPass::createPipeline() {
@ -62,12 +106,12 @@ void WorldPass::createPipeline() {
normalAttributeDescription.location = 1; normalAttributeDescription.location = 1;
normalAttributeDescription.offset = offsetof(Vertex, normal); normalAttributeDescription.offset = offsetof(Vertex, normal);
normalAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT; normalAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT;
const std::array<VkVertexInputAttributeDescription, 2> attributes = { const std::array<VkVertexInputAttributeDescription, 2> attributes = {
positionAttributeDescription, positionAttributeDescription,
normalAttributeDescription normalAttributeDescription
}; };
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 1; vertexInputInfo.vertexBindingDescriptionCount = 1;
@ -137,7 +181,7 @@ void WorldPass::createPipeline() {
pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = &dynamicState; pipelineInfo.pDynamicState = &dynamicState;
pipelineInfo.layout = pipelineLayout_; pipelineInfo.layout = pipelineLayout_;
pipelineInfo.renderPass = renderer_.getRenderPass(); pipelineInfo.renderPass = renderPass_;
vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_); vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_);