Skip to content

Commit 3c83f86

Browse files
Merge branch 'feat/tri_renderer' into feat/pipeline_abstraction
2 parents 9413d5e + 334ce57 commit 3c83f86

14 files changed

Lines changed: 200 additions & 83 deletions

include/quark/vk/allocator.hpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#pragma once
2+
3+
#include <quark/utils/raii.hpp>
4+
#include <quark/utils/result.hpp>
5+
#include <quark/vk/device/device_view.hpp>
6+
#include <utility>
7+
#include <vk_mem_alloc.h>
8+
#include <vulkan/vulkan_core.h>
9+
10+
namespace quark::vk {
11+
12+
class Allocator final {
13+
public:
14+
struct CreateInfo {
15+
VkInstance instance{VK_NULL_HANDLE};
16+
DeviceView device{};
17+
const VkAllocationCallbacks *allocation_callbacks{nullptr};
18+
uint32_t vulkan_api_version{VK_API_VERSION_1_0};
19+
};
20+
21+
Allocator() = default;
22+
~Allocator() { destroy(); }
23+
24+
QUARK_NO_COPY(Allocator);
25+
26+
[[nodiscard]] constexpr Allocator(Allocator &&other) noexcept
27+
: allocator_(std::exchange(other.allocator_, nullptr)) {}
28+
29+
[[nodiscard]] constexpr Allocator &operator=(Allocator &&other) noexcept {
30+
if (this == &other) {
31+
return *this;
32+
}
33+
34+
destroy();
35+
allocator_ = std::exchange(other.allocator_, nullptr);
36+
return *this;
37+
}
38+
39+
[[nodiscard]] util::Status create(const CreateInfo &ci);
40+
void destroy() noexcept;
41+
42+
[[nodiscard]] bool valid() const noexcept { return allocator_ != nullptr; }
43+
[[nodiscard]] VmaAllocator handle() const noexcept { return allocator_; }
44+
45+
private:
46+
VmaAllocator allocator_ = nullptr;
47+
};
48+
49+
} // namespace quark::vk

include/quark/vk/buffer.hpp

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#pragma once
22

33
#include <cstddef>
4+
#include <memory>
45

56
#include <quark/utils/raii.hpp>
67
#include <quark/utils/result.hpp>
8+
#include <quark/vk/allocator.hpp>
79
#include <vk_mem_alloc.h>
810
#include <vulkan/vulkan_core.h>
911

@@ -13,62 +15,49 @@ class Buffer final {
1315

1416
public:
1517
struct CreateInfo {
16-
VmaAllocator allocator = nullptr;
18+
const Allocator *allocator = nullptr;
1719
VkDeviceSize size{};
1820
VkBufferUsageFlags usage{};
19-
VmaMemoryUsage memory_usage = VMA_MEMORY_USAGE_AUTO;
21+
VmaMemoryUsage memory_usage{VMA_MEMORY_USAGE_AUTO};
2022
VmaAllocationCreateFlags allocation_flags{};
21-
VkSharingMode sharing_mode = VK_SHARING_MODE_EXCLUSIVE;
23+
VkSharingMode sharing_mode{VK_SHARING_MODE_EXCLUSIVE};
2224
};
2325

2426
Buffer() = default;
2527
~Buffer() { destroy(); }
2628

27-
QUARK_NO_COPY(Buffer); // do we want copy or not?
28-
29-
Buffer(Buffer &&other) noexcept
30-
: allocator_(other.allocator_), buffer_(other.buffer_),
31-
allocation_(other.allocation_), size_(other.size_) {
32-
other.allocator_ = nullptr;
33-
other.buffer_ = VK_NULL_HANDLE;
34-
other.allocation_ = nullptr;
35-
other.size_ = 0;
36-
}
37-
38-
Buffer &operator=(Buffer &&other) noexcept {
39-
if (this == &other) {
40-
return *this;
41-
}
42-
43-
this->destroy();
44-
allocator_ = other.allocator_;
45-
buffer_ = other.buffer_;
46-
allocation_ = other.allocation_;
47-
size_ = other.size_;
48-
49-
other.allocator_ = nullptr;
50-
other.buffer_ = VK_NULL_HANDLE;
51-
other.allocation_ = nullptr;
52-
other.size_ = 0;
53-
return *this;
54-
}
29+
QUARK_MOVE_ONLY(Buffer);
5530

5631
util::Status create(const CreateInfo &ci);
5732
void destroy() noexcept;
5833

5934
util::Status upload(const void *src, size_t byte_count,
6035
VkDeviceSize offset = 0);
6136

62-
[[nodiscard]] bool valid() noexcept { return buffer_ != VK_NULL_HANDLE; }
37+
[[nodiscard]] bool valid() noexcept {
38+
return state_ != nullptr && state_->buffer != VK_NULL_HANDLE;
39+
}
6340

64-
[[nodiscard]] VkBuffer handle() const noexcept { return buffer_; }
65-
[[nodiscard]] VkDeviceSize size() const noexcept { return size_; }
41+
[[nodiscard]] VkBuffer handle() const noexcept {
42+
return state_ == nullptr ? VK_NULL_HANDLE : state_->buffer;
43+
}
44+
[[nodiscard]] VkDeviceSize size() const noexcept {
45+
return state_ == nullptr ? 0 : state_->size;
46+
}
6647

6748
private:
68-
VmaAllocator allocator_{nullptr};
69-
VkBuffer buffer_{VK_NULL_HANDLE};
70-
VmaAllocation allocation_{nullptr};
71-
VkDeviceSize size_{};
49+
struct State {
50+
VmaAllocator allocator{nullptr};
51+
VkBuffer buffer{VK_NULL_HANDLE};
52+
VmaAllocation allocation{nullptr};
53+
VkDeviceSize size{};
54+
};
55+
56+
struct StateDeleter {
57+
void operator()(State *state) const noexcept;
58+
};
59+
60+
std::unique_ptr<State, StateDeleter> state_;
7261
};
7362

7463
} // namespace quark::vk

include/quark/vk/device/details/device.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
#include <cstdint>
44
#include <quark/utils/raii.hpp>
55
#include <quark/utils/result.hpp>
6+
#include <quark/vk/allocator.hpp>
67
#include <quark/vk/device/details/device_capabilities.hpp>
78
#include <vector>
8-
#include <vk_mem_alloc.h>
99
#include <vulkan/vulkan_core.h>
1010

1111
namespace quark::vk::details {
@@ -65,10 +65,14 @@ class Device final {
6565
return capabilities_;
6666
}
6767

68-
[[nodiscard]] VmaAllocator vma_allocator() const noexcept {
68+
[[nodiscard]] const Allocator &allocator() const noexcept {
6969
return allocator_;
7070
}
7171

72+
[[nodiscard]] VmaAllocator vma_allocator() const noexcept {
73+
return allocator_.handle();
74+
}
75+
7276
private:
7377
struct DeviceSelection {
7478
VkPhysicalDevice physical_device{VK_NULL_HANDLE};
@@ -106,7 +110,7 @@ class Device final {
106110
uint32_t graphics_queue_family_index_ = 0;
107111
uint32_t present_queue_family_index_ = 0;
108112
const VkAllocationCallbacks *alloc_ = nullptr;
109-
VmaAllocator allocator_ = nullptr;
113+
Allocator allocator_;
110114
DeviceCapabilities capabilities_{};
111115
};
112116

include/quark/vk/device/device_bundle.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <quark/utils/raii.hpp>
44
#include <quark/utils/result.hpp>
5+
#include <quark/vk/allocator.hpp>
56
#include <quark/vk/device/details/device.hpp>
67
#include <quark/vk/device/details/device_capabilities.hpp>
78
#include <vulkan/vulkan_core.h>
@@ -35,6 +36,7 @@ class DeviceBundle final {
3536
[[nodiscard]] uint32_t graphics_queue_family_index() const noexcept;
3637
[[nodiscard]] uint32_t present_queue_family_index() const noexcept;
3738
[[nodiscard]] details::DeviceCapabilities capabilities() const noexcept;
39+
[[nodiscard]] const Allocator &allocator() const noexcept;
3840
[[nodiscard]] VmaAllocator vma_allocator() const noexcept;
3941

4042
private:

include/quark/vk/triangle_renderer.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
#include <quark/platform/shader/details/shader_registry.hpp>
77
#include <quark/utils/raii.hpp>
88
#include <quark/utils/result.hpp>
9+
#include <quark/vk/allocator.hpp>
910
#include <quark/vk/device/device_view.hpp>
1011
#include <quark/vk/pipeline/graphics_pipeline_desc.hpp>
1112
#include <quark/vk/triangle_vertex_buffer.hpp>
12-
#include <vk_mem_alloc.h>
1313
#include <vulkan/vulkan_core.h>
1414

1515
namespace quark::vk {
@@ -18,7 +18,7 @@ class TriangleRenderer final {
1818
public:
1919
struct CreateInfo {
2020
DeviceView device{};
21-
VmaAllocator allocator = nullptr;
21+
const Allocator *allocator = nullptr;
2222
RetirementQueue *retire_queue = nullptr;
2323
VkExtent2D extent{};
2424
VkFormat color_format{VK_FORMAT_UNDEFINED};

include/quark/vk/triangle_vertex_buffer.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <quark/utils/raii.hpp>
66
#include <quark/utils/result.hpp>
7+
#include <quark/vk/allocator.hpp>
78
#include <quark/vk/buffer.hpp>
89

910
namespace quark::vk {
@@ -15,7 +16,7 @@ class TriangleVertexBuffer final {
1516

1617
QUARK_NO_COPY_NO_MOVE(TriangleVertexBuffer);
1718

18-
util::Status create(VmaAllocator allocator);
19+
util::Status create(const Allocator &allocator);
1920
void destroy() noexcept;
2021

2122
void bind(VkCommandBuffer command_buffer) const noexcept;

src/backend/vulkan/device/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_library(
22
quark_backend_vulkan_device STATIC
3+
allocator.cpp
34
device.cpp
45
device_feature_chain_builder.cpp
56
device_bundle.cpp
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <quark/vk/allocator.hpp>
2+
#include <quark/vk/diagnostic_prelude.hpp>
3+
4+
namespace quark::vk {
5+
6+
util::Status Allocator::create(const Allocator::CreateInfo &ci) {
7+
destroy();
8+
9+
QUARK_ENSURE(
10+
ci.instance != VK_NULL_HANDLE,
11+
QUARK_ERR(util::Errc::InvalidArg, "Allocator instance must be valid"));
12+
QUARK_ENSURE(ci.device.physical_device != VK_NULL_HANDLE,
13+
QUARK_ERR(util::Errc::InvalidArg,
14+
"Allocator physical device must be valid"));
15+
QUARK_ENSURE(ci.device.device != VK_NULL_HANDLE,
16+
QUARK_ERR(util::Errc::InvalidArg,
17+
"Allocator logical device must be valid"));
18+
19+
const VmaAllocatorCreateInfo allocator_info{
20+
.flags = 0,
21+
.physicalDevice = ci.device.physical_device,
22+
.device = ci.device.device,
23+
.preferredLargeHeapBlockSize = 0,
24+
.pAllocationCallbacks = ci.allocation_callbacks,
25+
.pDeviceMemoryCallbacks = nullptr,
26+
.pHeapSizeLimit = nullptr,
27+
.pVulkanFunctions = nullptr,
28+
.instance = ci.instance,
29+
.vulkanApiVersion = ci.vulkan_api_version,
30+
#if VMA_EXTERNAL_MEMORY
31+
.pTypeExternalMemoryHandleTypes = nullptr,
32+
#endif
33+
};
34+
35+
QUARK_VK_TRY(vmaCreateAllocator(&allocator_info, &allocator_));
36+
37+
QUARK_OK();
38+
}
39+
40+
void Allocator::destroy() noexcept {
41+
if (allocator_ == nullptr) {
42+
return;
43+
}
44+
45+
vmaDestroyAllocator(allocator_);
46+
allocator_ = nullptr;
47+
}
48+
49+
} // namespace quark::vk

src/backend/vulkan/device/buffer.cpp

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,34 @@
77

88
namespace quark::vk {
99

10+
void Buffer::StateDeleter::operator()(State *state) const noexcept {
11+
if (state == nullptr) {
12+
return;
13+
}
14+
15+
if (state->allocator != nullptr && state->buffer != VK_NULL_HANDLE &&
16+
state->allocation != nullptr) {
17+
vmaDestroyBuffer(state->allocator, state->buffer, state->allocation);
18+
}
19+
20+
delete state;
21+
}
22+
1023
util::Status Buffer::create(const Buffer::CreateInfo &ci) {
1124
destroy();
1225

1326
QUARK_ENSURE(ci.allocator != nullptr,
1427
QUARK_ERR(util::Errc::InvalidArg, "Buffer allocator is null"));
28+
QUARK_ENSURE(
29+
ci.allocator->valid(),
30+
QUARK_ERR(util::Errc::InvalidArg, "Buffer allocator is not created"));
1531
QUARK_ENSURE(ci.size > 0,
1632
QUARK_ERR(util::Errc::InvalidArg, "Buffer size must be > 0"));
1733
QUARK_ENSURE(ci.usage != 0,
1834
QUARK_ERR(util::Errc::InvalidArg, "Buffer usage must be set"));
1935

36+
VmaAllocator allocator = ci.allocator->handle();
37+
2038
VkBufferCreateInfo buffer_info{};
2139
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
2240
buffer_info.size = ci.size;
@@ -27,45 +45,40 @@ util::Status Buffer::create(const Buffer::CreateInfo &ci) {
2745
alloc_info.usage = ci.memory_usage;
2846
alloc_info.flags = ci.allocation_flags;
2947

30-
QUARK_VK_TRY(vmaCreateBuffer(ci.allocator, &buffer_info, &alloc_info,
31-
&buffer_, &allocation_, nullptr));
48+
auto state = std::unique_ptr<State, StateDeleter>(new State{});
49+
state->allocator = allocator;
3250

33-
allocator_ = ci.allocator;
34-
size_ = ci.size;
35-
QUARK_OK();
36-
}
51+
QUARK_VK_TRY(vmaCreateBuffer(allocator, &buffer_info, &alloc_info,
52+
&state->buffer, &state->allocation, nullptr));
3753

38-
void Buffer::destroy() noexcept {
39-
if (allocator_ != nullptr && buffer_ != VK_NULL_HANDLE &&
40-
allocation_ != nullptr) {
41-
vmaDestroyBuffer(allocator_, buffer_, allocation_);
42-
}
54+
state->size = ci.size;
55+
state_ = std::move(state);
4356

44-
allocator_ = nullptr;
45-
buffer_ = VK_NULL_HANDLE;
46-
allocation_ = nullptr;
47-
size_ = 0;
57+
QUARK_OK();
4858
}
4959

60+
void Buffer::destroy() noexcept { state_.reset(); }
61+
5062
util::Status Buffer::upload(const void *src, size_t byte_count,
5163
VkDeviceSize offset) {
5264
QUARK_ENSURE(valid(),
5365
QUARK_ERR(util::Errc::InvalidState, "Buffer is not created"));
5466
QUARK_ENSURE(src != nullptr,
5567
QUARK_ERR(util::Errc::InvalidArg, "Upload source is null"));
56-
QUARK_ENSURE(offset <= size_, QUARK_ERR(util::Errc::InvalidArg,
57-
"Upload offset exceeds buffer size"));
68+
QUARK_ENSURE(
69+
offset <= state_->size,
70+
QUARK_ERR(util::Errc::InvalidArg, "Upload offset exceeds buffer size"));
5871
QUARK_ENSURE(byte_count <= (std::numeric_limits<VkDeviceSize>::max)(),
5972
QUARK_ERR(util::Errc::InvalidArg,
6073
"Upload byte_count exceeds VkDeviceSize"));
6174

6275
const VkDeviceSize copy_size = static_cast<VkDeviceSize>(byte_count);
6376
QUARK_ENSURE(
64-
copy_size <= (size_ - offset),
77+
copy_size <= (state_->size - offset),
6578
QUARK_ERR(util::Errc::InvalidArg, "Upload range exceeds buffer size"));
6679

67-
QUARK_VK_TRY(vmaCopyMemoryToAllocation(allocator_, src, allocation_, offset,
68-
copy_size));
80+
QUARK_VK_TRY(vmaCopyMemoryToAllocation(
81+
state_->allocator, src, state_->allocation, offset, copy_size));
6982
QUARK_OK();
7083
}
7184

0 commit comments

Comments
 (0)