Add offscreen rendering
This commit is contained in:
parent
3f96161dff
commit
b5dcebe55e
4 changed files with 168 additions and 47 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
113
src/renderer.cpp
113
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++) {
|
||||
// swapchain image view
|
||||
{
|
||||
VkImageViewCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = target->images[i];
|
||||
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++) {
|
||||
// swapchain framebuffer
|
||||
{
|
||||
VkFramebufferCreateInfo framebufferInfo = {};
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.renderPass = presentationRenderPass_;
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
framebufferInfo.pAttachments = &target->imageViews[i];
|
||||
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);
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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_);
|
||||
|
||||
|
|
Reference in a new issue