Successfully cleared the screen. created synchronization objects for rendering and presentation
This commit is contained in:
parent
c393e0cdb1
commit
4365cc45d1
@ -4,7 +4,6 @@ set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-DDEBUG")
|
||||
set(CMAKE_CXX_FLAGS "-fsanitize=address -g -DDEBUG -D_DEBUG")
|
||||
|
||||
project(Pleascach)
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#include <Renderer/Pipeline.hpp>
|
||||
|
||||
|
||||
#include <util/log.hpp>
|
||||
|
||||
CommandBuffer::CommandBuffer(vk::Device dev, u32 queue_family) {
|
||||
/* (For now) allow command buffers to be individually recycled */
|
||||
auto pool_info = vk::CommandPoolCreateInfo {
|
||||
@ -18,7 +20,6 @@ CommandBuffer::CommandBuffer(vk::Device dev, u32 queue_family) {
|
||||
.level = vk::CommandBufferLevel::ePrimary,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
|
||||
command_buffer = dev.allocateCommandBuffers(alloc_info)[0];
|
||||
}
|
||||
@ -26,7 +27,6 @@ CommandBuffer::CommandBuffer(vk::Device dev, u32 queue_family) {
|
||||
void CommandBuffer::begin() {
|
||||
auto begin_info = vk::CommandBufferBeginInfo{
|
||||
.flags = static_cast<vk::CommandBufferUsageFlags>(0),
|
||||
.pInheritanceInfo = nullptr,
|
||||
};
|
||||
|
||||
command_buffer.begin(begin_info);
|
||||
@ -50,8 +50,10 @@ void CommandBuffer::end() {
|
||||
|
||||
void CommandBuffer::recycle() {
|
||||
command_buffer.reset();
|
||||
|
||||
}
|
||||
|
||||
void CommandBuffer::cleanup(vk::Device dev) {
|
||||
dev.freeCommandBuffers(command_pool, command_buffer);
|
||||
dev.destroyCommandPool(command_pool);
|
||||
}
|
||||
|
||||
@ -29,4 +29,8 @@ struct CommandBuffer {
|
||||
|
||||
vk::CommandBuffer command_buffer;
|
||||
vk::CommandPool command_pool;
|
||||
|
||||
operator vk::CommandBuffer* () {
|
||||
return &command_buffer;
|
||||
}
|
||||
};
|
||||
|
||||
@ -145,8 +145,6 @@ Renderer::Renderer(Window& win) : win(win) {
|
||||
Log::error("Failed to get surface from window\n");
|
||||
}
|
||||
|
||||
swapchain = std::make_unique<Swapchain>(dev, surface, win.getDimensions());
|
||||
|
||||
queue = dev.getQueue(queue_family, 0);
|
||||
|
||||
|
||||
@ -185,7 +183,7 @@ Renderer::Renderer(Window& win) : win(win) {
|
||||
.memoryTypeIndex = mem::choose_heap(phys_dev, depth_mem_reqs, vk::MemoryPropertyFlagBits::eDeviceLocal),
|
||||
};
|
||||
|
||||
auto depth_alloc = dev.allocateMemory(depth_alloc_info);
|
||||
depth_alloc = dev.allocateMemory(depth_alloc_info);
|
||||
dev.bindImageMemory(depth_image, depth_alloc, 0);
|
||||
|
||||
auto depth_view_info = vk::ImageViewCreateInfo {
|
||||
@ -208,29 +206,101 @@ Renderer::Renderer(Window& win) : win(win) {
|
||||
};
|
||||
|
||||
depth_image_view = dev.createImageView(depth_view_info);
|
||||
|
||||
render_fence = dev.createFence(vk::FenceCreateInfo { .flags = vk::FenceCreateFlagBits::eSignaled });
|
||||
|
||||
image_wait_semaphore = dev.createSemaphore(vk::SemaphoreCreateInfo{});
|
||||
render_wait_semaphore = dev.createSemaphore(vk::SemaphoreCreateInfo{});
|
||||
|
||||
render_pass = std::make_unique<RenderPass>(dev);
|
||||
swapchain = std::make_unique<Swapchain>(dev, surface, win.getDimensions(), *render_pass, depth_image_view);
|
||||
|
||||
command_buffer = std::make_unique<CommandBuffer>(dev, queue_family);
|
||||
|
||||
}
|
||||
|
||||
void Renderer::draw() {
|
||||
Log::info("draw() called \n");
|
||||
|
||||
dev.waitForFences(render_fence, true, UINT64_MAX);
|
||||
dev.resetFences(render_fence);
|
||||
|
||||
/* check if the swapchain is still good (no resize) */
|
||||
auto image_ret = dev.acquireNextImageKHR(*swapchain, UINT64_MAX);
|
||||
auto image_ret = dev.acquireNextImageKHR(*swapchain, UINT64_MAX, image_wait_semaphore);
|
||||
if (image_ret.result == vk::Result::eErrorOutOfDateKHR) {
|
||||
swapchain->recreate(win.getDimensions());
|
||||
}
|
||||
|
||||
current_image_idx = image_ret.value;
|
||||
|
||||
/* prepare command buffer for recording commands */
|
||||
command_buffer->recycle();
|
||||
command_buffer->begin();
|
||||
|
||||
vk::ClearValue clear_values[] = {
|
||||
vk::ClearColorValue(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
vk::ClearDepthStencilValue {.depth = 1.0f}
|
||||
};
|
||||
|
||||
/* use renderpass to transform images from unspecified layout to a presentable one while clearing */
|
||||
auto render_pass_info = vk::RenderPassBeginInfo {
|
||||
.renderPass = *render_pass,
|
||||
.framebuffer = swapchain->framebuffers[current_image_idx],
|
||||
.renderArea = {
|
||||
.offset = { 0, 0 },
|
||||
.extent = swapchain->extent,
|
||||
},
|
||||
.clearValueCount = std::size(clear_values),
|
||||
.pClearValues = clear_values,
|
||||
};
|
||||
|
||||
auto viewport = vk::Viewport{
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = static_cast<float>(swapchain->extent.width),
|
||||
.height = static_cast<float>(swapchain->extent.height),
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f,
|
||||
};
|
||||
|
||||
auto scissor = vk::Rect2D{
|
||||
.offset = {0, 0},
|
||||
.extent = swapchain->extent,
|
||||
};
|
||||
|
||||
|
||||
/* no secondary command buffers (yet), so contents are passed inline */
|
||||
command_buffer->command_buffer.beginRenderPass(render_pass_info, vk::SubpassContents::eInline);
|
||||
command_buffer->command_buffer.setViewport(0, viewport);
|
||||
command_buffer->command_buffer.setScissor(0, scissor);
|
||||
command_buffer->command_buffer.endRenderPass();
|
||||
|
||||
command_buffer->end();
|
||||
|
||||
|
||||
vk::PipelineStageFlags stage_flags = vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||
|
||||
/* submit our command buffer to the queue */
|
||||
auto submit_info = vk::SubmitInfo{
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &image_wait_semaphore,
|
||||
.pWaitDstStageMask = &stage_flags,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &command_buffer->command_buffer,
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = &render_wait_semaphore,
|
||||
};
|
||||
|
||||
queue.submit(submit_info, render_fence);
|
||||
}
|
||||
|
||||
void Renderer::present() {
|
||||
Log::info("present() called \n");
|
||||
auto present_info = vk::PresentInfoKHR{
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &render_wait_semaphore,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain->operator vk::SwapchainKHR &(),
|
||||
.pSwapchains = &swapchain->operator vk::SwapchainKHR & (),
|
||||
.pImageIndices = ¤t_image_idx,
|
||||
};
|
||||
|
||||
@ -239,6 +309,7 @@ void Renderer::present() {
|
||||
break;
|
||||
case vk::Result::eSuboptimalKHR:
|
||||
case vk::Result::eErrorOutOfDateKHR:
|
||||
Log::info("Recreating swapchain");
|
||||
swapchain->recreate(win.getDimensions());
|
||||
break;
|
||||
default:
|
||||
@ -250,9 +321,13 @@ void Renderer::present() {
|
||||
Renderer::~Renderer() {
|
||||
dev.destroyImage(depth_image);
|
||||
dev.destroyImageView(depth_image_view);
|
||||
dev.freeMemory(depth_alloc);
|
||||
|
||||
|
||||
swapchain.reset();
|
||||
dev.waitIdle();
|
||||
command_buffer->cleanup(dev);
|
||||
render_pass->cleanup(dev);
|
||||
dev.destroy();
|
||||
instance.destroySurfaceKHR(surface);
|
||||
instance.destroy();
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include <Renderer/Swapchain.hpp>
|
||||
#include <Renderer/CommandBuffer.hpp>
|
||||
#include <Renderer/RenderPass.hpp>
|
||||
|
||||
struct Window;
|
||||
|
||||
@ -23,6 +24,8 @@ struct Renderer {
|
||||
vk::Instance instance;
|
||||
vk::Device dev;
|
||||
|
||||
vk::Fence render_fence;
|
||||
vk::Semaphore image_wait_semaphore, render_wait_semaphore;
|
||||
vk::SurfaceKHR surface;
|
||||
std::unique_ptr<Swapchain> swapchain;
|
||||
|
||||
@ -30,8 +33,11 @@ struct Renderer {
|
||||
vk::Queue queue;
|
||||
|
||||
std::unique_ptr<CommandBuffer> command_buffer;
|
||||
std::unique_ptr<RenderPass> render_pass;
|
||||
|
||||
uint32_t current_image_idx;
|
||||
|
||||
vk::Image depth_image;
|
||||
vk::ImageView depth_image_view;
|
||||
vk::DeviceMemory depth_alloc;
|
||||
};
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
#include <Renderer/Swapchain.hpp>
|
||||
|
||||
Swapchain::Swapchain(vk::Device& dev, const vk::SurfaceKHR& surface, const vk::Extent2D& extent) : dev(dev), surface(surface) {
|
||||
Swapchain::Swapchain(vk::Device& dev, const vk::SurfaceKHR& surface, const vk::Extent2D& extent, RenderPass render_pass, vk::ImageView depth_image_view)
|
||||
: dev(dev), surface(surface), render_pass(render_pass), depth_image_view(depth_image_view) {
|
||||
create(extent);
|
||||
}
|
||||
|
||||
void Swapchain::create(const vk::Extent2D& extent, vk::SwapchainKHR old_swapchain) {
|
||||
this->extent = extent;
|
||||
|
||||
auto format = vk::Format::eB8G8R8A8Unorm;
|
||||
|
||||
@ -33,8 +35,9 @@ void Swapchain::create(const vk::Extent2D& extent, vk::SwapchainKHR old_swapchai
|
||||
|
||||
images = dev.getSwapchainImagesKHR(swapchain);
|
||||
views.resize(images.size());
|
||||
for(size_t i = 0; i < views.size(); i++) {
|
||||
auto color_image_info = vk::ImageViewCreateInfo {
|
||||
framebuffers.resize(images.size());
|
||||
for (size_t i = 0; i < views.size(); i++) {
|
||||
auto color_image_info = vk::ImageViewCreateInfo{
|
||||
.image = images[i],
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = format,
|
||||
@ -52,8 +55,19 @@ void Swapchain::create(const vk::Extent2D& extent, vk::SwapchainKHR old_swapchai
|
||||
.layerCount = 1,
|
||||
}
|
||||
};
|
||||
|
||||
views[i] = dev.createImageView(color_image_info);
|
||||
|
||||
vk::ImageView attachments[] = { views[i], depth_image_view };
|
||||
auto framebuffer_info = vk::FramebufferCreateInfo {
|
||||
.renderPass = render_pass,
|
||||
.attachmentCount = static_cast<uint32_t>(std::size(attachments)),
|
||||
.pAttachments = attachments,
|
||||
.width = extent.width,
|
||||
.height = extent.height,
|
||||
.layers = 1,
|
||||
};
|
||||
|
||||
framebuffers[i] = dev.createFramebuffer(framebuffer_info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,10 +75,12 @@ void Swapchain::create(const vk::Extent2D& extent, vk::SwapchainKHR old_swapchai
|
||||
void Swapchain::recreate(const vk::Extent2D& extent) {
|
||||
dev.waitIdle();
|
||||
cleanup();
|
||||
create(extent);
|
||||
create(extent, swapchain);
|
||||
}
|
||||
|
||||
void Swapchain::cleanup() {
|
||||
for(auto& fb : framebuffers)
|
||||
dev.destroyFramebuffer(fb);
|
||||
dev.destroySwapchainKHR(swapchain);
|
||||
}
|
||||
|
||||
|
||||
@ -3,8 +3,12 @@
|
||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
|
||||
#include <Renderer/RenderPass.hpp>
|
||||
|
||||
|
||||
struct Swapchain {
|
||||
Swapchain(vk::Device& dev, const vk::SurfaceKHR& surface, const vk::Extent2D& extent);
|
||||
Swapchain(vk::Device& dev, const vk::SurfaceKHR& surface, const vk::Extent2D& extent, RenderPass render_pass, vk::ImageView depth_image_view);
|
||||
vk::SwapchainKHR swapchain;
|
||||
inline operator vk::SwapchainKHR& () {
|
||||
return swapchain;
|
||||
@ -14,6 +18,12 @@ struct Swapchain {
|
||||
vk::SurfaceKHR surface;
|
||||
std::vector<vk::Image> images;
|
||||
std::vector<vk::ImageView> views;
|
||||
std::vector<vk::Framebuffer> framebuffers;
|
||||
|
||||
RenderPass render_pass;
|
||||
vk::ImageView depth_image_view;
|
||||
|
||||
vk::Extent2D extent;
|
||||
|
||||
void create(const vk::Extent2D& extent, vk::SwapchainKHR old_swapchain = nullptr);
|
||||
void recreate(const vk::Extent2D& extent);
|
||||
|
||||
@ -3,13 +3,11 @@
|
||||
#include <Renderer/Renderer.hpp>
|
||||
|
||||
#include <util/log.hpp>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
Window win("Test", 256, 512);
|
||||
Window win(argv[0], 256, 512);
|
||||
auto in = win.getInput();
|
||||
Renderer ren(win);
|
||||
|
||||
@ -23,7 +21,6 @@ int main() {
|
||||
switch (event.tag) {
|
||||
case InputEvent::Tag::RESIZE:
|
||||
Log::info("Event Processed: Resized to %dx%d\n", event.resize.width, event.resize.height);
|
||||
win.setDimensions(event.resize.width, event.resize.width);
|
||||
/* no need to have a resize() function in the renderer, b/c swapchain images will be
|
||||
* automatically marked out-of-date, and recreation will be triggered in our code
|
||||
*/
|
||||
@ -36,6 +33,9 @@ int main() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ren.draw();
|
||||
ren.present();
|
||||
}
|
||||
|
||||
} catch (const std::string& e) {
|
||||
|
||||
81
renderer/RenderPass.cpp
Normal file
81
renderer/RenderPass.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include <Renderer/RenderPass.hpp>
|
||||
|
||||
RenderPass::RenderPass(vk::Device dev, vk::Format image_format, vk::Format depth_format) {
|
||||
/* transform color image from UNDEFINED format to presentable one for rendering */
|
||||
auto color_attach_desc = vk::AttachmentDescription {
|
||||
.format = image_format,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
/* since its set to clear, it clears the initial image to the specified
|
||||
clear color instead of loading the data */
|
||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||
/* we care about the data after the end of the renderpass, so store */
|
||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
/* for the depth stencil buffer, we care about neither */
|
||||
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
|
||||
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
.finalLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||
};
|
||||
|
||||
auto color_attach_ref = vk::AttachmentReference { .attachment = 0, .layout = vk::ImageLayout::eColorAttachmentOptimal };
|
||||
|
||||
auto depth_attach_desc = vk::AttachmentDescription{
|
||||
.format = depth_format,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||
.storeOp = vk::AttachmentStoreOp::eDontCare,
|
||||
.stencilLoadOp = vk::AttachmentLoadOp::eClear,
|
||||
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal,
|
||||
};
|
||||
|
||||
auto depth_attach_ref = vk::AttachmentReference{ .attachment = 1, .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal };
|
||||
|
||||
/* only one subpass for now, uses both attachments */
|
||||
auto subpass_desc = vk::SubpassDescription {
|
||||
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
|
||||
.colorAttachmentCount = 1,
|
||||
.pColorAttachments = &color_attach_ref,
|
||||
.pDepthStencilAttachment = &depth_attach_ref,
|
||||
};
|
||||
|
||||
|
||||
/* designates producer and consumer of the image to position subpass */
|
||||
auto color_dep = vk::SubpassDependency{
|
||||
.srcSubpass = vk::SubpassExternal,
|
||||
.dstSubpass = 0,
|
||||
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
.srcAccessMask = vk::AccessFlagBits::eNone,
|
||||
.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
|
||||
};
|
||||
|
||||
auto depth_dep = vk::SubpassDependency {
|
||||
.srcSubpass = vk::SubpassExternal,
|
||||
.dstSubpass = 0,
|
||||
.srcStageMask = vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests,
|
||||
.dstStageMask = vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests,
|
||||
.srcAccessMask = vk::AccessFlagBits::eNone,
|
||||
.dstAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite,
|
||||
};
|
||||
|
||||
vk::AttachmentDescription descs[] = { color_attach_desc, depth_attach_desc };
|
||||
vk::SubpassDependency deps[] = { color_dep, depth_dep};
|
||||
vk::SubpassDescription subpasses[] = {subpass_desc};
|
||||
|
||||
auto pass_info = vk::RenderPassCreateInfo {
|
||||
.attachmentCount = static_cast<uint32_t>(std::size(descs)),
|
||||
.pAttachments = descs,
|
||||
.subpassCount = static_cast<uint32_t>(std::size(subpasses)),
|
||||
.pSubpasses = subpasses,
|
||||
.dependencyCount = static_cast<uint32_t>(std::size(deps)),
|
||||
.pDependencies = deps,
|
||||
};
|
||||
|
||||
render_pass = dev.createRenderPass(pass_info);
|
||||
}
|
||||
|
||||
void RenderPass::cleanup(vk::Device dev) {
|
||||
dev.destroyRenderPass(render_pass);
|
||||
}
|
||||
16
renderer/RenderPass.hpp
Normal file
16
renderer/RenderPass.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
struct RenderPass {
|
||||
vk::RenderPass render_pass;
|
||||
|
||||
RenderPass(vk::Device dev, vk::Format image_format = vk::Format::eB8G8R8A8Unorm, vk::Format depth_format = vk::Format::eD16Unorm);
|
||||
|
||||
void cleanup(vk::Device dev);
|
||||
|
||||
operator vk::RenderPass&() {
|
||||
return render_pass;
|
||||
}
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user