Wrapper around fences and render pass.
This commit is contained in:
@@ -333,7 +333,7 @@ void VulkanTutorial::destroy_swapchain_objects() {
|
||||
|
||||
m_context.destroy_pipeline(m_pipeline);
|
||||
m_context.destroy_pipeline_layout(m_pipeline_layout);
|
||||
m_context.destroy_render_pass(m_render_pass);
|
||||
m_render_pass.destroy();
|
||||
}
|
||||
|
||||
void VulkanTutorial::create_render_pass() {
|
||||
@@ -378,13 +378,7 @@ void VulkanTutorial::create_render_pass() {
|
||||
.pDependencies = &subpass_dep,
|
||||
};
|
||||
|
||||
if(vkCreateRenderPass(
|
||||
m_context.device(),
|
||||
&render_pass_info,
|
||||
nullptr,
|
||||
&m_render_pass
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to create render pass");
|
||||
m_render_pass = vk::RenderPass(m_context, render_pass_info);
|
||||
}
|
||||
|
||||
void VulkanTutorial::create_descriptor_set_layout() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vk/Context.h>
|
||||
#include <vk/Swapchain.h>
|
||||
#include <vk/Buffer.h>
|
||||
#include <vk/RenderPass.h>
|
||||
|
||||
#include <core/math.h>
|
||||
|
||||
@@ -69,7 +70,7 @@ private:
|
||||
VkQueue m_graphic_queue = nullptr;
|
||||
VkQueue m_presentation_queue = nullptr;
|
||||
|
||||
VkRenderPass m_render_pass = VK_NULL_HANDLE;
|
||||
vk::RenderPass m_render_pass;
|
||||
VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
|
||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
||||
|
||||
@@ -42,12 +42,16 @@ public:
|
||||
return m_stride;
|
||||
}
|
||||
|
||||
bool is_dense() const {
|
||||
return m_stride == sizeof(T);
|
||||
}
|
||||
|
||||
const T* data() const {
|
||||
return m_data;
|
||||
return reinterpret_cast<const T*>(m_data);
|
||||
}
|
||||
|
||||
T* data() {
|
||||
return m_data;
|
||||
return reinterpret_cast<T*>(m_data);
|
||||
}
|
||||
|
||||
const T& operator[](Index index) const {
|
||||
@@ -74,6 +78,3 @@ private:
|
||||
Index m_size = 0;
|
||||
Index m_stride = sizeof(T);
|
||||
};
|
||||
|
||||
using Vector3AV = ArrayView<Vector3>;
|
||||
using TriangleAV = ArrayView<Triangle>;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <core/types.h>
|
||||
#include <core/ArrayView.h>
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
@@ -26,6 +27,10 @@ using Quaternion = Eigen::Quaternion<Real>;
|
||||
using Triangle = Eigen::Array<Index, 3, 1>;
|
||||
|
||||
|
||||
using Vector3AV = ArrayView<Vector3>;
|
||||
using TriangleAV = ArrayView<Triangle>;
|
||||
|
||||
|
||||
template<typename Scalar, typename Derived0, typename Derived1>
|
||||
auto lerp(
|
||||
Scalar factor,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace vk {
|
||||
|
||||
@@ -140,7 +140,7 @@ void Context::shutdown() {
|
||||
m_allocator->free_all_pages();
|
||||
m_allocator.reset();
|
||||
|
||||
destroy_fence(m_transfer_fence);
|
||||
m_transfer_fence.destroy();
|
||||
destroy_command_pool(m_transfer_command_pool);
|
||||
|
||||
destroy_device(m_device);
|
||||
@@ -330,7 +330,7 @@ void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family,
|
||||
|
||||
vkEndCommandBuffer(command_buffer);
|
||||
|
||||
vkResetFences(m_device, 1, &m_transfer_fence);
|
||||
m_transfer_fence.reset();
|
||||
|
||||
VkSubmitInfo submit_info {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
@@ -342,7 +342,7 @@ void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family,
|
||||
1, &submit_info,
|
||||
m_transfer_fence
|
||||
);
|
||||
vkWaitForFences(m_device, 1, &m_transfer_fence, VK_TRUE, UINT64_MAX);
|
||||
m_transfer_fence.wait();
|
||||
}
|
||||
|
||||
|
||||
@@ -790,11 +790,7 @@ void Context::create_internal_objects() {
|
||||
throw std::runtime_error("failed to create command pool");
|
||||
}
|
||||
|
||||
VkFenceCreateInfo fence_info {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
};
|
||||
if(vkCreateFence(m_device, &fence_info, nullptr, &m_transfer_fence) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to create fence");
|
||||
m_transfer_fence = Fence(*this);
|
||||
}
|
||||
|
||||
void Context::initialize_extension_functions() {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vk/forward.h>
|
||||
#include <vk/Fence.h>
|
||||
|
||||
#include <core/utils.h>
|
||||
#include <core/Logger.h>
|
||||
@@ -194,7 +195,7 @@ private:
|
||||
|
||||
uint32_t m_transfer_queue_index = UINT32_MAX;
|
||||
VkCommandPool m_transfer_command_pool = VK_NULL_HANDLE;
|
||||
VkFence m_transfer_fence = VK_NULL_HANDLE;
|
||||
Fence m_transfer_fence;
|
||||
|
||||
std::vector<ContextDestructionCallback> m_context_destruction_callbacks;
|
||||
|
||||
|
||||
123
src/vk/Fence.cpp
Normal file
123
src/vk/Fence.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
|
||||
#include <vk/Fence.h>
|
||||
#include <vk/Context.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace vk {
|
||||
|
||||
|
||||
Fence::Fence() noexcept {
|
||||
}
|
||||
|
||||
Fence::Fence(Context& context, VkFenceCreateFlags flags)
|
||||
: m_context(&context)
|
||||
{
|
||||
assert(m_context);
|
||||
|
||||
VkFenceCreateInfo create_info {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = flags,
|
||||
};
|
||||
if(vkCreateFence(
|
||||
context.device(),
|
||||
&create_info,
|
||||
nullptr,
|
||||
&m_fence
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to create fence");
|
||||
}
|
||||
|
||||
Fence::Fence(Fence&& other) noexcept
|
||||
{
|
||||
swap(*this, other);
|
||||
}
|
||||
|
||||
Fence::~Fence() noexcept {
|
||||
if(is_valid())
|
||||
destroy();
|
||||
}
|
||||
|
||||
|
||||
Fence& Fence::operator=(Fence&& other) noexcept {
|
||||
swap(*this, other);
|
||||
if(other)
|
||||
other.destroy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
VkResult Fence::get_status() const {
|
||||
assert(m_context);
|
||||
assert(is_valid());
|
||||
|
||||
VkResult result = vkGetFenceStatus(
|
||||
m_context->device(),
|
||||
m_fence
|
||||
);
|
||||
|
||||
if(result < 0)
|
||||
throw std::runtime_error("failed to get fence status");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Fence::reset() {
|
||||
assert(m_context);
|
||||
assert(is_valid());
|
||||
|
||||
if(vkResetFences(
|
||||
m_context->device(),
|
||||
1,
|
||||
&m_fence
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to reset fence");
|
||||
}
|
||||
|
||||
void Fence::wait(uint64_t timeout) const {
|
||||
assert(m_context);
|
||||
assert(is_valid());
|
||||
|
||||
wait_for_fences(
|
||||
m_context->device(),
|
||||
ArrayView<VkFence>(1, const_cast<VkFence*>(&m_fence)),
|
||||
true,
|
||||
timeout
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void Fence::destroy() noexcept {
|
||||
assert(is_valid());
|
||||
assert(m_context);
|
||||
|
||||
vkDestroyFence(
|
||||
m_context->device(),
|
||||
m_fence,
|
||||
nullptr
|
||||
);
|
||||
|
||||
m_fence = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void wait_for_fences(VkDevice device, ArrayView<VkFence> fences, bool wait_all, uint64_t timeout) {
|
||||
assert(fences.is_dense());
|
||||
|
||||
if(fences.size() == 0)
|
||||
return;
|
||||
|
||||
if(vkWaitForFences(
|
||||
device,
|
||||
fences.size(),
|
||||
fences.data(),
|
||||
wait_all,
|
||||
timeout
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to wait for fences");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
69
src/vk/Fence.h
Normal file
69
src/vk/Fence.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
#pragma once
|
||||
|
||||
#include <core/ArrayView.h>
|
||||
|
||||
#include <vk/forward.h>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
|
||||
namespace vk {
|
||||
|
||||
|
||||
class Fence {
|
||||
public:
|
||||
Fence() noexcept;
|
||||
Fence(Context& context, VkFenceCreateFlags flags=0);
|
||||
Fence(const Fence&) = delete;
|
||||
Fence(Fence&& other) noexcept;
|
||||
~Fence() noexcept;
|
||||
|
||||
Fence& operator=(const Fence&) = delete;
|
||||
Fence& operator=(Fence&& other) noexcept;
|
||||
|
||||
explicit inline operator bool() const noexcept {
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
inline bool is_valid() const noexcept {
|
||||
return m_fence != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline const Context* context() const noexcept {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
inline Context* context() noexcept {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
inline operator VkFence() noexcept {
|
||||
return m_fence;
|
||||
}
|
||||
|
||||
inline VkFence fence() noexcept {
|
||||
return m_fence;
|
||||
}
|
||||
|
||||
VkResult get_status() const;
|
||||
void reset();
|
||||
void wait(uint64_t timeout=UINT64_MAX) const;
|
||||
|
||||
friend inline void swap(Fence& fence_0, Fence& fence_1) noexcept {
|
||||
using std::swap;
|
||||
swap(fence_0.m_context, fence_1.m_context);
|
||||
swap(fence_0.m_fence, fence_1.m_fence);
|
||||
}
|
||||
|
||||
void destroy() noexcept;
|
||||
|
||||
private:
|
||||
Context* m_context = nullptr;
|
||||
VkFence m_fence = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
void wait_for_fences(VkDevice device, ArrayView<VkFence> fences, bool wait_all=true, uint64_t timeout=UINT64_MAX);
|
||||
|
||||
|
||||
}
|
||||
63
src/vk/RenderPass.cpp
Normal file
63
src/vk/RenderPass.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
|
||||
#include <vk/RenderPass.h>
|
||||
#include <vk/Context.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace vk {
|
||||
|
||||
|
||||
RenderPass::RenderPass() noexcept {
|
||||
}
|
||||
|
||||
RenderPass::RenderPass(Context& context, const VkRenderPassCreateInfo& create_info)
|
||||
: m_context(&context)
|
||||
{
|
||||
assert(m_context);
|
||||
|
||||
if(vkCreateRenderPass(
|
||||
context.device(),
|
||||
&create_info,
|
||||
nullptr,
|
||||
&m_render_pass
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to create render pass");
|
||||
}
|
||||
|
||||
RenderPass::RenderPass(RenderPass&& other) noexcept
|
||||
{
|
||||
swap(*this, other);
|
||||
}
|
||||
|
||||
RenderPass::~RenderPass() noexcept {
|
||||
if(is_valid())
|
||||
destroy();
|
||||
}
|
||||
|
||||
|
||||
RenderPass& RenderPass::operator=(RenderPass&& other) noexcept {
|
||||
swap(*this, other);
|
||||
if(other)
|
||||
other.destroy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void RenderPass::destroy() noexcept {
|
||||
assert(is_valid());
|
||||
assert(m_context);
|
||||
|
||||
vkDestroyRenderPass(
|
||||
m_context->device(),
|
||||
m_render_pass,
|
||||
nullptr
|
||||
);
|
||||
|
||||
m_render_pass = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
53
src/vk/RenderPass.h
Normal file
53
src/vk/RenderPass.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
#pragma once
|
||||
|
||||
#include <vk/forward.h>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
|
||||
namespace vk {
|
||||
|
||||
|
||||
class RenderPass {
|
||||
public:
|
||||
RenderPass() noexcept;
|
||||
RenderPass(Context& context, const VkRenderPassCreateInfo& create_info);
|
||||
RenderPass(const RenderPass&) = delete;
|
||||
RenderPass(RenderPass&& other) noexcept;
|
||||
~RenderPass() noexcept;
|
||||
|
||||
RenderPass& operator=(const RenderPass&) = delete;
|
||||
RenderPass& operator=(RenderPass&& other) noexcept;
|
||||
|
||||
explicit inline operator bool() const noexcept {
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
inline bool is_valid() const noexcept {
|
||||
return m_render_pass != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline operator VkRenderPass() noexcept {
|
||||
return m_render_pass;
|
||||
}
|
||||
|
||||
inline VkRenderPass render_pass() noexcept {
|
||||
return m_render_pass;
|
||||
}
|
||||
|
||||
friend inline void swap(RenderPass& render_pass_0, RenderPass& render_pass_1) noexcept {
|
||||
using std::swap;
|
||||
swap(render_pass_0.m_context, render_pass_1.m_context);
|
||||
swap(render_pass_0.m_render_pass, render_pass_1.m_render_pass);
|
||||
}
|
||||
|
||||
void destroy() noexcept;
|
||||
|
||||
private:
|
||||
Context* m_context = nullptr;
|
||||
VkRenderPass m_render_pass = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -84,8 +84,8 @@ VkSemaphore Swapchain::ready_to_render() {
|
||||
return m_frame_resources[m_frame_resources_index].ready_to_render;
|
||||
}
|
||||
|
||||
VkFence Swapchain::render_done() {
|
||||
return m_frame_resources[m_frame_resources_index].render_done;
|
||||
Fence& Swapchain::render_done() {
|
||||
return *m_frame_resources[m_frame_resources_index].render_done;
|
||||
}
|
||||
|
||||
void Swapchain::initialize(const SwapchainSettings& settings) {
|
||||
@@ -112,13 +112,8 @@ void Swapchain::begin_frame() {
|
||||
// frame_resources are used cyclically. We wait for the current one to be
|
||||
// done rendering to not render more that MAX_FRAMES_IN_FLIGHT frames at
|
||||
// the same time.
|
||||
if(frame_resources.render_done != VK_NULL_HANDLE) {
|
||||
vkWaitForFences(
|
||||
m_context->device(),
|
||||
1, &frame_resources.render_done,
|
||||
VK_TRUE,
|
||||
UINT64_MAX
|
||||
);
|
||||
if(frame_resources.render_done) {
|
||||
frame_resources.render_done->wait();
|
||||
}
|
||||
|
||||
bool acquired_image = false;
|
||||
@@ -151,18 +146,13 @@ void Swapchain::begin_frame() {
|
||||
// In case vkAcquireNextImageKHR doesn't return images in-order, we wait
|
||||
// again to be sure.
|
||||
if(image_resources.render_done != VK_NULL_HANDLE) {
|
||||
vkWaitForFences(
|
||||
m_context->device(),
|
||||
1, &image_resources.render_done,
|
||||
VK_TRUE,
|
||||
UINT64_MAX
|
||||
);
|
||||
image_resources.render_done.wait();
|
||||
}
|
||||
|
||||
// Remember the right frame to wait for.
|
||||
frame_resources.render_done = image_resources.render_done;
|
||||
frame_resources.render_done = &image_resources.render_done;
|
||||
|
||||
vkResetFences(m_context->device(), 1, &frame_resources.render_done);
|
||||
frame_resources.render_done->reset();
|
||||
}
|
||||
|
||||
void Swapchain::swap_buffers(Array<VkSemaphore> wait_semaphores) {
|
||||
@@ -297,9 +287,9 @@ void Swapchain::create() {
|
||||
swapchain_images
|
||||
);
|
||||
|
||||
m_image_resources.resize(image_count, {});
|
||||
for(size_t index = 0; index < image_count; index += 1) {
|
||||
auto& image_resources = m_image_resources[index];
|
||||
m_image_resources.emplace_back();
|
||||
auto& image_resources = m_image_resources.back();
|
||||
|
||||
image_resources.image = swapchain_images[index];
|
||||
|
||||
@@ -332,17 +322,7 @@ void Swapchain::create() {
|
||||
throw std::runtime_error("failed to create swapchain image view");
|
||||
}
|
||||
|
||||
VkFenceCreateInfo fence_info {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
|
||||
};
|
||||
if(vkCreateFence(
|
||||
m_context->device(),
|
||||
&fence_info,
|
||||
nullptr,
|
||||
&image_resources.render_done
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to create fence");
|
||||
image_resources.render_done = Fence(*m_context, VK_FENCE_CREATE_SIGNALED_BIT);
|
||||
}
|
||||
|
||||
m_frame_resources.resize(MAX_FRAMES_IN_FLIGHT, {});
|
||||
@@ -374,11 +354,11 @@ void Swapchain::destroy() {
|
||||
for(auto& frame_resources: m_frame_resources) {
|
||||
m_context->destroy_semaphore(frame_resources.ready_to_render);
|
||||
// This is a reference to an ImageResources.render_done
|
||||
frame_resources.render_done = VK_NULL_HANDLE;
|
||||
frame_resources.render_done = nullptr;
|
||||
}
|
||||
|
||||
for(auto& image_resources: m_image_resources) {
|
||||
m_context->destroy_fence(image_resources.render_done);
|
||||
image_resources.render_done.destroy();
|
||||
m_context->destroy_image_view(image_resources.view);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
VkImageView image_view();
|
||||
VkImageView image_view(size_t image_index);
|
||||
VkSemaphore ready_to_render();
|
||||
VkFence render_done();
|
||||
Fence& render_done();
|
||||
|
||||
void initialize(const SwapchainSettings& settings);
|
||||
void shutdown();
|
||||
@@ -76,12 +76,12 @@ private:
|
||||
struct ImageResources {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
VkFence render_done = VK_NULL_HANDLE;
|
||||
Fence render_done;
|
||||
};
|
||||
|
||||
struct FrameResources {
|
||||
VkSemaphore ready_to_render = VK_NULL_HANDLE;
|
||||
VkFence render_done = VK_NULL_HANDLE;
|
||||
Fence* render_done = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -15,5 +15,9 @@ using MemoryPageSP = std::shared_ptr<MemoryBlock>;
|
||||
class Context;
|
||||
class ContextSettings;
|
||||
|
||||
class Buffer;
|
||||
class RenderPass;
|
||||
class Fence;
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user