Browse Source

Wrapper around fences and render pass.

master
Draklaw 4 years ago
parent
commit
63a87edc29
  1. 3
      CMakeLists.txt
  2. 10
      src/VulkanTutorial.cpp
  3. 3
      src/VulkanTutorial.h
  4. 11
      src/core/ArrayView.h
  5. 5
      src/core/math.h
  6. 1
      src/vk/Buffer.cpp
  7. 12
      src/vk/Context.cpp
  8. 3
      src/vk/Context.h
  9. 123
      src/vk/Fence.cpp
  10. 69
      src/vk/Fence.h
  11. 63
      src/vk/RenderPass.cpp
  12. 53
      src/vk/RenderPass.h
  13. 44
      src/vk/Swapchain.cpp
  14. 6
      src/vk/Swapchain.h
  15. 4
      src/vk/forward.h

3
CMakeLists.txt

@ -37,9 +37,12 @@ add_executable(vk_expe
src/core/Logger.cpp src/core/Logger.cpp
src/vk/Context.cpp src/vk/Context.cpp
src/vk/Fence.cpp
src/vk/Swapchain.cpp src/vk/Swapchain.cpp
src/vk/Memory.cpp src/vk/Memory.cpp
src/vk/Buffer.cpp src/vk/Buffer.cpp
src/vk/RenderPass.cpp
src/main.cpp src/main.cpp
src/Simplex.cpp src/Simplex.cpp
src/Planet.cpp src/Planet.cpp

10
src/VulkanTutorial.cpp

@ -333,7 +333,7 @@ void VulkanTutorial::destroy_swapchain_objects() {
m_context.destroy_pipeline(m_pipeline); m_context.destroy_pipeline(m_pipeline);
m_context.destroy_pipeline_layout(m_pipeline_layout); 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() { void VulkanTutorial::create_render_pass() {
@ -378,13 +378,7 @@ void VulkanTutorial::create_render_pass() {
.pDependencies = &subpass_dep, .pDependencies = &subpass_dep,
}; };
if(vkCreateRenderPass( m_render_pass = vk::RenderPass(m_context, render_pass_info);
m_context.device(),
&render_pass_info,
nullptr,
&m_render_pass
) != VK_SUCCESS)
throw std::runtime_error("failed to create render pass");
} }
void VulkanTutorial::create_descriptor_set_layout() { void VulkanTutorial::create_descriptor_set_layout() {

3
src/VulkanTutorial.h

@ -4,6 +4,7 @@
#include <vk/Context.h> #include <vk/Context.h>
#include <vk/Swapchain.h> #include <vk/Swapchain.h>
#include <vk/Buffer.h> #include <vk/Buffer.h>
#include <vk/RenderPass.h>
#include <core/math.h> #include <core/math.h>
@ -69,7 +70,7 @@ private:
VkQueue m_graphic_queue = nullptr; VkQueue m_graphic_queue = nullptr;
VkQueue m_presentation_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; VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
VkPipeline m_pipeline = VK_NULL_HANDLE; VkPipeline m_pipeline = VK_NULL_HANDLE;

11
src/core/ArrayView.h

@ -42,12 +42,16 @@ public:
return m_stride; return m_stride;
} }
bool is_dense() const {
return m_stride == sizeof(T);
}
const T* data() const { const T* data() const {
return m_data; return reinterpret_cast<const T*>(m_data);
} }
T* data() { T* data() {
return m_data; return reinterpret_cast<T*>(m_data);
} }
const T& operator[](Index index) const { const T& operator[](Index index) const {
@ -74,6 +78,3 @@ private:
Index m_size = 0; Index m_size = 0;
Index m_stride = sizeof(T); Index m_stride = sizeof(T);
}; };
using Vector3AV = ArrayView<Vector3>;
using TriangleAV = ArrayView<Triangle>;

5
src/core/math.h

@ -3,6 +3,7 @@
#include <core/types.h> #include <core/types.h>
#include <core/ArrayView.h>
#include <Eigen/Dense> #include <Eigen/Dense>
@ -26,6 +27,10 @@ using Quaternion = Eigen::Quaternion<Real>;
using Triangle = Eigen::Array<Index, 3, 1>; using Triangle = Eigen::Array<Index, 3, 1>;
using Vector3AV = ArrayView<Vector3>;
using TriangleAV = ArrayView<Triangle>;
template<typename Scalar, typename Derived0, typename Derived1> template<typename Scalar, typename Derived0, typename Derived1>
auto lerp( auto lerp(
Scalar factor, Scalar factor,

1
src/vk/Buffer.cpp

@ -7,6 +7,7 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstring>
namespace vk { namespace vk {

12
src/vk/Context.cpp

@ -140,7 +140,7 @@ void Context::shutdown() {
m_allocator->free_all_pages(); m_allocator->free_all_pages();
m_allocator.reset(); m_allocator.reset();
destroy_fence(m_transfer_fence); m_transfer_fence.destroy();
destroy_command_pool(m_transfer_command_pool); destroy_command_pool(m_transfer_command_pool);
destroy_device(m_device); destroy_device(m_device);
@ -330,7 +330,7 @@ void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family,
vkEndCommandBuffer(command_buffer); vkEndCommandBuffer(command_buffer);
vkResetFences(m_device, 1, &m_transfer_fence); m_transfer_fence.reset();
VkSubmitInfo submit_info { VkSubmitInfo submit_info {
.sType = VK_STRUCTURE_TYPE_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, 1, &submit_info,
m_transfer_fence 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"); throw std::runtime_error("failed to create command pool");
} }
VkFenceCreateInfo fence_info { m_transfer_fence = Fence(*this);
.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");
} }
void Context::initialize_extension_functions() { void Context::initialize_extension_functions() {

3
src/vk/Context.h

@ -2,6 +2,7 @@
#pragma once #pragma once
#include <vk/forward.h> #include <vk/forward.h>
#include <vk/Fence.h>
#include <core/utils.h> #include <core/utils.h>
#include <core/Logger.h> #include <core/Logger.h>
@ -194,7 +195,7 @@ private:
uint32_t m_transfer_queue_index = UINT32_MAX; uint32_t m_transfer_queue_index = UINT32_MAX;
VkCommandPool m_transfer_command_pool = VK_NULL_HANDLE; 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; std::vector<ContextDestructionCallback> m_context_destruction_callbacks;

123
src/vk/Fence.cpp

@ -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

@ -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

@ -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

@ -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;
};
}

44
src/vk/Swapchain.cpp

@ -84,8 +84,8 @@ VkSemaphore Swapchain::ready_to_render() {
return m_frame_resources[m_frame_resources_index].ready_to_render; return m_frame_resources[m_frame_resources_index].ready_to_render;
} }
VkFence Swapchain::render_done() { Fence& Swapchain::render_done() {
return m_frame_resources[m_frame_resources_index].render_done; return *m_frame_resources[m_frame_resources_index].render_done;
} }
void Swapchain::initialize(const SwapchainSettings& settings) { 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 // 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 // done rendering to not render more that MAX_FRAMES_IN_FLIGHT frames at
// the same time. // the same time.
if(frame_resources.render_done != VK_NULL_HANDLE) { if(frame_resources.render_done) {
vkWaitForFences( frame_resources.render_done->wait();
m_context->device(),
1, &frame_resources.render_done,
VK_TRUE,
UINT64_MAX
);
} }
bool acquired_image = false; bool acquired_image = false;
@ -151,18 +146,13 @@ void Swapchain::begin_frame() {
// In case vkAcquireNextImageKHR doesn't return images in-order, we wait // In case vkAcquireNextImageKHR doesn't return images in-order, we wait
// again to be sure. // again to be sure.
if(image_resources.render_done != VK_NULL_HANDLE) { if(image_resources.render_done != VK_NULL_HANDLE) {
vkWaitForFences( image_resources.render_done.wait();
m_context->device(),
1, &image_resources.render_done,
VK_TRUE,
UINT64_MAX
);
} }
// Remember the right frame to wait for. // 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) { void Swapchain::swap_buffers(Array<VkSemaphore> wait_semaphores) {
@ -297,9 +287,9 @@ void Swapchain::create() {
swapchain_images swapchain_images
); );
m_image_resources.resize(image_count, {});
for(size_t index = 0; index < image_count; index += 1) { 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]; image_resources.image = swapchain_images[index];
@ -332,17 +322,7 @@ void Swapchain::create() {
throw std::runtime_error("failed to create swapchain image view"); throw std::runtime_error("failed to create swapchain image view");
} }
VkFenceCreateInfo fence_info { image_resources.render_done = Fence(*m_context, VK_FENCE_CREATE_SIGNALED_BIT);
.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");
} }
m_frame_resources.resize(MAX_FRAMES_IN_FLIGHT, {}); m_frame_resources.resize(MAX_FRAMES_IN_FLIGHT, {});
@ -374,11 +354,11 @@ void Swapchain::destroy() {
for(auto& frame_resources: m_frame_resources) { for(auto& frame_resources: m_frame_resources) {
m_context->destroy_semaphore(frame_resources.ready_to_render); m_context->destroy_semaphore(frame_resources.ready_to_render);
// This is a reference to an ImageResources.render_done // 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) { 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); m_context->destroy_image_view(image_resources.view);
} }

6
src/vk/Swapchain.h

@ -59,7 +59,7 @@ public:
VkImageView image_view(); VkImageView image_view();
VkImageView image_view(size_t image_index); VkImageView image_view(size_t image_index);
VkSemaphore ready_to_render(); VkSemaphore ready_to_render();
VkFence render_done(); Fence& render_done();
void initialize(const SwapchainSettings& settings); void initialize(const SwapchainSettings& settings);
void shutdown(); void shutdown();
@ -76,12 +76,12 @@ private:
struct ImageResources { struct ImageResources {
VkImage image = VK_NULL_HANDLE; VkImage image = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE; VkImageView view = VK_NULL_HANDLE;
VkFence render_done = VK_NULL_HANDLE; Fence render_done;
}; };
struct FrameResources { struct FrameResources {
VkSemaphore ready_to_render = VK_NULL_HANDLE; VkSemaphore ready_to_render = VK_NULL_HANDLE;
VkFence render_done = VK_NULL_HANDLE; Fence* render_done = nullptr;
}; };
private: private:

4
src/vk/forward.h

@ -15,5 +15,9 @@ using MemoryPageSP = std::shared_ptr<MemoryBlock>;
class Context; class Context;
class ContextSettings; class ContextSettings;
class Buffer;
class RenderPass;
class Fence;
} }
Loading…
Cancel
Save