wip: convert from include style to module import style :D
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
This commit is contained in:
parent
273f1e2006
commit
3c0dcb672e
71 changed files with 2222 additions and 1815 deletions
|
|
@ -1,26 +1,27 @@
|
|||
add_library_module(
|
||||
NAME
|
||||
renderer
|
||||
system.cpp
|
||||
# Vulkan - backend
|
||||
backend/vk/messenger.cpp
|
||||
backend/vk/context/device.cpp
|
||||
backend/vk/context/gpu.cpp
|
||||
backend/vk/context/instance.cpp
|
||||
backend/vk/context/surface.cpp
|
||||
backend/vk/context/swapchain.cpp
|
||||
backend/vk/data/buffer.cpp
|
||||
backend/vk/renderer/pass.cpp
|
||||
backend/vk/renderer/renderer.cpp
|
||||
# frontend
|
||||
frontend/messenger.cpp
|
||||
frontend/context/device.cpp
|
||||
frontend/context/gpu.cpp
|
||||
frontend/context/instance.cpp
|
||||
frontend/context/surface.cpp
|
||||
frontend/context/swapchain.cpp
|
||||
frontend/data/buffer.cpp
|
||||
frontend/renderer/renderer.cpp
|
||||
frontend/renderer/pass.cpp)
|
||||
INTERFACES
|
||||
# system.cppm Vulkan - backend
|
||||
api.cppm
|
||||
# backends/vk/messenger.cppm
|
||||
backends/factory.cppm
|
||||
# backends/vk/library_loader.cppm
|
||||
backends/vk/library_wrapper.cppm
|
||||
backends/vk/context/device.cppm
|
||||
backends/vk/context/gpu.cppm
|
||||
backends/vk/context/instance.cppm
|
||||
backends/vk/context/surface.cppm
|
||||
# backends/vk/context/swapchain.cppm backends/vk/data/buffer.cppm
|
||||
# backends/vk/renderer/pass.cppm backends/vk/renderer/renderer.cppm frontend
|
||||
# frontend/messenger.cppm
|
||||
frontend/context/device.cppm
|
||||
frontend/context/gpu.cppm
|
||||
frontend/context/instance.cppm
|
||||
frontend/context/surface.cppm
|
||||
# frontend/context/swapchain.cppm frontend/data/buffer.cppm
|
||||
# frontend/renderer/renderer.cppm frontend/renderer/pass.cppm
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
renderer
|
||||
|
|
@ -33,6 +34,8 @@ target_link_libraries(
|
|||
camera
|
||||
PRIVATE surface pthread)
|
||||
|
||||
return()
|
||||
|
||||
add_test_module(
|
||||
renderer
|
||||
test/utils.cpp
|
||||
|
|
|
|||
14
modules/renderer/api.cppm
Normal file
14
modules/renderer/api.cppm
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export module renderer.api;
|
||||
import std;
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
export enum class Api: std::uint8_t {
|
||||
none = 0u,
|
||||
|
||||
vulkan,
|
||||
direct_x,
|
||||
metal,
|
||||
};
|
||||
|
||||
}
|
||||
85
modules/renderer/backends/factory.cppm
Normal file
85
modules/renderer/backends/factory.cppm
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
export module renderer.backend.factory;
|
||||
import memory.scope;
|
||||
import renderer.frontend.device;
|
||||
import renderer.backend.vk.device;
|
||||
import debug.assertions;
|
||||
import ecs.entity;
|
||||
import renderer.backend.vk.instance;
|
||||
import renderer.backend.vk.gpu;
|
||||
import renderer.backend.vk.surface;
|
||||
import renderer.frontend.instance;
|
||||
import renderer.frontend.surface;
|
||||
import renderer.frontend.gpu;
|
||||
import renderer.api;
|
||||
import std;
|
||||
|
||||
export namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] auto get_instance(Api target_api) -> IInstance *;
|
||||
|
||||
[[nodiscard]] auto create_surface(
|
||||
Api target_api,
|
||||
IInstance *instance,
|
||||
const ecs::Entity &surface_entity
|
||||
);
|
||||
|
||||
[[nodiscard]] auto create_gpu(Api target_api, IInstance *instance) -> memory::Scope<IGpu>;
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
||||
module :private;
|
||||
using namespace lt;
|
||||
using namespace lt::renderer;
|
||||
|
||||
[[nodiscard]] auto get_instance(Api target_api) -> IInstance *
|
||||
{
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return vkb::Instance::get();
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto create_surface(
|
||||
Api target_api,
|
||||
class IInstance *instance,
|
||||
const lt::ecs::Entity &surface_entity
|
||||
) -> memory::Scope<ISurface>
|
||||
{
|
||||
debug::ensure(instance, "Failed to create renderer::ISurface: null instance");
|
||||
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vkb::Surface>(instance, surface_entity);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto create_gpu(Api target_api, IInstance *instance) -> memory::Scope<IGpu>
|
||||
{
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vkb::Gpu>(instance);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto create_device(Api target_api, IGpu *gpu, ISurface *surface)
|
||||
-> memory::Scope<IDevice>
|
||||
{
|
||||
debug::ensure(gpu, "Failed to create renderer::IDevice: null gpu");
|
||||
debug::ensure(surface, "Failed to create renderer::IDevice: null surface");
|
||||
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vkb::Device>(gpu, surface);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
|
|
@ -1,3 +1,252 @@
|
|||
export module renderer.backend.vk.device;
|
||||
|
||||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/frontend/context/device.hpp>
|
||||
#include <renderer/frontend/context/gpu.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Device: public IDevice
|
||||
{
|
||||
public:
|
||||
Device(IGpu *gpu, ISurface *surface);
|
||||
[[nodiscard]] auto vk() const -> VkDevice
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_family_indices() const -> std::array<uint32_t, 2>
|
||||
{
|
||||
return { m_graphics_queue_family_index, m_present_queue_family_index };
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_graphics_queue() const -> VkQueue
|
||||
{
|
||||
return m_graphics_queue;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_present_queue() const -> VkQueue
|
||||
{
|
||||
return m_present_queue;
|
||||
}
|
||||
|
||||
/** utilities */
|
||||
template<typename T, typename... Args>
|
||||
void name(const T &object, std::format_string<Args...> fmt, Args &&...args)
|
||||
{
|
||||
const auto name = std::format(fmt, std::forward<Args>(args)...);
|
||||
auto info = VkDebugUtilsObjectNameInfoEXT {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = get_object_type(object),
|
||||
.objectHandle = (uint64_t)(object),
|
||||
.pObjectName = name.c_str(),
|
||||
};
|
||||
|
||||
vk_set_debug_object_name(m_device, &info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void name(const T &object, const char *name)
|
||||
{
|
||||
auto info = VkDebugUtilsObjectNameInfoEXT {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = get_object_type(object),
|
||||
.objectHandle = (uint64_t)(object),
|
||||
.pObjectName = name,
|
||||
};
|
||||
|
||||
vk_set_debug_object_name(m_device, &info);
|
||||
}
|
||||
|
||||
|
||||
/** work functions */
|
||||
void submit(VkSubmitInfo info, VkFence fence) const;
|
||||
|
||||
void present(VkPresentInfoKHR info) const;
|
||||
|
||||
void wait_idle() const;
|
||||
|
||||
void wait_for_fence(VkFence fence) const;
|
||||
|
||||
void wait_for_fences(std::span<VkFence> fences) const;
|
||||
|
||||
void reset_fence(VkFence fence) const;
|
||||
|
||||
void reset_fences(std::span<VkFence> fences) const;
|
||||
|
||||
/** getter functions */
|
||||
[[nodiscard]] auto acquire_image(
|
||||
VkSwapchainKHR swapchain,
|
||||
VkSemaphore semaphore,
|
||||
uint64_t timeout = 100'000'000
|
||||
) -> std::optional<uint32_t>;
|
||||
|
||||
[[nodiscard]] auto get_swapchain_images(VkSwapchainKHR swapchain) const -> std::vector<VkImage>;
|
||||
|
||||
[[nodiscard]] auto get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements;
|
||||
|
||||
/** binders / mappers */
|
||||
void bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset = 0u) const;
|
||||
|
||||
[[nodiscard]] auto map_memory(VkDeviceMemory memory, size_t size, size_t offset) const
|
||||
-> std::span<std::byte>;
|
||||
|
||||
void unmap_memory(VkDeviceMemory memory);
|
||||
|
||||
/** create functions */
|
||||
[[nodiscard]] auto create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR;
|
||||
|
||||
[[nodiscard]] auto create_framebuffer(VkFramebufferCreateInfo info) const -> VkFramebuffer;
|
||||
|
||||
[[nodiscard]] auto create_image_view(VkImageViewCreateInfo info) const -> VkImageView;
|
||||
|
||||
[[nodiscard]] auto create_graphics_pipeline(VkGraphicsPipelineCreateInfo info) const
|
||||
-> VkPipeline;
|
||||
|
||||
[[nodiscard]] auto create_pass(VkRenderPassCreateInfo info) const -> VkRenderPass;
|
||||
|
||||
[[nodiscard]] auto create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> descriptor_set_layout,
|
||||
std::vector<VkPushConstantRange> push_constant_ranges
|
||||
) const -> VkPipelineLayout;
|
||||
|
||||
[[nodiscard]] auto create_shader_module(VkShaderModuleCreateInfo info) const -> VkShaderModule;
|
||||
|
||||
[[nodiscard]] auto create_command_pool(VkCommandPoolCreateInfo info) const -> VkCommandPool;
|
||||
|
||||
[[nodiscard]] auto create_semaphores(uint32_t count) const -> std::vector<VkSemaphore>;
|
||||
|
||||
[[nodiscard]] auto create_fences(VkFenceCreateInfo info, uint32_t count) const
|
||||
-> std::vector<VkFence>;
|
||||
|
||||
[[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer;
|
||||
|
||||
[[nodiscard]] auto create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const
|
||||
-> VkDescriptorSetLayout;
|
||||
|
||||
[[nodiscard]] auto create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const
|
||||
-> VkDescriptorPool;
|
||||
|
||||
/** allocation functions */
|
||||
[[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory;
|
||||
|
||||
[[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const
|
||||
-> std::vector<VkCommandBuffer>;
|
||||
|
||||
[[nodiscard]] auto allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const
|
||||
-> VkDescriptorSet;
|
||||
|
||||
/** de-allocation functions */
|
||||
void free_memory(VkDeviceMemory memory) const;
|
||||
|
||||
void free_descriptor_set(
|
||||
VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const;
|
||||
|
||||
/** destroy functions */
|
||||
void destroy_swapchain(VkSwapchainKHR swapchain) const;
|
||||
|
||||
void destroy_framebuffer(VkFramebuffer framebuffer) const;
|
||||
|
||||
void destroy_framebuffers(std::span<VkFramebuffer> framebuffers) const;
|
||||
|
||||
void destroy_image_view(VkImageView image_view) const;
|
||||
|
||||
void destroy_image_views(std::span<VkImageView> image_views) const;
|
||||
|
||||
void destroy_pipeline(VkPipeline pipeline) const;
|
||||
|
||||
void destroy_pass(VkRenderPass pass) const;
|
||||
|
||||
void destroy_pipeline_layout(VkPipelineLayout pipeline_layout) const;
|
||||
|
||||
void destroy_shader_module(VkShaderModule shader_module) const;
|
||||
|
||||
void destroy_command_pool(VkCommandPool command_pool) const;
|
||||
|
||||
void destroy_semaphore(VkSemaphore semaphore) const;
|
||||
|
||||
void destroy_semaphores(std::span<VkSemaphore> semaphores) const;
|
||||
|
||||
void destroy_fence(VkFence fence) const;
|
||||
|
||||
void destroy_fences(std::span<VkFence> fences) const;
|
||||
|
||||
void destroy_buffer(VkBuffer buffer) const;
|
||||
|
||||
void destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const;
|
||||
|
||||
void destroy_descriptor_pool(VkDescriptorPool pool) const;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static auto get_object_type(const T &object) -> VkObjectType
|
||||
{
|
||||
std::ignore = object;
|
||||
|
||||
if constexpr (std::is_same_v<T, VkQueue>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_QUEUE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkFence>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_FENCE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkSemaphore>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_SEMAPHORE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkSwapchainKHR>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_SWAPCHAIN_KHR;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkImage>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_IMAGE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkImageView>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_IMAGE_VIEW;
|
||||
}
|
||||
|
||||
static_assert("invalid type");
|
||||
}
|
||||
|
||||
|
||||
void initialize_physical_device();
|
||||
|
||||
void initialize_logical_device();
|
||||
|
||||
void initialize_queue_indices();
|
||||
|
||||
[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
|
||||
|
||||
vk::Gpu m_gpu {};
|
||||
|
||||
vk::Surface *m_surface {};
|
||||
|
||||
vk::Device m_device;
|
||||
|
||||
vk::Queue m_graphics_queue;
|
||||
|
||||
vk::Queue m_present_queue;
|
||||
|
||||
std::uint32_t m_graphics_queue_family_index = vk::constants::queue_family_ignored;
|
||||
|
||||
std::uint32_t m_present_queue_family_index = vk::constants::queue_family_ignored;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
||||
|
||||
//
|
||||
#include <logger/logger.hpp>
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
|
|
@ -58,7 +307,6 @@ void Device::initialize_logical_device()
|
|||
const float priorities = .0f;
|
||||
|
||||
auto queue_infos = std::vector<VkDeviceQueueCreateInfo> {};
|
||||
auto queue_families = std::set { m_graphics_queue_family_index, m_present_queue_family_index };
|
||||
|
||||
for (auto queue_family : queue_families)
|
||||
{
|
||||
|
|
@ -81,91 +329,25 @@ void Device::initialize_logical_device()
|
|||
};
|
||||
|
||||
auto descriptor_indexing_features = m_gpu->get_descriptor_indexing_features();
|
||||
log::debug("");
|
||||
|
||||
log::debug(
|
||||
"shaderInputAttachmentArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderInputAttachmentArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformTexelBufferArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformTexelBufferArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageTexelBufferArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageTexelBufferArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderSampledImageArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageImageArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageImageArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderInputAttachmentArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderInputAttachmentArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformTexelBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformTexelBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageTexelBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageTexelBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUniformBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingUniformBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingSampledImageUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageImageUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageImageUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUniformTexelBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingUniformTexelBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageTexelBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageTexelBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUpdateUnusedWhilePending: {}",
|
||||
descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingPartiallyBound: {}",
|
||||
descriptor_indexing_features.descriptorBindingPartiallyBound
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingVariableDescriptorCount: {}",
|
||||
descriptor_indexing_features.descriptorBindingVariableDescriptorCount
|
||||
);
|
||||
log::debug(" runtimeDescriptorArray: {}", descriptor_indexing_features.runtimeDescriptorArray);
|
||||
const auto dynamic_rendering_features = VkPhysicalDeviceDynamicRenderingFeatures {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
|
||||
.pNext = &descriptor_indexing_features,
|
||||
.dynamicRendering = true,
|
||||
};
|
||||
|
||||
auto queue_indices = std::set { m_graphics_queue_family_index, m_present_queue_family_index };
|
||||
m_device = vk::Device(
|
||||
vk::Device::CreateInfo {
|
||||
.queue_indices = queue_indices,
|
||||
.extensions = {
|
||||
vk::constants::device_extension_names::swapchain,
|
||||
vk::constants::device_extension_names::dynamic_rendering,
|
||||
vk::constants::device_extension_names::descriptor_indexing,
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
m_device = m_gpu->create_device(
|
||||
VkDeviceCreateInfo {
|
||||
|
|
@ -185,18 +367,18 @@ void Device::initialize_queue_indices()
|
|||
auto properties = m_gpu->get_queue_family_properties();
|
||||
for (auto idx = uint32_t { 0u }; const auto &property : properties)
|
||||
{
|
||||
if (property.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
if (property.queue_flags & vk::QueueFlags::graphics_bit)
|
||||
{
|
||||
m_graphics_queue_family_index = idx;
|
||||
}
|
||||
|
||||
if (m_gpu->queue_family_supports_presentation(m_surface->vk(), idx))
|
||||
if (m_gpu->queue_family_supports_surface(m_surface->vk(), idx))
|
||||
{
|
||||
m_present_queue_family_index = idx;
|
||||
}
|
||||
|
||||
if (m_graphics_queue_family_index != VK_QUEUE_FAMILY_IGNORED
|
||||
&& m_present_queue_family_index != VK_QUEUE_FAMILY_IGNORED)
|
||||
if (m_graphics_queue_family_index != vk::constants::queue_family_ignored
|
||||
&& m_present_queue_family_index != vk::constants::queue_family_ignored)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -204,13 +386,13 @@ void Device::initialize_queue_indices()
|
|||
++idx;
|
||||
}
|
||||
|
||||
ensure(
|
||||
m_graphics_queue_family_index != VK_QUEUE_FAMILY_IGNORED,
|
||||
debug::ensure(
|
||||
m_graphics_queue_family_index != vk::constants::queue_family_ignored,
|
||||
"Failed to find graphics queue family"
|
||||
);
|
||||
|
||||
ensure(
|
||||
m_present_queue_family_index != VK_QUEUE_FAMILY_IGNORED,
|
||||
debug::ensure(
|
||||
m_present_queue_family_index != vk::constants::queue_family_ignored,
|
||||
"Failed to find presentation queue family"
|
||||
);
|
||||
}
|
||||
125
modules/renderer/backends/vk/context/gpu.cppm
Normal file
125
modules/renderer/backends/vk/context/gpu.cppm
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
export module renderer.backend.vk.gpu;
|
||||
import renderer.backend.vk.library_wrapper;
|
||||
import debug.assertions;
|
||||
import renderer.frontend.instance;
|
||||
import renderer.frontend.gpu;
|
||||
import renderer.backend.vk.instance;
|
||||
import memory.null_on_move;
|
||||
import std;
|
||||
|
||||
namespace lt::renderer::vkb {
|
||||
|
||||
export class Gpu: public IGpu
|
||||
{
|
||||
public:
|
||||
Gpu(IInstance *instance);
|
||||
|
||||
// [[nodiscard]] auto queue_family_supports_presentation(
|
||||
// VkSurfaceKHR surface,
|
||||
// uint32_t queue_family_idx
|
||||
// ) -> bool;
|
||||
//
|
||||
// [[nodiscard]] auto get_surface_capabilities(VkSurfaceKHR surface) const
|
||||
// -> VkSurfaceCapabilitiesKHR;
|
||||
//
|
||||
// [[nodiscard]] auto get_surface_formats(VkSurfaceKHR surface) const
|
||||
// -> std::vector<VkSurfaceFormatKHR>;
|
||||
//
|
||||
// [[nodiscard]] auto get_properties() const -> VkPhysicalDeviceProperties
|
||||
// {
|
||||
// return m_properties;
|
||||
// }
|
||||
//
|
||||
// [[nodiscard]] auto get_descriptor_indexing_features() const
|
||||
// -> VkPhysicalDeviceDescriptorIndexingFeatures
|
||||
// {
|
||||
// return m_descriptor_indexing_features;
|
||||
// }
|
||||
//
|
||||
// [[nodiscard]] auto get_memory_properties() const -> VkPhysicalDeviceMemoryProperties
|
||||
// {
|
||||
// return m_memory_properties;
|
||||
// }
|
||||
//
|
||||
// [[nodiscard]] auto get_queue_family_properties() const ->
|
||||
// std::vector<VkQueueFamilyProperties>
|
||||
// {
|
||||
// return m_queue_family_properties;
|
||||
// }
|
||||
|
||||
private:
|
||||
vk::Gpu m_gpu;
|
||||
|
||||
vk::Gpu::Properties m_properties {};
|
||||
|
||||
// VkPhysicalDeviceDescriptorIndexingFeatures m_descriptor_indexing_features;
|
||||
|
||||
vk::Gpu::MemoryProperties m_memory_properties {};
|
||||
|
||||
std::vector<vk::Gpu::QueueFamilyProperties> m_queue_family_properties;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vkb
|
||||
|
||||
|
||||
module :private;
|
||||
using namespace lt::renderer::vkb;
|
||||
|
||||
Gpu::Gpu(IInstance *instance)
|
||||
{
|
||||
auto gpus = vk::Gpu::enumerate(static_cast<Instance *>(instance)->vk());
|
||||
|
||||
for (auto &gpu : gpus)
|
||||
{
|
||||
auto properties = gpu.get_properties();
|
||||
auto features = gpu.get_features();
|
||||
|
||||
if (properties.device_type == vk::Gpu::Type::discrete_gpu && features.geometry_shader)
|
||||
{
|
||||
m_gpu = gpu;
|
||||
}
|
||||
}
|
||||
|
||||
debug::ensure(m_gpu, "Failed to find any suitable Vulkan physical device");
|
||||
|
||||
m_memory_properties = m_gpu.get_memory_properties();
|
||||
m_queue_family_properties = m_gpu.get_queue_family_properties();
|
||||
}
|
||||
|
||||
// [[nodiscard]] auto Gpu::queue_family_supports_presentation(
|
||||
// VkSurfaceKHR surface,
|
||||
// uint32_t queue_family_idx
|
||||
// ) -> bool
|
||||
// {
|
||||
// auto supported = VkBool32 { false };
|
||||
// vkc(vk_get_physical_device_surface_support(m_gpu, queue_family_idx, surface, &supported));
|
||||
//
|
||||
// return supported;
|
||||
// }
|
||||
//
|
||||
// [[nodiscard]] auto Gpu::get_surface_capabilities(VkSurfaceKHR surface) const
|
||||
// -> VkSurfaceCapabilitiesKHR
|
||||
// {
|
||||
// auto capabilities = VkSurfaceCapabilitiesKHR {};
|
||||
// vkc(vk_get_physical_device_surface_capabilities(m_gpu, surface, &capabilities));
|
||||
// return capabilities;
|
||||
// }
|
||||
//
|
||||
// [[nodiscard]] auto Gpu::get_surface_formats(VkSurfaceKHR surface) const
|
||||
// -> std::vector<VkSurfaceFormatKHR>
|
||||
// {
|
||||
// auto count = uint32_t { 0u };
|
||||
// vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, nullptr));
|
||||
//
|
||||
// auto formats = std::vector<VkSurfaceFormatKHR>(count);
|
||||
// vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, formats.data()));
|
||||
//
|
||||
// return formats;
|
||||
// }
|
||||
|
||||
// [[nodiscard]] auto Gpu::create_device(VkDeviceCreateInfo info) const -> VkDevice
|
||||
// {
|
||||
// auto *device = VkDevice {};
|
||||
// vkc(vk_create_device(m_gpu, &info, nullptr, &device));
|
||||
// return device;
|
||||
// }
|
||||
149
modules/renderer/backends/vk/context/instance.cppm
Normal file
149
modules/renderer/backends/vk/context/instance.cppm
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
export module renderer.backend.vk.instance;
|
||||
import debug.assertions;
|
||||
import renderer.frontend.instance;
|
||||
import renderer.backend.vk.library_wrapper;
|
||||
// import renderer.backend.vk.library_loader;
|
||||
import std;
|
||||
|
||||
namespace lt::renderer::vkb {
|
||||
|
||||
/**
|
||||
* Responsible for dynamically loading Vulkan library/functions.
|
||||
*
|
||||
* @note: The delayed vkInstance destruction is due to a work-around for a libx11 quirk:
|
||||
* @ref:
|
||||
* https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/commit/0017308648b6bf8eef10ef0ffb9470576c0c2e9e
|
||||
* https://www.xfree86.org/4.7.0/DRI11.html
|
||||
* https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/1894
|
||||
*/
|
||||
export class Instance: public IInstance
|
||||
{
|
||||
public:
|
||||
static auto get() -> IInstance *
|
||||
{
|
||||
return &Instance::instance();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto vk() -> vk::Instance &
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
// /* create functions */
|
||||
// [[nodiscard]] auto create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const ->
|
||||
// VkSurfaceKHR;
|
||||
//
|
||||
// [[nodiscard]] auto create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const
|
||||
// -> VkDebugUtilsMessengerEXT;
|
||||
//
|
||||
// /* destroy functions */
|
||||
// void destroy_surface(VkSurfaceKHR surface) const;
|
||||
//
|
||||
// void destroy_messenger(VkDebugUtilsMessengerEXT messenger) const;
|
||||
//
|
||||
// [[nodiscard]] auto enumerate_gpus() const -> std::vector<VkPhysicalDevice>;
|
||||
|
||||
private:
|
||||
static auto instance() -> IInstance &
|
||||
{
|
||||
static auto instance = Instance {};
|
||||
return instance;
|
||||
}
|
||||
|
||||
Instance();
|
||||
|
||||
vk::Instance m_instance;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vkb
|
||||
|
||||
module :private;
|
||||
using namespace lt::renderer::vkb;
|
||||
|
||||
Instance::Instance()
|
||||
{
|
||||
vk::load_library();
|
||||
vk::load_global_functions();
|
||||
|
||||
const auto app_info = vk::ApplicationInfo {
|
||||
.name = "Hallo Hallo Hallo :3",
|
||||
.version = vk::constants::application_version,
|
||||
.engine_name = vk::constants::engine_name,
|
||||
.engine_version = vk::constants::engine_version,
|
||||
.api_version = vk::constants::api_version,
|
||||
};
|
||||
|
||||
using Setting = vk::Instance::Layer::Setting;
|
||||
const auto validation_layer_settings = std::vector<Setting> {
|
||||
Setting { .name = "validate_core", .values = true },
|
||||
Setting { .name = "validate_sync", .values = true },
|
||||
Setting { .name = "thread_safety", .values = true },
|
||||
Setting { .name = "debug_action", .values = true },
|
||||
Setting { .name = "enable_message_limit", .values = true },
|
||||
Setting {
|
||||
.name = "duplicate_message_limit",
|
||||
.values = std::numeric_limits<std::uint32_t>::max(),
|
||||
},
|
||||
Setting {
|
||||
.name = "report_flags",
|
||||
.values = std::vector<const char *> { "info", "warn", "perf", "error", "verbose" },
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
using Layer = vk::Instance::Layer;
|
||||
m_instance = vk::Instance(
|
||||
vk::Instance::CreateInfo {
|
||||
.application_info = app_info,
|
||||
.layers = std::vector<Layer> { Layer {
|
||||
.name = vk::instance_layer_names::validation,
|
||||
.settings = validation_layer_settings,
|
||||
} },
|
||||
.extensions = {
|
||||
vk::instance_extension_names::debug_utils,
|
||||
vk::instance_extension_names::surface,
|
||||
vk::instance_extension_names::xlib_surface,
|
||||
vk::instance_extension_names::physical_device_properties_2,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
m_instance.load_functions();
|
||||
}
|
||||
|
||||
// auto Instance::enumerate_gpus() const -> std::vector<VkPhysicalDevice>
|
||||
// {
|
||||
// auto count = 0u;
|
||||
// vkc(vk_enumerate_physical_devices(m_instance, &count, nullptr));
|
||||
// debug::ensure(count != 0u, "Failed to find any gpus with Vulkan support");
|
||||
//
|
||||
// auto gpus = std::vector<VkPhysicalDevice>(count);
|
||||
// vkc(vk_enumerate_physical_devices(m_instance, &count, gpus.data()));
|
||||
// return gpus;
|
||||
// }
|
||||
//
|
||||
// auto Instance::create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const -> VkSurfaceKHR
|
||||
// {
|
||||
// auto *value = VkSurfaceKHR {};
|
||||
// vk_create_xlib_surface_khr(m_instance, &info, m_allocator, &value);
|
||||
//
|
||||
// return value;
|
||||
// }
|
||||
//
|
||||
// [[nodiscard]] auto Instance::create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const
|
||||
// -> VkDebugUtilsMessengerEXT
|
||||
// {
|
||||
// auto *messenger = VkDebugUtilsMessengerEXT {};
|
||||
// vkc(vk_create_debug_messenger(m_instance, &info, m_allocator, &messenger));
|
||||
// return messenger;
|
||||
// }
|
||||
//
|
||||
// void Instance::destroy_surface(VkSurfaceKHR surface) const
|
||||
// {
|
||||
// vk_destroy_surface_khr(m_instance, surface, m_allocator);
|
||||
// }
|
||||
//
|
||||
// void Instance::destroy_messenger(VkDebugUtilsMessengerEXT messenger) const
|
||||
// {
|
||||
// vk_destroy_debug_messenger(m_instance, messenger, m_allocator);
|
||||
// }
|
||||
64
modules/renderer/backends/vk/context/surface.cppm
Normal file
64
modules/renderer/backends/vk/context/surface.cppm
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
export module renderer.backend.vk.surface;
|
||||
import debug.assertions;
|
||||
import ecs.entity;
|
||||
import ecs.registry;
|
||||
import memory.null_on_move;
|
||||
import math.vec2;
|
||||
import surface.system;
|
||||
import renderer.frontend.instance;
|
||||
import renderer.backend.vk.instance;
|
||||
import renderer.frontend.surface;
|
||||
import renderer.backend.vk.library_wrapper;
|
||||
|
||||
namespace lt::renderer::vkb {
|
||||
|
||||
export class Surface: public ISurface
|
||||
{
|
||||
public:
|
||||
Surface(IInstance *instance, const ecs::Entity &surface_entity);
|
||||
|
||||
[[nodiscard]] auto vk() -> vk::Surface &
|
||||
{
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_framebuffer_size() const -> math::uvec2 override;
|
||||
|
||||
private:
|
||||
vk::Surface m_surface;
|
||||
|
||||
ecs::Entity m_surface_entity;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vkb
|
||||
|
||||
module :private;
|
||||
using namespace lt::renderer::vkb;
|
||||
|
||||
Surface::Surface(IInstance *instance, const ecs::Entity &surface_entity)
|
||||
: m_surface_entity(surface_entity)
|
||||
{
|
||||
const auto &component = surface_entity.get<surface::SurfaceComponent>();
|
||||
|
||||
debug::ensure(
|
||||
component.get_native_data().display,
|
||||
"Failed to initialize vk::Surface: null x-display"
|
||||
);
|
||||
debug::ensure(
|
||||
component.get_native_data().window,
|
||||
"Failed to initialize vk::Surface: null x-window"
|
||||
);
|
||||
|
||||
m_surface = vk::Surface(
|
||||
static_cast<Instance *>(instance)->vk(),
|
||||
vk::Surface::XlibCreateInfo {
|
||||
.display = component.get_native_data().display,
|
||||
.window = component.get_native_data().window,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Surface::get_framebuffer_size() const -> math::uvec2
|
||||
{
|
||||
return m_surface_entity.get<surface::SurfaceComponent>().get_resolution();
|
||||
}
|
||||
|
|
@ -1,3 +1,93 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/utils.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/frontend/context/device.hpp>
|
||||
#include <renderer/frontend/context/gpu.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
#include <renderer/frontend/context/swapchain.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Swapchain: public ISwapchain
|
||||
{
|
||||
public:
|
||||
Swapchain(ISurface *surface, IGpu *gpu, IDevice *device);
|
||||
~Swapchain() override;
|
||||
|
||||
Swapchain(Swapchain &&) = default;
|
||||
|
||||
Swapchain(const Swapchain &) = delete;
|
||||
|
||||
auto operator=(Swapchain &&) -> Swapchain & = default;
|
||||
|
||||
auto operator=(const Swapchain &) const -> Swapchain & = delete;
|
||||
|
||||
[[nodiscard]] auto vk() const -> VkSwapchainKHR
|
||||
{
|
||||
return m_swapchain;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto vk_ptr() -> VkSwapchainKHR *
|
||||
{
|
||||
return &m_swapchain;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_resolution() const -> VkExtent2D
|
||||
{
|
||||
return m_resolution;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_format() const -> VkFormat
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image_count() const -> size_t
|
||||
{
|
||||
return m_images.size();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image_view(uint32_t idx) -> VkImageView
|
||||
{
|
||||
return m_image_views[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image(uint32_t idx) -> VkImage
|
||||
{
|
||||
return m_images[idx];
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const
|
||||
-> std::vector<VkFramebuffer>;
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto get_optimal_image_count(
|
||||
VkSurfaceCapabilitiesKHR capabilities,
|
||||
uint32_t desired_image_count
|
||||
) const -> uint32_t;
|
||||
|
||||
memory::NullOnMove<class Surface *> m_surface {};
|
||||
|
||||
class Gpu *m_gpu {};
|
||||
|
||||
class Device *m_device {};
|
||||
|
||||
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<VkImage> m_images;
|
||||
|
||||
std::vector<VkImageView> m_image_views;
|
||||
|
||||
VkExtent2D m_resolution {};
|
||||
|
||||
VkFormat m_format {};
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
||||
#include <logger/logger.hpp>
|
||||
#include <ranges>
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
|
|
@ -1,3 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <renderer/backend/vk/raii/raii.hpp>
|
||||
#include <renderer/frontend/data/buffer.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Buffer: public IBuffer
|
||||
{
|
||||
public:
|
||||
Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info);
|
||||
|
||||
[[nodiscard]] auto map() -> std::span<std::byte> override;
|
||||
|
||||
void unmap() override;
|
||||
|
||||
// TODO(Light): this is to make copying possible.
|
||||
// But it should be removed in the future,
|
||||
// Right now it's not possible because: buffers can't understand CommandBuffers.
|
||||
// And I'm not sure how to properly abstract over command buffers,
|
||||
// before using other APIs...
|
||||
[[nodiscard]] auto vk()
|
||||
{
|
||||
return *m_buffer;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const -> size_t override
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo;
|
||||
|
||||
[[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags;
|
||||
|
||||
[[nodiscard]] auto to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags;
|
||||
|
||||
|
||||
[[nodiscard]] auto has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const
|
||||
-> bool;
|
||||
|
||||
[[nodiscard]] auto has_required_memory_properties(
|
||||
uint32_t required_properties,
|
||||
uint32_t property_flags
|
||||
) const -> bool;
|
||||
|
||||
Device *m_device {};
|
||||
|
||||
Gpu *m_gpu {};
|
||||
|
||||
raii::Buffer m_buffer;
|
||||
|
||||
raii::Memory m_memory;
|
||||
|
||||
// TODO(Light): should this reflect the allocation size instead?
|
||||
size_t m_size {};
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
||||
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
#include <renderer/backend/vk/data/buffer.hpp>
|
||||
951
modules/renderer/backends/vk/library_wrapper.cppm
Normal file
951
modules/renderer/backends/vk/library_wrapper.cppm
Normal file
|
|
@ -0,0 +1,951 @@
|
|||
module;
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <vulkan/vulkan_xlib.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#error "Unsupported platform"
|
||||
#elif defined(__unix__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
export module renderer.backend.vk.library_wrapper;
|
||||
import memory.null_on_move;
|
||||
import math.vec3;
|
||||
import debug.assertions;
|
||||
import std;
|
||||
|
||||
template<class... Ts>
|
||||
struct overloads: Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
|
||||
export namespace lt::renderer::vk {
|
||||
|
||||
using Bool32 = VkBool32;
|
||||
|
||||
namespace constants {
|
||||
|
||||
constexpr auto application_version = VK_MAKE_VERSION(1, 0, 0);
|
||||
constexpr auto engine_version = VK_MAKE_VERSION(1, 0, 0);
|
||||
constexpr auto api_version = VK_API_VERSION_1_4;
|
||||
constexpr auto engine_name = std::string_view { "light_engine_vulkan_renderer" };
|
||||
|
||||
constexpr auto max_physical_device_name = VK_MAX_PHYSICAL_DEVICE_NAME_SIZE;
|
||||
constexpr auto max_memory_types = VK_MAX_MEMORY_TYPES;
|
||||
constexpr auto max_memory_heaps = VK_MAX_MEMORY_HEAPS;
|
||||
constexpr auto uuid_size = VK_UUID_SIZE;
|
||||
|
||||
} // namespace constants
|
||||
|
||||
|
||||
namespace instance_layer_names {
|
||||
|
||||
constexpr auto validation = "VK_LAYER_KHRONOS_validation";
|
||||
|
||||
}
|
||||
|
||||
namespace instance_extension_names {
|
||||
|
||||
constexpr auto debug_utils = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
|
||||
constexpr auto surface = VK_KHR_SURFACE_EXTENSION_NAME;
|
||||
constexpr auto xlib_surface = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
|
||||
constexpr auto physical_device_properties_2
|
||||
= VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
|
||||
|
||||
} // namespace instance_extension_names
|
||||
|
||||
namespace device_extension_names {
|
||||
|
||||
constexpr auto xlib_surface = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
|
||||
constexpr auto swapchain = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
|
||||
constexpr auto dynamic_rendering = VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME;
|
||||
constexpr auto descriptor_indexing = VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME;
|
||||
|
||||
}; // namespace device_extension_names
|
||||
|
||||
|
||||
void load_library();
|
||||
|
||||
void unload_library();
|
||||
|
||||
void load_global_functions();
|
||||
|
||||
void load_device_functions(VkDevice device);
|
||||
|
||||
using Version_T = uint32_t;
|
||||
|
||||
struct ApplicationInfo
|
||||
{
|
||||
std::string_view name;
|
||||
|
||||
Version_T version;
|
||||
|
||||
std::string_view engine_name;
|
||||
|
||||
Version_T engine_version;
|
||||
|
||||
Version_T api_version;
|
||||
};
|
||||
|
||||
namespace QueueFlags {
|
||||
enum T : std::underlying_type_t<VkQueueFlagBits> // NOLINT
|
||||
{
|
||||
graphics_bit = VK_QUEUE_GRAPHICS_BIT,
|
||||
compute_bit = VK_QUEUE_COMPUTE_BIT,
|
||||
transfer_bit = VK_QUEUE_TRANSFER_BIT,
|
||||
sparse_binding_bit = VK_QUEUE_SPARSE_BINDING_BIT,
|
||||
protected_bit = VK_QUEUE_PROTECTED_BIT,
|
||||
video_decode_bit_khr = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
|
||||
video_encode_bit_khr = VK_QUEUE_VIDEO_ENCODE_BIT_KHR,
|
||||
optical_flow_bit_nv = VK_QUEUE_OPTICAL_FLOW_BIT_NV,
|
||||
};
|
||||
}
|
||||
|
||||
namespace MemoryHeapFlags {
|
||||
enum T : std::underlying_type_t<VkMemoryHeapFlagBits> // NOLINT
|
||||
{
|
||||
|
||||
device_local_bit = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
|
||||
multi_instance_bit = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT,
|
||||
tile_memory_bit = VK_MEMORY_HEAP_TILE_MEMORY_BIT_QCOM,
|
||||
};
|
||||
};
|
||||
|
||||
namespace MemoryPropertyFlags {
|
||||
enum T : std::underlying_type_t<VkMemoryPropertyFlagBits> // NOLINT
|
||||
{
|
||||
|
||||
device_local_bit = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
host_visible_bit = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
|
||||
host_coherent_bit = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
host_cached_bit = VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
||||
lazily_allocated_bit = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,
|
||||
protected_bit = VK_MEMORY_PROPERTY_PROTECTED_BIT,
|
||||
device_coherent_bit_amd = VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD,
|
||||
device_uncached_bit_amd = VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD,
|
||||
rdma_capable_bit_nv = VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV,
|
||||
};
|
||||
}
|
||||
|
||||
class Instance
|
||||
{
|
||||
public:
|
||||
friend class Surface;
|
||||
friend class Gpu;
|
||||
|
||||
struct Layer
|
||||
{
|
||||
struct Setting
|
||||
{
|
||||
std::string name;
|
||||
std::variant<std::vector<const char *>, std::uint32_t, bool> values;
|
||||
};
|
||||
|
||||
std::string name;
|
||||
|
||||
std::vector<Setting> settings;
|
||||
};
|
||||
|
||||
using Extension = std::string;
|
||||
|
||||
struct CreateInfo
|
||||
{
|
||||
ApplicationInfo application_info;
|
||||
|
||||
std::vector<Layer> layers;
|
||||
|
||||
std::vector<Extension> extensions;
|
||||
};
|
||||
|
||||
Instance() = default;
|
||||
|
||||
Instance(CreateInfo info);
|
||||
|
||||
Instance(Instance &&) = default;
|
||||
|
||||
Instance(const Instance &) = delete;
|
||||
|
||||
auto operator=(Instance &&) -> Instance & = default;
|
||||
|
||||
auto operator=(const Instance &) = delete;
|
||||
|
||||
~Instance();
|
||||
|
||||
void load_functions();
|
||||
|
||||
[[nodiscard]] operator bool() const
|
||||
{
|
||||
return m_instance != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
private:
|
||||
memory::NullOnMove<VkInstance> m_instance {};
|
||||
};
|
||||
|
||||
class Surface
|
||||
{
|
||||
public:
|
||||
friend class Gpu;
|
||||
|
||||
struct XlibCreateInfo
|
||||
{
|
||||
Display *display;
|
||||
|
||||
Window window;
|
||||
};
|
||||
|
||||
Surface() = default;
|
||||
|
||||
Surface(const Instance &instance, const XlibCreateInfo &info);
|
||||
|
||||
Surface(Surface &&) = default;
|
||||
|
||||
Surface(const Surface &) = delete;
|
||||
|
||||
auto operator=(Surface &&) -> Surface & = default;
|
||||
|
||||
auto operator=(const Surface &) -> Surface & = delete;
|
||||
|
||||
~Surface();
|
||||
|
||||
[[nodiscard]] operator bool() const
|
||||
{
|
||||
return m_surface != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
private:
|
||||
memory::NullOnMove<VkSurfaceKHR> m_surface {};
|
||||
|
||||
VkInstance m_instance {};
|
||||
};
|
||||
|
||||
class Gpu
|
||||
{
|
||||
public:
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
other = 0,
|
||||
integrated_gpu = 1,
|
||||
discrete_gpu = 2,
|
||||
virtual_gpu = 3,
|
||||
cpu = 4,
|
||||
};
|
||||
|
||||
struct Features
|
||||
{
|
||||
Bool32 robust_buffer_access;
|
||||
Bool32 full_draw_index_uint32;
|
||||
Bool32 image_cube_array;
|
||||
Bool32 independent_blend;
|
||||
Bool32 geometry_shader;
|
||||
Bool32 tessellation_shader;
|
||||
Bool32 sample_rate_shading;
|
||||
Bool32 dual_src_blend;
|
||||
Bool32 logic_op;
|
||||
Bool32 multi_draw_indirect;
|
||||
Bool32 draw_indirect_first_instance;
|
||||
Bool32 depth_clamp;
|
||||
Bool32 depth_bias_clamp;
|
||||
Bool32 fill_mode_non_solid;
|
||||
Bool32 depth_bounds;
|
||||
Bool32 wide_lines;
|
||||
Bool32 large_points;
|
||||
Bool32 alpha_to_one;
|
||||
Bool32 multi_viewport;
|
||||
Bool32 sampler_anisotropy;
|
||||
Bool32 texture_compression_etc2;
|
||||
Bool32 texture_compression_astc_ldr;
|
||||
Bool32 texture_compression_bc;
|
||||
Bool32 occlusion_query_precise;
|
||||
Bool32 pipeline_statistics_query;
|
||||
Bool32 vertex_pipeline_stores_and_atomics;
|
||||
Bool32 fragment_stores_and_atomics;
|
||||
Bool32 shader_tessellation_and_geometry_point_size;
|
||||
Bool32 shader_image_gather_extended;
|
||||
Bool32 shader_storage_image_extended_formats;
|
||||
Bool32 shader_storage_image_multisample;
|
||||
Bool32 shader_storage_image_read_without_format;
|
||||
Bool32 shader_storage_image_write_without_format;
|
||||
Bool32 shader_uniform_buffer_array_dynamic_indexing;
|
||||
Bool32 shader_sampled_image_array_dynamic_indexing;
|
||||
Bool32 shader_storage_buffer_array_dynamic_indexing;
|
||||
Bool32 shader_storage_image_array_dynamic_indexing;
|
||||
Bool32 shader_clip_distance;
|
||||
Bool32 shader_cull_distance;
|
||||
Bool32 shader_float64;
|
||||
Bool32 shader_int64;
|
||||
Bool32 shader_int16;
|
||||
Bool32 shader_resource_residency;
|
||||
Bool32 shader_resource_min_lod;
|
||||
Bool32 sparse_binding;
|
||||
Bool32 sparse_residency_buffer;
|
||||
Bool32 sparse_residency_image_2d;
|
||||
Bool32 sparse_residency_image_3d;
|
||||
Bool32 sparse_residency_2_samples;
|
||||
Bool32 sparse_residency_4_samples;
|
||||
Bool32 sparse_residency_8_samples;
|
||||
Bool32 sparse_residency_16_samples;
|
||||
Bool32 sparse_residency_aliased;
|
||||
Bool32 variable_multisample_rate;
|
||||
Bool32 inherited_queries;
|
||||
};
|
||||
|
||||
struct Limits
|
||||
{
|
||||
std::uint32_t max_image_dimension_1d;
|
||||
std::uint32_t max_image_dimension_2d;
|
||||
std::uint32_t max_image_dimension_3d;
|
||||
std::uint32_t max_image_dimension_cube;
|
||||
std::uint32_t max_image_array_layers;
|
||||
std::uint32_t max_texel_buffer_elements;
|
||||
std::uint32_t max_uniform_buffer_range;
|
||||
std::uint32_t max_storage_buffer_range;
|
||||
std::uint32_t max_push_constants_size;
|
||||
std::uint32_t max_memory_allocation_count;
|
||||
std::uint32_t max_sampler_allocation_count;
|
||||
std::size_t buffer_image_granularity;
|
||||
std::size_t sparse_address_space_size;
|
||||
std::uint32_t max_bound_descriptor_sets;
|
||||
std::uint32_t max_per_stage_descriptor_samplers;
|
||||
std::uint32_t max_per_stage_descriptor_uniform_buffers;
|
||||
std::uint32_t max_per_stage_descriptor_storage_buffers;
|
||||
std::uint32_t max_per_stage_descriptor_sampled_images;
|
||||
std::uint32_t max_per_stage_descriptor_storage_images;
|
||||
std::uint32_t max_per_stage_descriptor_input_attachments;
|
||||
std::uint32_t max_per_stage_resources;
|
||||
std::uint32_t max_descriptor_set_samplers;
|
||||
std::uint32_t max_descriptor_set_uniform_buffers;
|
||||
std::uint32_t max_descriptor_set_uniform_buffers_dynamic;
|
||||
std::uint32_t max_descriptor_set_storage_buffers;
|
||||
std::uint32_t max_descriptor_set_storage_buffers_dynamic;
|
||||
std::uint32_t max_descriptor_set_sampled_images;
|
||||
std::uint32_t max_descriptor_set_storage_images;
|
||||
std::uint32_t max_descriptor_set_input_attachments;
|
||||
std::uint32_t max_vertex_input_attributes;
|
||||
std::uint32_t max_vertex_input_bindings;
|
||||
std::uint32_t max_vertex_input_attribute_offset;
|
||||
std::uint32_t max_vertex_input_binding_stride;
|
||||
std::uint32_t max_vertex_output_components;
|
||||
std::uint32_t max_tessellation_generation_level;
|
||||
std::uint32_t max_tessellation_patch_size;
|
||||
std::uint32_t max_tessellation_control_per_vertex_input_components;
|
||||
std::uint32_t max_tessellation_control_per_vertex_output_components;
|
||||
std::uint32_t max_tessellation_control_per_patch_output_components;
|
||||
std::uint32_t max_tessellation_control_total_output_components;
|
||||
std::uint32_t max_tessellation_evaluation_input_components;
|
||||
std::uint32_t max_tessellation_evaluation_output_components;
|
||||
std::uint32_t max_geometry_shader_invocations;
|
||||
std::uint32_t max_geometry_input_components;
|
||||
std::uint32_t max_geometry_output_components;
|
||||
std::uint32_t max_geometry_output_vertices;
|
||||
std::uint32_t max_geometry_total_output_components;
|
||||
std::uint32_t max_fragment_input_components;
|
||||
std::uint32_t max_fragment_output_attachments;
|
||||
std::uint32_t max_fragment_dual_src_attachments;
|
||||
std::uint32_t max_fragment_combined_output_resources;
|
||||
std::uint32_t max_compute_shared_memory_size;
|
||||
std::array<std::uint32_t, 3> max_compute_work_group_count;
|
||||
std::uint32_t max_compute_work_group_invocations;
|
||||
std::array<std::uint32_t, 3> max_compute_work_group_size;
|
||||
std::uint32_t sub_pixel_precision_bits;
|
||||
std::uint32_t sub_texel_precision_bits;
|
||||
std::uint32_t mipmap_precision_bits;
|
||||
std::uint32_t max_draw_indexed_index_value;
|
||||
std::uint32_t max_draw_indirect_count;
|
||||
float max_sampler_lod_bias;
|
||||
float max_sampler_anisotropy;
|
||||
std::uint32_t max_viewports;
|
||||
std::array<std::uint32_t, 2> max_viewport_dimensions;
|
||||
std::array<float, 2> viewport_bounds_range;
|
||||
std::uint32_t viewport_sub_pixel_bits;
|
||||
std::size_t min_memory_map_alignment;
|
||||
VkDeviceSize min_texel_buffer_offset_alignment;
|
||||
VkDeviceSize min_uniform_buffer_offset_alignment;
|
||||
VkDeviceSize min_storage_buffer_offset_alignment;
|
||||
std::int32_t min_texel_offset;
|
||||
std::uint32_t max_texel_offset;
|
||||
std::int32_t min_texel_gather_offset;
|
||||
std::uint32_t max_texel_gather_offset;
|
||||
float min_interpolation_offset;
|
||||
float max_interpolation_offset;
|
||||
std::uint32_t sub_pixel_interpolation_offset_bits;
|
||||
std::uint32_t max_framebuffer_width;
|
||||
std::uint32_t max_framebuffer_height;
|
||||
std::uint32_t max_framebuffer_layers;
|
||||
VkSampleCountFlags framebuffer_color_sample_counts;
|
||||
VkSampleCountFlags framebuffer_depth_sample_counts;
|
||||
VkSampleCountFlags framebuffer_stencil_sample_counts;
|
||||
VkSampleCountFlags framebuffer_no_attachments_sample_counts;
|
||||
std::uint32_t max_color_attachments;
|
||||
VkSampleCountFlags sampled_image_color_sample_counts;
|
||||
VkSampleCountFlags sampled_image_integer_sample_counts;
|
||||
VkSampleCountFlags sampled_image_depth_sample_counts;
|
||||
VkSampleCountFlags sampled_image_stencil_sample_counts;
|
||||
VkSampleCountFlags storage_image_sample_counts;
|
||||
std::uint32_t max_sample_mask_words;
|
||||
Bool32 timestamp_compute_and_graphics;
|
||||
float timestamp_period;
|
||||
std::uint32_t max_clip_distances;
|
||||
std::uint32_t max_cull_distances;
|
||||
std::uint32_t max_combined_clip_and_cull_distances;
|
||||
std::uint32_t discrete_queue_priorities;
|
||||
std::array<float, 2> point_size_range;
|
||||
std::array<float, 2> line_width_range;
|
||||
float point_size_granularity;
|
||||
float line_width_granularity;
|
||||
Bool32 strict_lines;
|
||||
Bool32 standard_sample_locations;
|
||||
std::size_t optimal_buffer_copy_offset_alignment;
|
||||
std::size_t optimal_buffer_copy_row_pitch_alignment;
|
||||
std::size_t non_coherent_atom_size;
|
||||
};
|
||||
|
||||
struct SparseProperties
|
||||
{
|
||||
Bool32 residency_standard_2d_block_shape;
|
||||
Bool32 residency_standard_2d_multisample_block_shape;
|
||||
Bool32 residency_standard_3d_block_shape;
|
||||
Bool32 residency_aligned_mip_size;
|
||||
Bool32 residency_non_resident_strict;
|
||||
};
|
||||
|
||||
struct Properties
|
||||
{
|
||||
std::uint32_t api_version;
|
||||
std::uint32_t driver_version;
|
||||
std::uint32_t vendor_id;
|
||||
std::uint32_t device_id;
|
||||
Type device_type;
|
||||
std::array<char, constants::max_physical_device_name> device_name;
|
||||
std::array<std::uint8_t, constants::uuid_size> pipeline_cache_uuid;
|
||||
Limits limits;
|
||||
SparseProperties sparse_properties;
|
||||
};
|
||||
|
||||
struct MemoryType
|
||||
{
|
||||
MemoryPropertyFlags::T property_flags;
|
||||
std::uint32_t heap_idx;
|
||||
};
|
||||
|
||||
struct MemoryHeap
|
||||
{
|
||||
std::size_t size;
|
||||
MemoryHeapFlags::T flags;
|
||||
};
|
||||
|
||||
struct MemoryProperties
|
||||
{
|
||||
std::uint32_t memory_type_count;
|
||||
std::array<MemoryType, constants::max_memory_types> memory_types;
|
||||
|
||||
std::uint32_t memory_heap_count;
|
||||
std::array<MemoryHeap, constants::max_memory_heaps> memory_heaps;
|
||||
};
|
||||
|
||||
struct QueueFamilyProperties
|
||||
{
|
||||
QueueFlags::T queue_flags {};
|
||||
std::uint32_t queue_count {};
|
||||
std::uint32_t timestamp_valid_bits {};
|
||||
math::uvec3 min_image_transfer_granularity;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
static auto enumerate(const Instance &instance) -> std::vector<Gpu>;
|
||||
|
||||
Gpu() = default;
|
||||
|
||||
Gpu(Gpu &&) = default;
|
||||
|
||||
Gpu(const Gpu &) = default;
|
||||
|
||||
auto operator=(Gpu &&) -> Gpu & = default;
|
||||
|
||||
auto operator=(const Gpu &) -> Gpu & = default;
|
||||
|
||||
~Gpu();
|
||||
|
||||
[[nodiscard]] auto get_properties() const -> Properties;
|
||||
|
||||
[[nodiscard]] auto get_features() const -> Features;
|
||||
|
||||
[[nodiscard]] auto get_memory_properties() const -> MemoryProperties;
|
||||
|
||||
[[nodiscard]] auto get_queue_family_properties() const -> std::vector<QueueFamilyProperties>;
|
||||
|
||||
[[nodiscard]] auto queue_family_supports_surface(
|
||||
const Surface &surface,
|
||||
std::uint32_t queue_family_idx
|
||||
) const -> bool;
|
||||
|
||||
[[nodiscard]] operator bool() const
|
||||
{
|
||||
return m_physical_device != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
private:
|
||||
VkPhysicalDevice m_physical_device {};
|
||||
|
||||
VkInstance m_instance {};
|
||||
};
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
struct CreateInfo
|
||||
{
|
||||
std::set<std::uint32_t> queue_indices;
|
||||
|
||||
std::vector<std::string> extensions;
|
||||
|
||||
Gpu::Features required_gpu_features;
|
||||
};
|
||||
|
||||
Device() = default;
|
||||
|
||||
Device(CreateInfo info);
|
||||
|
||||
Device(Device &&) = default;
|
||||
|
||||
Device(const Device &) = delete;
|
||||
|
||||
auto operator=(Device &&) -> Device & = default;
|
||||
|
||||
auto operator=(const Device &) -> Device & = delete;
|
||||
|
||||
~Device();
|
||||
|
||||
private:
|
||||
memory::NullOnMove<VkDevice> m_device {};
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
auto enumerate_instance_extension_properties() -> std::vector<VkExtensionProperties>;
|
||||
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
||||
module :private;
|
||||
using namespace lt::renderer::vk;
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// global functions
|
||||
PFN_vkGetInstanceProcAddr vk_get_instance_proc_address {};
|
||||
PFN_vkCreateInstance vk_create_instance {};
|
||||
PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties {};
|
||||
PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties {};
|
||||
|
||||
// instance functions
|
||||
PFN_vkDestroyInstance vk_destroy_instance {};
|
||||
PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices {};
|
||||
|
||||
PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties {};
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties {};
|
||||
PFN_vkCreateDevice vk_create_device {};
|
||||
PFN_vkGetDeviceProcAddr vk_get_device_proc_address {};
|
||||
PFN_vkDestroyDevice vk_destroy_device {};
|
||||
PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features {};
|
||||
PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties {};
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties {};
|
||||
|
||||
// extension instance functions
|
||||
PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label {};
|
||||
PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label {};
|
||||
PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label {};
|
||||
PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger {};
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger {};
|
||||
PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label {};
|
||||
PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label {};
|
||||
PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label {};
|
||||
PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name {};
|
||||
PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag {};
|
||||
PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message {};
|
||||
|
||||
// surface instance functions
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {};
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {};
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {};
|
||||
|
||||
// device functions
|
||||
PFN_vkGetDeviceQueue vk_get_device_queue {};
|
||||
PFN_vkCreateCommandPool vk_create_command_pool {};
|
||||
PFN_vkDestroyCommandPool vk_destroy_command_pool {};
|
||||
PFN_vkAllocateCommandBuffers vk_allocate_command_buffers {};
|
||||
PFN_vkFreeCommandBuffers vk_free_command_buffers {};
|
||||
PFN_vkBeginCommandBuffer vk_begin_command_buffer {};
|
||||
PFN_vkEndCommandBuffer vk_end_command_buffer {};
|
||||
PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier {};
|
||||
PFN_vkQueueSubmit vk_queue_submit {};
|
||||
PFN_vkQueueWaitIdle vk_queue_wait_idle {};
|
||||
PFN_vkDeviceWaitIdle vk_device_wait_idle {};
|
||||
PFN_vkCreateFence vk_create_fence {};
|
||||
PFN_vkDestroyFence vk_destroy_fence {};
|
||||
PFN_vkWaitForFences vk_wait_for_fences {};
|
||||
PFN_vkResetFences vk_reset_fences {};
|
||||
PFN_vkCreateSemaphore vk_create_semaphore {};
|
||||
PFN_vkDestroySemaphore vk_destroy_semaphore {};
|
||||
PFN_vkCreateSwapchainKHR vk_create_swapchain_khr {};
|
||||
PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr {};
|
||||
PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr {};
|
||||
PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr {};
|
||||
PFN_vkQueuePresentKHR vk_queue_present_khr {};
|
||||
PFN_vkCreateImageView vk_create_image_view {};
|
||||
PFN_vkDestroyImageView vk_destroy_image_view {};
|
||||
PFN_vkCreateRenderPass vk_create_render_pass {};
|
||||
PFN_vkDestroyRenderPass vk_destroy_render_pass {};
|
||||
PFN_vkCreateFramebuffer vk_create_frame_buffer {};
|
||||
PFN_vkDestroyFramebuffer vk_destroy_frame_buffer {};
|
||||
PFN_vkCreateShaderModule vk_create_shader_module {};
|
||||
PFN_vkDestroyShaderModule vk_destroy_shader_module {};
|
||||
PFN_vkCreatePipelineLayout vk_create_pipeline_layout {};
|
||||
PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout {};
|
||||
PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines {};
|
||||
PFN_vkDestroyPipeline vk_destroy_pipeline {};
|
||||
PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass {};
|
||||
PFN_vkCmdEndRenderPass vk_cmd_end_render_pass {};
|
||||
PFN_vkCmdBindPipeline vk_cmd_bind_pipeline {};
|
||||
PFN_vkCmdDraw vk_cmd_draw {};
|
||||
PFN_vkCmdSetViewport vk_cmd_set_viewport {};
|
||||
PFN_vkCmdSetScissor vk_cmd_set_scissors {};
|
||||
PFN_vkCmdPushConstants vk_cmd_push_constants {};
|
||||
PFN_vkCmdCopyBuffer vk_cmd_copy_buffer {};
|
||||
|
||||
PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout {};
|
||||
PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout {};
|
||||
PFN_vkCreateDescriptorPool vk_create_descriptor_pool {};
|
||||
PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool {};
|
||||
PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets {};
|
||||
PFN_vkFreeDescriptorSets vk_free_descriptor_sets {};
|
||||
|
||||
PFN_vkCreateBuffer vk_create_buffer {};
|
||||
PFN_vkDestroyBuffer vk_destroy_buffer {};
|
||||
PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements {};
|
||||
PFN_vkAllocateMemory vk_allocate_memory {};
|
||||
PFN_vkBindBufferMemory vk_bind_buffer_memory {};
|
||||
PFN_vkMapMemory vk_map_memory {};
|
||||
PFN_vkUnmapMemory vk_unmap_memory {};
|
||||
PFN_vkFreeMemory vk_free_memory {};
|
||||
|
||||
PFN_vkResetCommandBuffer vk_reset_command_buffer {};
|
||||
|
||||
PFN_vkCmdBeginRendering vk_cmd_begin_rendering {};
|
||||
PFN_vkCmdEndRendering vk_cmd_end_rendering {};
|
||||
|
||||
PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr {};
|
||||
PFN_vkDestroySurfaceKHR vk_destroy_surface_khr {};
|
||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
namespace {
|
||||
void *library = nullptr; // NOLINT
|
||||
}
|
||||
|
||||
void load_library()
|
||||
{
|
||||
constexpr auto runtime_loader_flags = RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE;
|
||||
library = dlopen("libvulkan.so.1", runtime_loader_flags);
|
||||
if (!library)
|
||||
{
|
||||
library = dlopen("libvulkan.so", runtime_loader_flags);
|
||||
}
|
||||
lt::debug::ensure(library, "Failed to dlopen vulkan library");
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
vk_get_instance_proc_address = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
|
||||
dlsym(library, "vkGetInstanceProcAddr")
|
||||
);
|
||||
lt::debug::ensure(
|
||||
vk_get_instance_proc_address,
|
||||
"Failed to load vulkan function: vkGetInstanceProcAddr"
|
||||
);
|
||||
}
|
||||
|
||||
void vkc(VkResult result)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
throw std::runtime_error {
|
||||
std::format("Vulkan call failed with result: {}", std::to_underlying(result))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void unload_library()
|
||||
{
|
||||
if (!library)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// calling dlclose causes many issues with runtime analyzers
|
||||
// eg. https://github.com/google/sanitizers/issues/89
|
||||
// with no noticable gains, so we just don't bother closing it.
|
||||
|
||||
// dlclose(library);
|
||||
// library = nullptr;
|
||||
}
|
||||
|
||||
void load_global_functions()
|
||||
{
|
||||
constexpr auto load_fn = []<typename T>(T &pfn, const char *fn_name) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_instance_proc_address(nullptr, fn_name));
|
||||
lt::debug::ensure(pfn, "Failed to load vulkan global function: {}", fn_name);
|
||||
// log::trace("Loaded global function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_create_instance, "vkCreateInstance");
|
||||
load_fn(vk_enumerate_instance_extension_properties, "vkEnumerateInstanceExtensionProperties");
|
||||
load_fn(vk_enumerate_instance_layer_properties, "vkEnumerateInstanceLayerProperties");
|
||||
}
|
||||
|
||||
void Instance::load_functions()
|
||||
{
|
||||
const auto load_fn = [this]<typename T>(T &pfn, const char *fn_name) {
|
||||
pfn = std::bit_cast<T>(vk_get_instance_proc_address(m_instance, fn_name));
|
||||
lt::debug::ensure(pfn, "Failed to load vulkan instance function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_destroy_instance, "vkDestroyInstance");
|
||||
load_fn(vk_enumerate_physical_devices, "vkEnumeratePhysicalDevices");
|
||||
load_fn(vk_get_physical_device_properties, "vkGetPhysicalDeviceProperties");
|
||||
load_fn(
|
||||
vk_get_physical_device_queue_family_properties,
|
||||
"vkGetPhysicalDeviceQueueFamilyProperties"
|
||||
);
|
||||
load_fn(vk_create_device, "vkCreateDevice");
|
||||
load_fn(vk_get_device_proc_address, "vkGetDeviceProcAddr");
|
||||
load_fn(vk_destroy_device, "vkDestroyDevice");
|
||||
load_fn(vk_get_physical_device_features, "vkGetPhysicalDeviceFeatures");
|
||||
load_fn(vk_enumerate_device_extension_properties, "vkEnumerateDeviceExtensionProperties");
|
||||
load_fn(vk_get_physical_device_memory_properties, "vkGetPhysicalDeviceMemoryProperties");
|
||||
|
||||
load_fn(vk_cmd_begin_debug_label, "vkCmdBeginDebugUtilsLabelEXT");
|
||||
load_fn(vk_cmd_end_debug_label, "vkCmdEndDebugUtilsLabelEXT");
|
||||
load_fn(vk_cmd_insert_debug_label, "vkCmdInsertDebugUtilsLabelEXT");
|
||||
load_fn(vk_create_debug_messenger, "vkCreateDebugUtilsMessengerEXT");
|
||||
load_fn(vk_destroy_debug_messenger, "vkDestroyDebugUtilsMessengerEXT");
|
||||
load_fn(vk_queue_begin_debug_label, "vkQueueBeginDebugUtilsLabelEXT");
|
||||
load_fn(vk_queue_end_debug_label, "vkQueueEndDebugUtilsLabelEXT");
|
||||
load_fn(vk_queue_insert_debug_label, "vkQueueInsertDebugUtilsLabelEXT");
|
||||
load_fn(vk_set_debug_object_name, "vkSetDebugUtilsObjectNameEXT");
|
||||
load_fn(vk_set_debug_object_tag, "vkSetDebugUtilsObjectTagEXT");
|
||||
load_fn(vk_submit_debug_message, "vkSubmitDebugUtilsMessageEXT");
|
||||
|
||||
load_fn(vk_get_physical_device_surface_support, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
||||
load_fn(
|
||||
vk_get_physical_device_surface_capabilities,
|
||||
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"
|
||||
);
|
||||
load_fn(vk_get_physical_device_surface_formats, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||
load_fn(vk_create_xlib_surface_khr, "vkCreateXlibSurfaceKHR");
|
||||
load_fn(vk_destroy_surface_khr, "vkDestroySurfaceKHR");
|
||||
}
|
||||
|
||||
void load_device_functions(VkDevice device)
|
||||
{
|
||||
const auto load_fn = [device]<typename T>(T &pfn, const char *fn_name) {
|
||||
pfn = std::bit_cast<T>(vk_get_device_proc_address(device, fn_name));
|
||||
lt::debug::ensure(pfn, "Failed to load vulkan device function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_get_device_queue, "vkGetDeviceQueue");
|
||||
load_fn(vk_create_command_pool, "vkCreateCommandPool");
|
||||
load_fn(vk_destroy_command_pool, "vkDestroyCommandPool");
|
||||
load_fn(vk_allocate_command_buffers, "vkAllocateCommandBuffers");
|
||||
load_fn(vk_free_command_buffers, "vkFreeCommandBuffers");
|
||||
load_fn(vk_begin_command_buffer, "vkBeginCommandBuffer");
|
||||
load_fn(vk_end_command_buffer, "vkEndCommandBuffer");
|
||||
load_fn(vk_cmd_pipeline_barrier, "vkCmdPipelineBarrier");
|
||||
load_fn(vk_queue_submit, "vkQueueSubmit");
|
||||
load_fn(vk_queue_wait_idle, "vkQueueWaitIdle");
|
||||
load_fn(vk_device_wait_idle, "vkDeviceWaitIdle");
|
||||
load_fn(vk_create_fence, "vkCreateFence");
|
||||
load_fn(vk_destroy_fence, "vkDestroyFence");
|
||||
load_fn(vk_wait_for_fences, "vkWaitForFences");
|
||||
load_fn(vk_reset_fences, "vkResetFences");
|
||||
load_fn(vk_create_semaphore, "vkCreateSemaphore");
|
||||
load_fn(vk_destroy_semaphore, "vkDestroySemaphore");
|
||||
load_fn(vk_create_swapchain_khr, "vkCreateSwapchainKHR");
|
||||
load_fn(vk_destroy_swapchain_khr, "vkDestroySwapchainKHR");
|
||||
load_fn(vk_get_swapchain_images_khr, "vkGetSwapchainImagesKHR");
|
||||
load_fn(vk_acquire_next_image_khr, "vkAcquireNextImageKHR");
|
||||
load_fn(vk_queue_present_khr, "vkQueuePresentKHR");
|
||||
load_fn(vk_create_image_view, "vkCreateImageView");
|
||||
load_fn(vk_destroy_image_view, "vkDestroyImageView");
|
||||
load_fn(vk_create_render_pass, "vkCreateRenderPass");
|
||||
load_fn(vk_destroy_render_pass, "vkDestroyRenderPass");
|
||||
load_fn(vk_create_frame_buffer, "vkCreateFramebuffer");
|
||||
load_fn(vk_destroy_frame_buffer, "vkDestroyFramebuffer");
|
||||
load_fn(vk_create_shader_module, "vkCreateShaderModule");
|
||||
load_fn(vk_destroy_shader_module, "vkDestroyShaderModule");
|
||||
load_fn(vk_create_pipeline_layout, "vkCreatePipelineLayout");
|
||||
load_fn(vk_destroy_pipeline_layout, "vkDestroyPipelineLayout");
|
||||
load_fn(vk_create_graphics_pipelines, "vkCreateGraphicsPipelines");
|
||||
load_fn(vk_destroy_pipeline, "vkDestroyPipeline");
|
||||
load_fn(vk_cmd_begin_render_pass, "vkCmdBeginRenderPass");
|
||||
load_fn(vk_cmd_end_render_pass, "vkCmdEndRenderPass");
|
||||
load_fn(vk_cmd_bind_pipeline, "vkCmdBindPipeline");
|
||||
load_fn(vk_cmd_draw, "vkCmdDraw");
|
||||
load_fn(vk_cmd_set_viewport, "vkCmdSetViewport");
|
||||
load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
|
||||
load_fn(vk_cmd_push_constants, "vkCmdPushConstants");
|
||||
load_fn(vk_cmd_copy_buffer, "vkCmdCopyBuffer");
|
||||
load_fn(vk_create_descriptor_set_layout, "vkCreateDescriptorSetLayout");
|
||||
load_fn(vk_destroy_descriptor_set_layout, "vkDestroyDescriptorSetLayout");
|
||||
load_fn(vk_create_descriptor_pool, "vkCreateDescriptorPool");
|
||||
load_fn(vk_destroy_descriptor_pool, "vkDestroyDescriptorPool");
|
||||
load_fn(vk_allocate_descriptor_sets, "vkAllocateDescriptorSets");
|
||||
load_fn(vk_free_descriptor_sets, "vkFreeDescriptorSets");
|
||||
load_fn(vk_create_buffer, "vkCreateBuffer");
|
||||
load_fn(vk_destroy_buffer, "vkDestroyBuffer");
|
||||
load_fn(vk_allocate_memory, "vkAllocateMemory");
|
||||
load_fn(vk_bind_buffer_memory, "vkBindBufferMemory");
|
||||
load_fn(vk_map_memory, "vkMapMemory");
|
||||
load_fn(vk_unmap_memory, "vkUnmapMemory");
|
||||
load_fn(vk_free_memory, "vkFreeMemory");
|
||||
load_fn(vk_get_buffer_memory_requirements, "vkGetBufferMemoryRequirements");
|
||||
load_fn(vk_reset_command_buffer, "vkResetCommandBuffer");
|
||||
|
||||
load_fn(vk_cmd_begin_rendering, "vkCmdBeginRendering");
|
||||
load_fn(vk_cmd_end_rendering, "vkCmdEndRendering");
|
||||
}
|
||||
|
||||
Instance::Instance(CreateInfo info)
|
||||
{
|
||||
const auto layer_setting_type_visitor = overloads {
|
||||
[](const std::vector<const char *> &) { return VK_LAYER_SETTING_TYPE_STRING_EXT; },
|
||||
[](std::uint32_t) { return VK_LAYER_SETTING_TYPE_UINT32_EXT; },
|
||||
[](bool) { return VK_LAYER_SETTING_TYPE_BOOL32_EXT; },
|
||||
};
|
||||
|
||||
const auto layer_setting_value_visitor = overloads {
|
||||
[](std::vector<const char *> values) { return std::bit_cast<void *>(values.data()); },
|
||||
[](std::uint32_t value) { return std::bit_cast<void *>(&value); },
|
||||
[](bool value) { return std::bit_cast<void *>(&value); },
|
||||
};
|
||||
|
||||
auto layer_settings = std::vector<VkLayerSettingEXT> {};
|
||||
auto layer_names = std::vector<const char *> {};
|
||||
auto extension_names = std::vector<const char *> {};
|
||||
|
||||
for (const auto &layer : info.layers)
|
||||
{
|
||||
layer_names.emplace_back(layer.name.c_str());
|
||||
for (const auto &setting : layer.settings)
|
||||
{
|
||||
layer_settings.emplace_back(
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer.name.c_str(),
|
||||
.pSettingName = setting.name.c_str(),
|
||||
.type = std::visit(layer_setting_type_visitor, setting.values),
|
||||
.valueCount = 1u,
|
||||
.pValues = std::visit(layer_setting_value_visitor, setting.values),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const auto layer_settings_create_info = VkLayerSettingsCreateInfoEXT {
|
||||
.sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
|
||||
.settingCount = static_cast<uint32_t>(layer_settings.size()),
|
||||
.pSettings = layer_settings.data(),
|
||||
};
|
||||
|
||||
auto vk_info = VkInstanceCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pNext = &layer_settings_create_info,
|
||||
.flags = {},
|
||||
.enabledLayerCount = static_cast<uint32_t>(info.layers.size()),
|
||||
.ppEnabledLayerNames = layer_names.data(),
|
||||
.enabledExtensionCount = static_cast<uint32_t>(info.extensions.size()),
|
||||
.ppEnabledExtensionNames = extension_names.data(),
|
||||
};
|
||||
|
||||
vkc(vk_create_instance(&vk_info, nullptr, &m_instance));
|
||||
debug::ensure(m_instance, "Failed to create vulkan instance");
|
||||
}
|
||||
|
||||
Surface::Surface(const Instance &instance, const XlibCreateInfo &info)
|
||||
: m_instance(instance.m_instance)
|
||||
{
|
||||
const auto vk_info = VkXlibSurfaceCreateInfoKHR {
|
||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||
.pNext = {},
|
||||
.flags = {},
|
||||
.dpy = info.display,
|
||||
.window = info.window,
|
||||
};
|
||||
|
||||
vkc(vk_create_xlib_surface_khr(instance.m_instance, &vk_info, nullptr, &m_surface));
|
||||
}
|
||||
|
||||
Surface::~Surface()
|
||||
{
|
||||
vk_destroy_surface_khr(m_instance, m_surface, nullptr);
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]]
|
||||
/* static */ auto Gpu::enumerate(const Instance &instance) -> std::vector<Gpu>
|
||||
{
|
||||
auto count = 0u;
|
||||
vkc(vk_enumerate_physical_devices(instance.m_instance, &count, nullptr));
|
||||
debug::ensure(count != 0u, "Failed to find any gpus with Vulkan support");
|
||||
|
||||
auto vk_gpus = std::vector<VkPhysicalDevice>(count);
|
||||
vkc(vk_enumerate_physical_devices(instance.m_instance, &count, vk_gpus.data()));
|
||||
|
||||
auto gpus = std::vector<Gpu>(count);
|
||||
for (auto [vk_gpu, gpu] : std::views::zip(vk_gpus, gpus))
|
||||
{
|
||||
gpu.m_instance = instance.m_instance;
|
||||
gpu.m_physical_device = vk_gpu;
|
||||
}
|
||||
|
||||
return gpus;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::queue_family_supports_surface(
|
||||
const Surface &surface,
|
||||
std::uint32_t queue_family_idx
|
||||
) const -> bool
|
||||
{
|
||||
auto supported = VkBool32 { false };
|
||||
vkc(vk_get_physical_device_surface_support(
|
||||
m_physical_device,
|
||||
queue_family_idx,
|
||||
surface.m_surface,
|
||||
&supported
|
||||
));
|
||||
return supported;
|
||||
}
|
||||
|
||||
Device::Device(CreateInfo info)
|
||||
{
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
if (m_device)
|
||||
{
|
||||
vk_destroy_device(m_device, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto enumerate_instance_extension_properties() -> std::vector<VkExtensionProperties>
|
||||
{
|
||||
auto count = 0u;
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr));
|
||||
|
||||
auto extensions = std::vector<VkExtensionProperties>(count);
|
||||
std::memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties));
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data()));
|
||||
|
||||
return extensions;
|
||||
}
|
||||
102
modules/renderer/backends/vk/library_wrapper.cppma
Normal file
102
modules/renderer/backends/vk/library_wrapper.cppma
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
module;
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <vulkan/vulkan_xlib.h>
|
||||
|
||||
export module renderer.backend.vk.library_wrapper;
|
||||
import std;
|
||||
// import renderer.backend.vk.library_loader;
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
struct CreateInfo
|
||||
{
|
||||
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
||||
|
||||
std::vector<std::string> layers;
|
||||
|
||||
std::vector<std::string> extensions;
|
||||
|
||||
VkPhysicalDeviceFeatures2 features;
|
||||
};
|
||||
|
||||
Device() = default;
|
||||
|
||||
Device(CreateInfo info)
|
||||
{
|
||||
}
|
||||
|
||||
~Device()
|
||||
{
|
||||
if (m_device)
|
||||
{
|
||||
vk_destroy_device(m_device, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VkDevice m_device {};
|
||||
};
|
||||
|
||||
}; // namespace lt::renderer::vk
|
||||
|
||||
export namespace lt::renderer::vk {
|
||||
|
||||
using Version_T = uint32_t;
|
||||
|
||||
struct ApplicationInfo
|
||||
{
|
||||
std::string_view name;
|
||||
|
||||
Version_T version;
|
||||
|
||||
std::string_view *engine_name;
|
||||
|
||||
Version_T engine_version;
|
||||
|
||||
Version_T api_version;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
auto enumerate_instance_extension_properties() -> std::vector<VkExtensionProperties>
|
||||
{
|
||||
auto count = 0u;
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr));
|
||||
|
||||
auto extensions = std::vector<VkExtensionProperties>(count);
|
||||
std::memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties));
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data()));
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
struct VkInstanceCreateInfo
|
||||
{
|
||||
VkInstanceCreateFlags flags;
|
||||
|
||||
ApplicationInfo application_info;
|
||||
|
||||
std::vector<const char **> layers;
|
||||
|
||||
std::vector<const char **> extensions;
|
||||
|
||||
const void *next;
|
||||
};
|
||||
|
||||
class Instance
|
||||
{
|
||||
};
|
||||
|
||||
[[nodiscard]] auto create_instance() -> VkInstance
|
||||
{
|
||||
return VkInstanceCreateInfo
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,8 +1,58 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <renderer/backend/vk/messenger.hpp>
|
||||
export module renderer.backends.vk.messenger;
|
||||
|
||||
import memory.null_on_move;
|
||||
import renderer.backends.vk.instance;
|
||||
import renderer.backends.vk.raii;
|
||||
import renderer.backends.vk.library;
|
||||
import std;
|
||||
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Messenger: public IMessenger
|
||||
{
|
||||
public:
|
||||
Messenger(IInstance *instance, CreateInfo info);
|
||||
|
||||
private:
|
||||
static auto native_callback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
|
||||
void *vulkan_user_data
|
||||
) -> VkBool32;
|
||||
|
||||
[[nodiscard]] static auto to_native_severity(MessageSeverity severity)
|
||||
-> VkDebugUtilsMessageSeverityFlagsEXT;
|
||||
|
||||
[[nodiscard]] static auto from_native_severity(VkDebugUtilsMessageSeverityFlagsEXT severity)
|
||||
-> MessageSeverity;
|
||||
|
||||
[[nodiscard]] static auto to_native_type(MessageType type) -> VkDebugUtilsMessageTypeFlagsEXT;
|
||||
|
||||
[[nodiscard]] static auto from_native_type(VkDebugUtilsMessageTypeFlagsEXT type) -> MessageType;
|
||||
|
||||
class Instance *m_instance {};
|
||||
|
||||
raii::DebugMessenger m_debug_messenger;
|
||||
|
||||
MessageSeverity m_severities {};
|
||||
|
||||
MessageType m_types {};
|
||||
|
||||
Callback_T m_user_callback;
|
||||
|
||||
std::any m_user_data;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
||||
|
||||
module :private;
|
||||
using namespace lt::renderer::vk;
|
||||
|
||||
import logger;
|
||||
|
||||
Messenger::Messenger(IInstance *instance, CreateInfo info)
|
||||
: m_instance(static_cast<Instance *>(instance))
|
||||
, m_user_data(std::move(info.user_data))
|
||||
|
|
@ -162,5 +212,3 @@ Messenger::Messenger(IInstance *instance, CreateInfo info)
|
|||
|
||||
return static_cast<MessageType>(flags);
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
|
||||
|
||||
namespace lt::renderer::vk::raii {
|
||||
export namespace lt::renderer::vk::raii {
|
||||
|
||||
class DebugMessenger
|
||||
{
|
||||
8
modules/renderer/backends/vk/utils.cppm
Normal file
8
modules/renderer/backends/vk/utils.cppm
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,45 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/shader.hpp>
|
||||
#include <math/vec3.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
export module renderer.components;
|
||||
import assets.shader;
|
||||
import math.vec3;
|
||||
import memory.reference;
|
||||
import std;
|
||||
|
||||
namespace lt::renderer::components {
|
||||
|
||||
enum class VertexFormat : uint8_t
|
||||
{
|
||||
export enum class VertexFormat: std::uint8_t {
|
||||
r32_g32_b32_sfloat,
|
||||
|
||||
r32_g32_sfloat,
|
||||
};
|
||||
|
||||
enum class VertexInputRate : uint8_t
|
||||
{
|
||||
export enum class VertexInputRate: std::uint8_t {
|
||||
per_vertex,
|
||||
|
||||
per_instance,
|
||||
};
|
||||
|
||||
struct VertexInputAttributeDescriptipn
|
||||
export struct VertexInputAttributeDescriptipn
|
||||
{
|
||||
uint32_t location;
|
||||
std::uint32_t location;
|
||||
|
||||
uint32_t binding;
|
||||
std::uint32_t binding;
|
||||
|
||||
uint32_t offset;
|
||||
std::uint32_t offset;
|
||||
|
||||
VertexFormat format;
|
||||
};
|
||||
|
||||
struct VertexInputBindingDescription
|
||||
export struct VertexInputBindingDescription
|
||||
{
|
||||
uint32_t binding;
|
||||
std::uint32_t binding;
|
||||
|
||||
uint32_t stride;
|
||||
std::uint32_t stride;
|
||||
};
|
||||
|
||||
/** Requires a math::components::Transform component on the same entity to be functional. */
|
||||
struct Sprite
|
||||
export struct Sprite
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
export module renderer.data;
|
||||
|
||||
#include <math/mat4.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
struct FrameConstants
|
||||
export struct FrameConstants
|
||||
{
|
||||
math::mat4 view_projection;
|
||||
};
|
||||
|
|
@ -1,16 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/api.hpp>
|
||||
|
||||
export module.renderer.frontend.device;
|
||||
namespace lt::renderer {
|
||||
|
||||
class IDevice
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static auto create(Api target_api, class IGpu *gpu, class ISurface *surface)
|
||||
-> memory::Scope<IDevice>;
|
||||
|
||||
IDevice() = default;
|
||||
|
||||
virtual ~IDevice() = default;
|
||||
|
|
@ -1,16 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/api.hpp>
|
||||
export module renderer.frontend.gpu;
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
class IGpu
|
||||
export class IGpu
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static auto create(Api target_api, class IInstance *instance)
|
||||
-> memory::Scope<IGpu>;
|
||||
|
||||
IGpu() = default;
|
||||
|
||||
virtual ~IGpu() = default;
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <renderer/api.hpp>
|
||||
export module renderer.frontend.instance;
|
||||
import renderer.api;
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
class IInstance
|
||||
export class IInstance
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static auto get(Api target_api) -> IInstance *;
|
||||
// [[nodiscard]] static auto get(Api target_api) -> IInstance *;
|
||||
IInstance() = default;
|
||||
|
||||
virtual ~IInstance() = default;
|
||||
|
|
@ -1,21 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/entity.hpp>
|
||||
#include <math/vec2.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/api.hpp>
|
||||
export module renderer.frontend.surface;
|
||||
import ecs.entity;
|
||||
import math.vec2;
|
||||
import renderer.api;
|
||||
import memory.scope;
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
class ISurface
|
||||
export class ISurface
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static auto create(
|
||||
Api target_api,
|
||||
class IInstance *instance,
|
||||
const ecs::Entity &surface_entity
|
||||
) -> memory::Scope<ISurface>;
|
||||
|
||||
ISurface() = default;
|
||||
|
||||
virtual ~ISurface() = default;
|
||||
|
|
@ -29,3 +29,28 @@ public:
|
|||
};
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
||||
|
||||
#include <renderer/backend/vk/context/swapchain.hpp>
|
||||
#include <renderer/frontend/context/swapchain.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] /* static */ auto ISwapchain::create(
|
||||
Api target_api,
|
||||
ISurface *surface,
|
||||
IGpu *gpu,
|
||||
IDevice *device
|
||||
) -> memory::Scope<ISwapchain>
|
||||
{
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vk::Swapchain>(surface, gpu, device);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <bitwise/operations.hpp>
|
||||
#include <ecs/entity.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/api.hpp>
|
||||
export module renderer.frontend.messenger;
|
||||
import debug.assertions;
|
||||
import memory.scope;
|
||||
import renderer.api;
|
||||
import bitwise;
|
||||
import std;
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
class IMessenger
|
||||
export class IMessenger
|
||||
{
|
||||
public:
|
||||
enum class MessageSeverity : uint8_t
|
||||
enum class MessageSeverity : std::uint8_t
|
||||
{
|
||||
none = 0u,
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ public:
|
|||
all = verbose | info | warning | error,
|
||||
};
|
||||
|
||||
enum class MessageType : uint8_t
|
||||
enum class MessageType : std::uint8_t
|
||||
{
|
||||
none = 0u,
|
||||
general = bitwise::bit(0u),
|
||||
|
|
@ -72,3 +72,32 @@ public:
|
|||
};
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
||||
module :private;
|
||||
using namespace lt::renderer;
|
||||
|
||||
import renderer.backends.vk.messenger;
|
||||
|
||||
[[nodiscard]] /* static */ auto IMessenger::create(
|
||||
Api target_api,
|
||||
IInstance *instance,
|
||||
CreateInfo info
|
||||
) -> memory::Scope<IMessenger>
|
||||
{
|
||||
debug::ensure(
|
||||
info.severities != MessageSeverity::none,
|
||||
"Failed to create vk::Messenger: severities == none"
|
||||
);
|
||||
|
||||
debug::ensure(info.types != MessageType::none, "Failed to create vk::Messenger: types == none");
|
||||
|
||||
debug::ensure(info.callback, "Failed to create vk::Messenger: null callback");
|
||||
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vk::Messenger>(instance, std::move(info));
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/frontend/context/device.hpp>
|
||||
#include <renderer/frontend/context/gpu.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Device: public IDevice
|
||||
{
|
||||
public:
|
||||
Device(IGpu *gpu, ISurface *surface);
|
||||
|
||||
~Device() override;
|
||||
|
||||
Device(Device &&) = default;
|
||||
|
||||
Device(const Device &) = delete;
|
||||
|
||||
auto operator=(Device &&) -> Device & = default;
|
||||
|
||||
auto operator=(const Device &) const -> Device & = delete;
|
||||
|
||||
[[nodiscard]] auto vk() const -> VkDevice
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_family_indices() const -> std::array<uint32_t, 2>
|
||||
{
|
||||
return { m_graphics_queue_family_index, m_present_queue_family_index };
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_graphics_queue() const -> VkQueue
|
||||
{
|
||||
return m_graphics_queue;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_present_queue() const -> VkQueue
|
||||
{
|
||||
return m_present_queue;
|
||||
}
|
||||
|
||||
/** utilities */
|
||||
template<typename T, typename... Args>
|
||||
void name(const T &object, std::format_string<Args...> fmt, Args &&...args)
|
||||
{
|
||||
const auto name = std::format(fmt, std::forward<Args>(args)...);
|
||||
auto info = VkDebugUtilsObjectNameInfoEXT {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = get_object_type(object),
|
||||
.objectHandle = (uint64_t)(object),
|
||||
.pObjectName = name.c_str(),
|
||||
};
|
||||
|
||||
vk_set_debug_object_name(m_device, &info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void name(const T &object, const char *name)
|
||||
{
|
||||
auto info = VkDebugUtilsObjectNameInfoEXT {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = get_object_type(object),
|
||||
.objectHandle = (uint64_t)(object),
|
||||
.pObjectName = name,
|
||||
};
|
||||
|
||||
vk_set_debug_object_name(m_device, &info);
|
||||
}
|
||||
|
||||
|
||||
/** work functions */
|
||||
void submit(VkSubmitInfo info, VkFence fence) const;
|
||||
|
||||
void present(VkPresentInfoKHR info) const;
|
||||
|
||||
void wait_idle() const;
|
||||
|
||||
void wait_for_fence(VkFence fence) const;
|
||||
|
||||
void wait_for_fences(std::span<VkFence> fences) const;
|
||||
|
||||
void reset_fence(VkFence fence) const;
|
||||
|
||||
void reset_fences(std::span<VkFence> fences) const;
|
||||
|
||||
/** getter functions */
|
||||
[[nodiscard]] auto acquire_image(
|
||||
VkSwapchainKHR swapchain,
|
||||
VkSemaphore semaphore,
|
||||
uint64_t timeout = 100'000'000
|
||||
) -> std::optional<uint32_t>;
|
||||
|
||||
[[nodiscard]] auto get_swapchain_images(VkSwapchainKHR swapchain) const -> std::vector<VkImage>;
|
||||
|
||||
[[nodiscard]] auto get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements;
|
||||
|
||||
/** binders / mappers */
|
||||
void bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset = 0u) const;
|
||||
|
||||
[[nodiscard]] auto map_memory(VkDeviceMemory memory, size_t size, size_t offset) const
|
||||
-> std::span<std::byte>;
|
||||
|
||||
void unmap_memory(VkDeviceMemory memory);
|
||||
|
||||
/** create functions */
|
||||
[[nodiscard]] auto create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR;
|
||||
|
||||
[[nodiscard]] auto create_framebuffer(VkFramebufferCreateInfo info) const -> VkFramebuffer;
|
||||
|
||||
[[nodiscard]] auto create_image_view(VkImageViewCreateInfo info) const -> VkImageView;
|
||||
|
||||
[[nodiscard]] auto create_graphics_pipeline(VkGraphicsPipelineCreateInfo info) const
|
||||
-> VkPipeline;
|
||||
|
||||
[[nodiscard]] auto create_pass(VkRenderPassCreateInfo info) const -> VkRenderPass;
|
||||
|
||||
[[nodiscard]] auto create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> descriptor_set_layout,
|
||||
std::vector<VkPushConstantRange> push_constant_ranges
|
||||
) const -> VkPipelineLayout;
|
||||
|
||||
[[nodiscard]] auto create_shader_module(VkShaderModuleCreateInfo info) const -> VkShaderModule;
|
||||
|
||||
[[nodiscard]] auto create_command_pool(VkCommandPoolCreateInfo info) const -> VkCommandPool;
|
||||
|
||||
[[nodiscard]] auto create_semaphores(uint32_t count) const -> std::vector<VkSemaphore>;
|
||||
|
||||
[[nodiscard]] auto create_fences(VkFenceCreateInfo info, uint32_t count) const
|
||||
-> std::vector<VkFence>;
|
||||
|
||||
[[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer;
|
||||
|
||||
[[nodiscard]] auto create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const
|
||||
-> VkDescriptorSetLayout;
|
||||
|
||||
[[nodiscard]] auto create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const
|
||||
-> VkDescriptorPool;
|
||||
|
||||
/** allocation functions */
|
||||
[[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory;
|
||||
|
||||
[[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const
|
||||
-> std::vector<VkCommandBuffer>;
|
||||
|
||||
[[nodiscard]] auto allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const
|
||||
-> VkDescriptorSet;
|
||||
|
||||
/** de-allocation functions */
|
||||
void free_memory(VkDeviceMemory memory) const;
|
||||
|
||||
void free_descriptor_set(
|
||||
VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const;
|
||||
|
||||
/** destroy functions */
|
||||
void destroy_swapchain(VkSwapchainKHR swapchain) const;
|
||||
|
||||
void destroy_framebuffer(VkFramebuffer framebuffer) const;
|
||||
|
||||
void destroy_framebuffers(std::span<VkFramebuffer> framebuffers) const;
|
||||
|
||||
void destroy_image_view(VkImageView image_view) const;
|
||||
|
||||
void destroy_image_views(std::span<VkImageView> image_views) const;
|
||||
|
||||
void destroy_pipeline(VkPipeline pipeline) const;
|
||||
|
||||
void destroy_pass(VkRenderPass pass) const;
|
||||
|
||||
void destroy_pipeline_layout(VkPipelineLayout pipeline_layout) const;
|
||||
|
||||
void destroy_shader_module(VkShaderModule shader_module) const;
|
||||
|
||||
void destroy_command_pool(VkCommandPool command_pool) const;
|
||||
|
||||
void destroy_semaphore(VkSemaphore semaphore) const;
|
||||
|
||||
void destroy_semaphores(std::span<VkSemaphore> semaphores) const;
|
||||
|
||||
void destroy_fence(VkFence fence) const;
|
||||
|
||||
void destroy_fences(std::span<VkFence> fences) const;
|
||||
|
||||
void destroy_buffer(VkBuffer buffer) const;
|
||||
|
||||
void destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const;
|
||||
|
||||
void destroy_descriptor_pool(VkDescriptorPool pool) const;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static auto get_object_type(const T &object) -> VkObjectType
|
||||
{
|
||||
std::ignore = object;
|
||||
|
||||
if constexpr (std::is_same_v<T, VkQueue>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_QUEUE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkFence>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_FENCE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkSemaphore>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_SEMAPHORE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkSwapchainKHR>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_SWAPCHAIN_KHR;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkImage>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_IMAGE;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, VkImageView>)
|
||||
{
|
||||
return VK_OBJECT_TYPE_IMAGE_VIEW;
|
||||
}
|
||||
|
||||
static_assert("invalid type");
|
||||
}
|
||||
|
||||
|
||||
void initialize_physical_device();
|
||||
|
||||
void initialize_logical_device();
|
||||
|
||||
void initialize_queue_indices();
|
||||
|
||||
[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
|
||||
|
||||
memory::NullOnMove<class Gpu *> m_gpu {};
|
||||
|
||||
class Surface *m_surface {};
|
||||
|
||||
VkAllocationCallbacks *m_allocator = nullptr;
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
|
||||
VkQueue m_graphics_queue = VK_NULL_HANDLE;
|
||||
|
||||
VkQueue m_present_queue = VK_NULL_HANDLE;
|
||||
|
||||
uint32_t m_graphics_queue_family_index = VK_QUEUE_FAMILY_IGNORED;
|
||||
|
||||
uint32_t m_present_queue_family_index = VK_QUEUE_FAMILY_IGNORED;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
#include <renderer/backend/vk/context/instance.hpp>
|
||||
#include <renderer/backend/vk/utils.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
Gpu::Gpu(IInstance *instance)
|
||||
: m_descriptor_indexing_features(
|
||||
{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES }
|
||||
)
|
||||
{
|
||||
auto gpus = static_cast<Instance *>(instance)->enumerate_gpus();
|
||||
|
||||
for (auto &gpu : gpus)
|
||||
{
|
||||
auto properties = VkPhysicalDeviceProperties {};
|
||||
auto features = VkPhysicalDeviceFeatures2 {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
.pNext = &m_descriptor_indexing_features
|
||||
};
|
||||
|
||||
vk_get_physical_device_properties(gpu, &properties);
|
||||
vk_get_physical_device_features(gpu, &features);
|
||||
|
||||
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|
||||
&& features.features.geometryShader)
|
||||
{
|
||||
m_gpu = gpu;
|
||||
}
|
||||
}
|
||||
ensure(m_gpu, "Failed to find any suitable Vulkan physical device");
|
||||
|
||||
|
||||
vk_get_physical_device_memory_properties(m_gpu, &m_memory_properties);
|
||||
|
||||
auto count = uint32_t { 0u };
|
||||
vk_get_physical_device_queue_family_properties(m_gpu, &count, nullptr);
|
||||
m_queue_family_properties.resize(count);
|
||||
vk_get_physical_device_queue_family_properties(m_gpu, &count, m_queue_family_properties.data());
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::queue_family_supports_presentation(
|
||||
VkSurfaceKHR surface,
|
||||
uint32_t queue_family_idx
|
||||
) -> bool
|
||||
{
|
||||
auto supported = VkBool32 { false };
|
||||
vkc(vk_get_physical_device_surface_support(m_gpu, queue_family_idx, surface, &supported));
|
||||
|
||||
return supported;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::get_surface_capabilities(VkSurfaceKHR surface) const
|
||||
-> VkSurfaceCapabilitiesKHR
|
||||
{
|
||||
auto capabilities = VkSurfaceCapabilitiesKHR {};
|
||||
vkc(vk_get_physical_device_surface_capabilities(m_gpu, surface, &capabilities));
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::get_surface_formats(VkSurfaceKHR surface) const
|
||||
-> std::vector<VkSurfaceFormatKHR>
|
||||
{
|
||||
auto count = uint32_t { 0u };
|
||||
vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, nullptr));
|
||||
|
||||
auto formats = std::vector<VkSurfaceFormatKHR>(count);
|
||||
vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, formats.data()));
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::create_device(VkDeviceCreateInfo info) const -> VkDevice
|
||||
{
|
||||
auto *device = VkDevice {};
|
||||
vkc(vk_create_device(m_gpu, &info, nullptr, &device));
|
||||
return device;
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/frontend/context/gpu.hpp>
|
||||
#include <renderer/frontend/context/instance.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Gpu: public IGpu
|
||||
{
|
||||
public:
|
||||
Gpu(IInstance *instance);
|
||||
|
||||
[[nodiscard]] auto queue_family_supports_presentation(
|
||||
VkSurfaceKHR surface,
|
||||
uint32_t queue_family_idx
|
||||
) -> bool;
|
||||
|
||||
[[nodiscard]] auto get_surface_capabilities(VkSurfaceKHR surface) const
|
||||
-> VkSurfaceCapabilitiesKHR;
|
||||
|
||||
[[nodiscard]] auto get_surface_formats(VkSurfaceKHR surface) const
|
||||
-> std::vector<VkSurfaceFormatKHR>;
|
||||
|
||||
[[nodiscard]] auto create_device(VkDeviceCreateInfo info) const -> VkDevice;
|
||||
|
||||
[[nodiscard]] auto get_properties() const -> VkPhysicalDeviceProperties
|
||||
{
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_descriptor_indexing_features() const
|
||||
-> VkPhysicalDeviceDescriptorIndexingFeatures
|
||||
{
|
||||
return m_descriptor_indexing_features;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_memory_properties() const -> VkPhysicalDeviceMemoryProperties
|
||||
{
|
||||
return m_memory_properties;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_queue_family_properties() const -> std::vector<VkQueueFamilyProperties>
|
||||
{
|
||||
return m_queue_family_properties;
|
||||
}
|
||||
|
||||
private:
|
||||
memory::NullOnMove<VkPhysicalDevice> m_gpu = VK_NULL_HANDLE;
|
||||
|
||||
VkPhysicalDeviceProperties m_properties {};
|
||||
|
||||
VkPhysicalDeviceDescriptorIndexingFeatures m_descriptor_indexing_features;
|
||||
|
||||
VkPhysicalDeviceMemoryProperties m_memory_properties {};
|
||||
|
||||
std::vector<VkQueueFamilyProperties> m_queue_family_properties;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,457 +0,0 @@
|
|||
#include <app/system.hpp>
|
||||
#include <renderer/backend/vk/context/instance.hpp>
|
||||
#include <renderer/backend/vk/utils.hpp>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#error "Unsupported platform (currently)"
|
||||
#elif defined(__unix__)
|
||||
#include <dlfcn.h>
|
||||
namespace {
|
||||
void *library = nullptr; // NOLINT
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
// global functions
|
||||
PFN_vkGetInstanceProcAddr vk_get_instance_proc_address {};
|
||||
PFN_vkCreateInstance vk_create_instance {};
|
||||
PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties {};
|
||||
PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties {};
|
||||
|
||||
// instance functions
|
||||
PFN_vkDestroyInstance vk_destroy_instance {};
|
||||
PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices {};
|
||||
PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties {};
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties {};
|
||||
PFN_vkCreateDevice vk_create_device {};
|
||||
PFN_vkGetDeviceProcAddr vk_get_device_proc_address {};
|
||||
PFN_vkDestroyDevice vk_destroy_device {};
|
||||
PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features {};
|
||||
PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties {};
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties {};
|
||||
|
||||
// extension instance functions
|
||||
PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label {};
|
||||
PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label {};
|
||||
PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label {};
|
||||
PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger {};
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger {};
|
||||
PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label {};
|
||||
PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label {};
|
||||
PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label {};
|
||||
PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name {};
|
||||
PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag {};
|
||||
PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message {};
|
||||
|
||||
// device functions
|
||||
PFN_vkGetDeviceQueue vk_get_device_queue {};
|
||||
PFN_vkCreateCommandPool vk_create_command_pool {};
|
||||
PFN_vkDestroyCommandPool vk_destroy_command_pool {};
|
||||
PFN_vkAllocateCommandBuffers vk_allocate_command_buffers {};
|
||||
PFN_vkFreeCommandBuffers vk_free_command_buffers {};
|
||||
PFN_vkBeginCommandBuffer vk_begin_command_buffer {};
|
||||
PFN_vkEndCommandBuffer vk_end_command_buffer {};
|
||||
PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier {};
|
||||
PFN_vkQueueSubmit vk_queue_submit {};
|
||||
PFN_vkQueueWaitIdle vk_queue_wait_idle {};
|
||||
PFN_vkDeviceWaitIdle vk_device_wait_idle {};
|
||||
PFN_vkCreateFence vk_create_fence {};
|
||||
PFN_vkDestroyFence vk_destroy_fence {};
|
||||
PFN_vkWaitForFences vk_wait_for_fences {};
|
||||
PFN_vkResetFences vk_reset_fences {};
|
||||
PFN_vkCreateSemaphore vk_create_semaphore {};
|
||||
PFN_vkDestroySemaphore vk_destroy_semaphore {};
|
||||
PFN_vkCreateSwapchainKHR vk_create_swapchain_khr {};
|
||||
PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr {};
|
||||
PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr {};
|
||||
PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr {};
|
||||
PFN_vkQueuePresentKHR vk_queue_present_khr {};
|
||||
PFN_vkCreateImageView vk_create_image_view {};
|
||||
PFN_vkDestroyImageView vk_destroy_image_view {};
|
||||
PFN_vkCreateRenderPass vk_create_render_pass {};
|
||||
PFN_vkDestroyRenderPass vk_destroy_render_pass {};
|
||||
PFN_vkCreateFramebuffer vk_create_frame_buffer {};
|
||||
PFN_vkDestroyFramebuffer vk_destroy_frame_buffer {};
|
||||
PFN_vkCreateShaderModule vk_create_shader_module {};
|
||||
PFN_vkDestroyShaderModule vk_destroy_shader_module {};
|
||||
PFN_vkCreatePipelineLayout vk_create_pipeline_layout {};
|
||||
PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout {};
|
||||
PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines {};
|
||||
PFN_vkDestroyPipeline vk_destroy_pipeline {};
|
||||
PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass {};
|
||||
PFN_vkCmdEndRenderPass vk_cmd_end_render_pass {};
|
||||
PFN_vkCmdBindPipeline vk_cmd_bind_pipeline {};
|
||||
PFN_vkCmdDraw vk_cmd_draw {};
|
||||
PFN_vkCmdSetViewport vk_cmd_set_viewport {};
|
||||
PFN_vkCmdSetScissor vk_cmd_set_scissors {};
|
||||
PFN_vkCmdPushConstants vk_cmd_push_constants {};
|
||||
PFN_vkCmdCopyBuffer vk_cmd_copy_buffer {};
|
||||
|
||||
PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout {};
|
||||
PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout {};
|
||||
PFN_vkCreateDescriptorPool vk_create_descriptor_pool {};
|
||||
PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool {};
|
||||
PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets {};
|
||||
PFN_vkFreeDescriptorSets vk_free_descriptor_sets {};
|
||||
|
||||
PFN_vkCreateBuffer vk_create_buffer {};
|
||||
PFN_vkDestroyBuffer vk_destroy_buffer {};
|
||||
PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements {};
|
||||
PFN_vkAllocateMemory vk_allocate_memory {};
|
||||
PFN_vkBindBufferMemory vk_bind_buffer_memory {};
|
||||
PFN_vkMapMemory vk_map_memory {};
|
||||
PFN_vkUnmapMemory vk_unmap_memory {};
|
||||
PFN_vkFreeMemory vk_free_memory {};
|
||||
|
||||
PFN_vkResetCommandBuffer vk_reset_command_buffer {};
|
||||
|
||||
PFN_vkCmdBeginRendering vk_cmd_begin_rendering {};
|
||||
PFN_vkCmdEndRendering vk_cmd_end_rendering {};
|
||||
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {};
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {};
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {};
|
||||
|
||||
auto vk_create_xlib_surface_khr = PFN_vkCreateXlibSurfaceKHR {};
|
||||
auto vk_destroy_surface_khr = PFN_vkDestroySurfaceKHR {};
|
||||
|
||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
Instance::Instance()
|
||||
{
|
||||
load_library();
|
||||
load_global_functions();
|
||||
|
||||
initialize_instance();
|
||||
load_instance_functions();
|
||||
}
|
||||
|
||||
Instance::~Instance()
|
||||
{
|
||||
vk_destroy_instance(m_instance, nullptr);
|
||||
unload_library();
|
||||
}
|
||||
|
||||
void Instance::initialize_instance()
|
||||
{
|
||||
auto app_info = VkApplicationInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pApplicationName = "Hallo Hallo Hallo :3",
|
||||
.applicationVersion = VK_MAKE_VERSION(1, 4, 0),
|
||||
.pEngineName = "light",
|
||||
.engineVersion = VK_MAKE_VERSION(1, 4, 0),
|
||||
.apiVersion = VK_API_VERSION_1_4,
|
||||
};
|
||||
|
||||
auto extensions = std::vector<const char *> {
|
||||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
const char *layer_name = "VK_LAYER_KHRONOS_validation";
|
||||
const auto setting_validate_core = VkBool32 { VK_TRUE };
|
||||
const auto setting_validate_sync = VkBool32 { VK_TRUE };
|
||||
const auto setting_thread_safety = VkBool32 { VK_TRUE };
|
||||
const auto *setting_debug_action = "";
|
||||
const auto setting_enable_message_limit = VkBool32 { VK_TRUE };
|
||||
const auto setting_duplicate_message_limit = uint32_t { UINT32_MAX };
|
||||
auto setting_report_flags = std::array<const char *, 5> {
|
||||
"info", "warn", "perf", "error", "verbose",
|
||||
};
|
||||
|
||||
const auto settings = std::array<VkLayerSettingEXT, 7>({
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer_name,
|
||||
.pSettingName = "validate_core",
|
||||
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||
.valueCount = 1,
|
||||
.pValues = &setting_validate_core,
|
||||
},
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer_name,
|
||||
.pSettingName = "validate_sync",
|
||||
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||
.valueCount = 1,
|
||||
.pValues = &setting_validate_sync,
|
||||
},
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer_name,
|
||||
.pSettingName = "thread_safety",
|
||||
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||
.valueCount = 1,
|
||||
.pValues = &setting_thread_safety,
|
||||
},
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer_name,
|
||||
.pSettingName = "debug_action",
|
||||
.type = VK_LAYER_SETTING_TYPE_STRING_EXT,
|
||||
.valueCount = 1,
|
||||
.pValues = static_cast<const void *>(&setting_debug_action),
|
||||
},
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer_name,
|
||||
.pSettingName = "report_flags",
|
||||
.type = VK_LAYER_SETTING_TYPE_STRING_EXT,
|
||||
.valueCount = setting_report_flags.size(),
|
||||
.pValues = static_cast<const void *>(setting_report_flags.data()),
|
||||
},
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer_name,
|
||||
.pSettingName = "enable_message_limit",
|
||||
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||
.valueCount = 1,
|
||||
.pValues = &setting_enable_message_limit,
|
||||
},
|
||||
VkLayerSettingEXT {
|
||||
.pLayerName = layer_name,
|
||||
.pSettingName = "duplicate_message_limit",
|
||||
.type = VK_LAYER_SETTING_TYPE_UINT32_EXT,
|
||||
.valueCount = 1u,
|
||||
.pValues = &setting_duplicate_message_limit,
|
||||
},
|
||||
});
|
||||
|
||||
const VkLayerSettingsCreateInfoEXT layer_settings_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
|
||||
.settingCount = settings.size(),
|
||||
.pSettings = settings.data(),
|
||||
};
|
||||
|
||||
auto layers = std::vector<const char *> {
|
||||
"VK_LAYER_KHRONOS_validation",
|
||||
};
|
||||
|
||||
auto instance_info = VkInstanceCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pNext = &layer_settings_create_info,
|
||||
.pApplicationInfo = &app_info,
|
||||
.enabledLayerCount = static_cast<uint32_t>(layers.size()),
|
||||
.ppEnabledLayerNames = layers.data(),
|
||||
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
|
||||
.ppEnabledExtensionNames = extensions.data(),
|
||||
};
|
||||
|
||||
{
|
||||
auto count = 0u;
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr));
|
||||
|
||||
auto extensions = std::vector<VkExtensionProperties>(count);
|
||||
memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties));
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data()));
|
||||
|
||||
// log::info("Available vulkan instance extensions:");
|
||||
for (auto &ext : extensions)
|
||||
{
|
||||
// log::info("\t{} @ {}", ext.extensionName, ext.specVersion);
|
||||
}
|
||||
}
|
||||
|
||||
vkc(vk_create_instance(&instance_info, nullptr, &m_instance));
|
||||
ensure(m_instance, "Failed to create vulkan instance");
|
||||
}
|
||||
|
||||
void Instance::load_library()
|
||||
{
|
||||
constexpr auto runtime_loader_flags = RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE;
|
||||
library = dlopen("libvulkan.so.1", runtime_loader_flags);
|
||||
if (!library)
|
||||
{
|
||||
library = dlopen("libvulkan.so", runtime_loader_flags);
|
||||
}
|
||||
ensure(library, "Failed to dlopen vulkan library");
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
vk_get_instance_proc_address = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
|
||||
dlsym(library, "vkGetInstanceProcAddr")
|
||||
);
|
||||
ensure(vk_get_instance_proc_address, "Failed to load vulkan function: vkGetInstanceProcAddr");
|
||||
}
|
||||
|
||||
void Instance::unload_library()
|
||||
{
|
||||
if (!library)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// calling dlclose causes many issues with runtime analyzers
|
||||
// eg. https://github.com/google/sanitizers/issues/89
|
||||
// with no noticable gains, so we just don't bother closing it.
|
||||
|
||||
// dlclose(library);
|
||||
// library = nullptr;
|
||||
}
|
||||
|
||||
void Instance::load_global_functions()
|
||||
{
|
||||
constexpr auto load_fn = []<typename T>(T &pfn, const char *fn_name) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_instance_proc_address(nullptr, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan global function: {}", fn_name);
|
||||
// log::trace("Loaded global function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_create_instance, "vkCreateInstance");
|
||||
load_fn(vk_enumerate_instance_extension_properties, "vkEnumerateInstanceExtensionProperties");
|
||||
load_fn(vk_enumerate_instance_layer_properties, "vkEnumerateInstanceLayerProperties");
|
||||
}
|
||||
|
||||
void Instance::load_instance_functions()
|
||||
{
|
||||
const auto load_fn = [&]<typename T>(T &pfn, const char *fn_name) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_instance_proc_address(m_instance, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan instance function: {}", fn_name);
|
||||
// log::trace("Loaded instance function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_destroy_instance, "vkDestroyInstance");
|
||||
load_fn(vk_enumerate_physical_devices, "vkEnumeratePhysicalDevices");
|
||||
load_fn(vk_get_physical_device_properties, "vkGetPhysicalDeviceProperties");
|
||||
load_fn(
|
||||
vk_get_physical_device_queue_family_properties,
|
||||
"vkGetPhysicalDeviceQueueFamilyProperties"
|
||||
);
|
||||
load_fn(vk_create_device, "vkCreateDevice");
|
||||
load_fn(vk_get_device_proc_address, "vkGetDeviceProcAddr");
|
||||
load_fn(vk_destroy_device, "vkDestroyDevice");
|
||||
load_fn(vk_get_physical_device_features, "vkGetPhysicalDeviceFeatures");
|
||||
load_fn(vk_enumerate_device_extension_properties, "vkEnumerateDeviceExtensionProperties");
|
||||
load_fn(vk_get_physical_device_memory_properties, "vkGetPhysicalDeviceMemoryProperties");
|
||||
|
||||
load_fn(vk_cmd_begin_debug_label, "vkCmdBeginDebugUtilsLabelEXT");
|
||||
load_fn(vk_cmd_end_debug_label, "vkCmdEndDebugUtilsLabelEXT");
|
||||
load_fn(vk_cmd_insert_debug_label, "vkCmdInsertDebugUtilsLabelEXT");
|
||||
load_fn(vk_create_debug_messenger, "vkCreateDebugUtilsMessengerEXT");
|
||||
load_fn(vk_destroy_debug_messenger, "vkDestroyDebugUtilsMessengerEXT");
|
||||
load_fn(vk_queue_begin_debug_label, "vkQueueBeginDebugUtilsLabelEXT");
|
||||
load_fn(vk_queue_end_debug_label, "vkQueueEndDebugUtilsLabelEXT");
|
||||
load_fn(vk_queue_insert_debug_label, "vkQueueInsertDebugUtilsLabelEXT");
|
||||
load_fn(vk_set_debug_object_name, "vkSetDebugUtilsObjectNameEXT");
|
||||
load_fn(vk_set_debug_object_tag, "vkSetDebugUtilsObjectTagEXT");
|
||||
load_fn(vk_submit_debug_message, "vkSubmitDebugUtilsMessageEXT");
|
||||
|
||||
load_fn(vk_get_physical_device_surface_support, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
||||
load_fn(
|
||||
vk_get_physical_device_surface_capabilities,
|
||||
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"
|
||||
);
|
||||
load_fn(vk_get_physical_device_surface_formats, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||
load_fn(vk_create_xlib_surface_khr, "vkCreateXlibSurfaceKHR");
|
||||
load_fn(vk_destroy_surface_khr, "vkDestroySurfaceKHR");
|
||||
}
|
||||
|
||||
void Instance::load_device_functions_impl(VkDevice device)
|
||||
{
|
||||
const auto load_fn = [&]<typename T>(T &pfn, const char *fn_name) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_device_proc_address(device, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan device function: {}", fn_name);
|
||||
// log::trace("Loaded device function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_get_device_queue, "vkGetDeviceQueue");
|
||||
load_fn(vk_create_command_pool, "vkCreateCommandPool");
|
||||
load_fn(vk_destroy_command_pool, "vkDestroyCommandPool");
|
||||
load_fn(vk_allocate_command_buffers, "vkAllocateCommandBuffers");
|
||||
load_fn(vk_free_command_buffers, "vkFreeCommandBuffers");
|
||||
load_fn(vk_begin_command_buffer, "vkBeginCommandBuffer");
|
||||
load_fn(vk_end_command_buffer, "vkEndCommandBuffer");
|
||||
load_fn(vk_cmd_pipeline_barrier, "vkCmdPipelineBarrier");
|
||||
load_fn(vk_queue_submit, "vkQueueSubmit");
|
||||
load_fn(vk_queue_wait_idle, "vkQueueWaitIdle");
|
||||
load_fn(vk_device_wait_idle, "vkDeviceWaitIdle");
|
||||
load_fn(vk_create_fence, "vkCreateFence");
|
||||
load_fn(vk_destroy_fence, "vkDestroyFence");
|
||||
load_fn(vk_wait_for_fences, "vkWaitForFences");
|
||||
load_fn(vk_reset_fences, "vkResetFences");
|
||||
load_fn(vk_create_semaphore, "vkCreateSemaphore");
|
||||
load_fn(vk_destroy_semaphore, "vkDestroySemaphore");
|
||||
load_fn(vk_create_swapchain_khr, "vkCreateSwapchainKHR");
|
||||
load_fn(vk_destroy_swapchain_khr, "vkDestroySwapchainKHR");
|
||||
load_fn(vk_get_swapchain_images_khr, "vkGetSwapchainImagesKHR");
|
||||
load_fn(vk_acquire_next_image_khr, "vkAcquireNextImageKHR");
|
||||
load_fn(vk_queue_present_khr, "vkQueuePresentKHR");
|
||||
load_fn(vk_create_image_view, "vkCreateImageView");
|
||||
load_fn(vk_destroy_image_view, "vkDestroyImageView");
|
||||
load_fn(vk_create_render_pass, "vkCreateRenderPass");
|
||||
load_fn(vk_destroy_render_pass, "vkDestroyRenderPass");
|
||||
load_fn(vk_create_frame_buffer, "vkCreateFramebuffer");
|
||||
load_fn(vk_destroy_frame_buffer, "vkDestroyFramebuffer");
|
||||
load_fn(vk_create_shader_module, "vkCreateShaderModule");
|
||||
load_fn(vk_destroy_shader_module, "vkDestroyShaderModule");
|
||||
load_fn(vk_create_pipeline_layout, "vkCreatePipelineLayout");
|
||||
load_fn(vk_destroy_pipeline_layout, "vkDestroyPipelineLayout");
|
||||
load_fn(vk_create_graphics_pipelines, "vkCreateGraphicsPipelines");
|
||||
load_fn(vk_destroy_pipeline, "vkDestroyPipeline");
|
||||
load_fn(vk_cmd_begin_render_pass, "vkCmdBeginRenderPass");
|
||||
load_fn(vk_cmd_end_render_pass, "vkCmdEndRenderPass");
|
||||
load_fn(vk_cmd_bind_pipeline, "vkCmdBindPipeline");
|
||||
load_fn(vk_cmd_draw, "vkCmdDraw");
|
||||
load_fn(vk_cmd_set_viewport, "vkCmdSetViewport");
|
||||
load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
|
||||
load_fn(vk_cmd_push_constants, "vkCmdPushConstants");
|
||||
load_fn(vk_cmd_copy_buffer, "vkCmdCopyBuffer");
|
||||
load_fn(vk_create_descriptor_set_layout, "vkCreateDescriptorSetLayout");
|
||||
load_fn(vk_destroy_descriptor_set_layout, "vkDestroyDescriptorSetLayout");
|
||||
load_fn(vk_create_descriptor_pool, "vkCreateDescriptorPool");
|
||||
load_fn(vk_destroy_descriptor_pool, "vkDestroyDescriptorPool");
|
||||
load_fn(vk_allocate_descriptor_sets, "vkAllocateDescriptorSets");
|
||||
load_fn(vk_free_descriptor_sets, "vkFreeDescriptorSets");
|
||||
load_fn(vk_create_buffer, "vkCreateBuffer");
|
||||
load_fn(vk_destroy_buffer, "vkDestroyBuffer");
|
||||
load_fn(vk_allocate_memory, "vkAllocateMemory");
|
||||
load_fn(vk_bind_buffer_memory, "vkBindBufferMemory");
|
||||
load_fn(vk_map_memory, "vkMapMemory");
|
||||
load_fn(vk_unmap_memory, "vkUnmapMemory");
|
||||
load_fn(vk_free_memory, "vkFreeMemory");
|
||||
load_fn(vk_get_buffer_memory_requirements, "vkGetBufferMemoryRequirements");
|
||||
load_fn(vk_reset_command_buffer, "vkResetCommandBuffer");
|
||||
|
||||
load_fn(vk_cmd_begin_rendering, "vkCmdBeginRendering");
|
||||
load_fn(vk_cmd_end_rendering, "vkCmdEndRendering");
|
||||
}
|
||||
|
||||
auto Instance::enumerate_gpus() const -> std::vector<VkPhysicalDevice>
|
||||
{
|
||||
auto count = 0u;
|
||||
vkc(vk_enumerate_physical_devices(m_instance, &count, nullptr));
|
||||
ensure(count != 0u, "Failed to find any gpus with Vulkan support");
|
||||
|
||||
auto gpus = std::vector<VkPhysicalDevice>(count);
|
||||
vkc(vk_enumerate_physical_devices(m_instance, &count, gpus.data()));
|
||||
return gpus;
|
||||
}
|
||||
|
||||
auto Instance::create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const -> VkSurfaceKHR
|
||||
{
|
||||
auto *value = VkSurfaceKHR {};
|
||||
vk_create_xlib_surface_khr(m_instance, &info, m_allocator, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Instance::create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const
|
||||
-> VkDebugUtilsMessengerEXT
|
||||
{
|
||||
auto *messenger = VkDebugUtilsMessengerEXT {};
|
||||
vkc(vk_create_debug_messenger(m_instance, &info, m_allocator, &messenger));
|
||||
return messenger;
|
||||
}
|
||||
|
||||
void Instance::destroy_surface(VkSurfaceKHR surface) const
|
||||
{
|
||||
vk_destroy_surface_khr(m_instance, surface, m_allocator);
|
||||
}
|
||||
|
||||
void Instance::destroy_messenger(VkDebugUtilsMessengerEXT messenger) const
|
||||
{
|
||||
vk_destroy_debug_messenger(m_instance, messenger, m_allocator);
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/frontend/context/instance.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
/**
|
||||
* Responsible for dynamically loading Vulkan library/functions.
|
||||
*
|
||||
* @note: The delayed vkInstance destruction is due to a work-around for a libx11 quirk:
|
||||
* @ref:
|
||||
* https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/commit/0017308648b6bf8eef10ef0ffb9470576c0c2e9e
|
||||
* https://www.xfree86.org/4.7.0/DRI11.html
|
||||
* https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/1894
|
||||
*/
|
||||
class Instance: public IInstance
|
||||
{
|
||||
public:
|
||||
static auto get() -> IInstance *
|
||||
{
|
||||
return &Instance::instance();
|
||||
}
|
||||
|
||||
static auto load_device_functions(VkDevice device)
|
||||
{
|
||||
static_cast<Instance &>(instance()).load_device_functions_impl(device);
|
||||
}
|
||||
|
||||
~Instance() override;
|
||||
|
||||
Instance(Instance &&) = delete;
|
||||
|
||||
Instance(const Instance &) = delete;
|
||||
|
||||
auto operator=(const Instance &) -> Instance & = delete;
|
||||
|
||||
auto operator=(Instance &&) -> Instance & = delete;
|
||||
|
||||
[[nodiscard]] auto vk() const -> VkInstance
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
/* create functions */
|
||||
[[nodiscard]] auto create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const -> VkSurfaceKHR;
|
||||
|
||||
[[nodiscard]] auto create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const
|
||||
-> VkDebugUtilsMessengerEXT;
|
||||
|
||||
/* destroy functions */
|
||||
void destroy_surface(VkSurfaceKHR surface) const;
|
||||
|
||||
void destroy_messenger(VkDebugUtilsMessengerEXT messenger) const;
|
||||
|
||||
[[nodiscard]] auto enumerate_gpus() const -> std::vector<VkPhysicalDevice>;
|
||||
|
||||
private:
|
||||
static auto instance() -> IInstance &
|
||||
{
|
||||
static auto instance = Instance {};
|
||||
return instance;
|
||||
}
|
||||
|
||||
Instance();
|
||||
|
||||
void initialize_instance();
|
||||
|
||||
void load_library();
|
||||
|
||||
void unload_library();
|
||||
|
||||
void load_global_functions();
|
||||
|
||||
void load_instance_functions();
|
||||
|
||||
void load_device_functions_impl(VkDevice device);
|
||||
VkInstance m_instance = VK_NULL_HANDLE;
|
||||
|
||||
VkAllocationCallbacks *m_allocator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#include <renderer/backend/vk/context/instance.hpp>
|
||||
#include <renderer/backend/vk/context/surface.hpp>
|
||||
#include <surface/components.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
Surface::Surface(IInstance *instance, const ecs::Entity &surface_entity)
|
||||
: m_surface_entity(surface_entity)
|
||||
, m_instance(static_cast<Instance *>(instance))
|
||||
{
|
||||
const auto &component = surface_entity.get<surface::SurfaceComponent>();
|
||||
|
||||
ensure(component.get_native_data().display, "Failed to initialize vk::Surface: null x-display");
|
||||
ensure(component.get_native_data().window, "Failed to initialize vk::Surface: null x-window");
|
||||
|
||||
m_surface = m_instance->create_xlib_surface(
|
||||
VkXlibSurfaceCreateInfoKHR {
|
||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||
.dpy = component.get_native_data().display,
|
||||
.window = component.get_native_data().window,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Surface::~Surface()
|
||||
{
|
||||
if (!m_instance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_instance->destroy_surface(m_surface);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Surface::get_framebuffer_size() const -> math::uvec2
|
||||
{
|
||||
return m_surface_entity.get<surface::SurfaceComponent>().get_resolution();
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/entity.hpp>
|
||||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/frontend/context/instance.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Instance;
|
||||
|
||||
class Surface: public ISurface
|
||||
{
|
||||
public:
|
||||
Surface(IInstance *instance, const ecs::Entity &surface_entity);
|
||||
|
||||
~Surface() override;
|
||||
|
||||
Surface(Surface &&) = default;
|
||||
|
||||
Surface(const Surface &) = delete;
|
||||
|
||||
auto operator=(Surface &&) -> Surface & = default;
|
||||
|
||||
auto operator=(const Surface &) const -> Surface & = delete;
|
||||
|
||||
[[nodiscard]] auto vk() const -> VkSurfaceKHR
|
||||
{
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_framebuffer_size() const -> math::uvec2 override;
|
||||
|
||||
private:
|
||||
class Instance *m_instance {};
|
||||
|
||||
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||
|
||||
ecs::Entity m_surface_entity;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/utils.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/frontend/context/device.hpp>
|
||||
#include <renderer/frontend/context/gpu.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
#include <renderer/frontend/context/swapchain.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Swapchain: public ISwapchain
|
||||
{
|
||||
public:
|
||||
Swapchain(ISurface *surface, IGpu *gpu, IDevice *device);
|
||||
~Swapchain() override;
|
||||
|
||||
Swapchain(Swapchain &&) = default;
|
||||
|
||||
Swapchain(const Swapchain &) = delete;
|
||||
|
||||
auto operator=(Swapchain &&) -> Swapchain & = default;
|
||||
|
||||
auto operator=(const Swapchain &) const -> Swapchain & = delete;
|
||||
|
||||
[[nodiscard]] auto vk() const -> VkSwapchainKHR
|
||||
{
|
||||
return m_swapchain;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto vk_ptr() -> VkSwapchainKHR *
|
||||
{
|
||||
return &m_swapchain;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_resolution() const -> VkExtent2D
|
||||
{
|
||||
return m_resolution;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_format() const -> VkFormat
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image_count() const -> size_t
|
||||
{
|
||||
return m_images.size();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image_view(uint32_t idx) -> VkImageView
|
||||
{
|
||||
return m_image_views[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image(uint32_t idx) -> VkImage
|
||||
{
|
||||
return m_images[idx];
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const
|
||||
-> std::vector<VkFramebuffer>;
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto get_optimal_image_count(
|
||||
VkSurfaceCapabilitiesKHR capabilities,
|
||||
uint32_t desired_image_count
|
||||
) const -> uint32_t;
|
||||
|
||||
memory::NullOnMove<class Surface *> m_surface {};
|
||||
|
||||
class Gpu *m_gpu {};
|
||||
|
||||
class Device *m_device {};
|
||||
|
||||
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<VkImage> m_images;
|
||||
|
||||
std::vector<VkImageView> m_image_views;
|
||||
|
||||
VkExtent2D m_resolution {};
|
||||
|
||||
VkFormat m_format {};
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <renderer/backend/vk/raii/raii.hpp>
|
||||
#include <renderer/frontend/data/buffer.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Buffer: public IBuffer
|
||||
{
|
||||
public:
|
||||
Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info);
|
||||
|
||||
[[nodiscard]] auto map() -> std::span<std::byte> override;
|
||||
|
||||
void unmap() override;
|
||||
|
||||
// TODO(Light): this is to make copying possible.
|
||||
// But it should be removed in the future,
|
||||
// Right now it's not possible because: buffers can't understand CommandBuffers.
|
||||
// And I'm not sure how to properly abstract over command buffers,
|
||||
// before using other APIs...
|
||||
[[nodiscard]] auto vk()
|
||||
{
|
||||
return *m_buffer;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const -> size_t override
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo;
|
||||
|
||||
[[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags;
|
||||
|
||||
[[nodiscard]] auto to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags;
|
||||
|
||||
|
||||
[[nodiscard]] auto has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const
|
||||
-> bool;
|
||||
|
||||
[[nodiscard]] auto has_required_memory_properties(
|
||||
uint32_t required_properties,
|
||||
uint32_t property_flags
|
||||
) const -> bool;
|
||||
|
||||
Device *m_device {};
|
||||
|
||||
Gpu *m_gpu {};
|
||||
|
||||
raii::Buffer m_buffer;
|
||||
|
||||
raii::Memory m_memory;
|
||||
|
||||
// TODO(Light): should this reflect the allocation size instead?
|
||||
size_t m_size {};
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/context/instance.hpp>
|
||||
#include <renderer/backend/vk/raii/raii.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
#include <renderer/components/messenger.hpp>
|
||||
#include <renderer/frontend/messenger.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Messenger: public IMessenger
|
||||
{
|
||||
public:
|
||||
Messenger(IInstance *instance, CreateInfo info);
|
||||
|
||||
private:
|
||||
static auto native_callback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
|
||||
void *vulkan_user_data
|
||||
) -> VkBool32;
|
||||
|
||||
[[nodiscard]] static auto to_native_severity(MessageSeverity severity)
|
||||
-> VkDebugUtilsMessageSeverityFlagsEXT;
|
||||
|
||||
[[nodiscard]] static auto from_native_severity(VkDebugUtilsMessageSeverityFlagsEXT severity)
|
||||
-> MessageSeverity;
|
||||
|
||||
[[nodiscard]] static auto to_native_type(MessageType type) -> VkDebugUtilsMessageTypeFlagsEXT;
|
||||
|
||||
[[nodiscard]] static auto from_native_type(VkDebugUtilsMessageTypeFlagsEXT type) -> MessageType;
|
||||
|
||||
class Instance *m_instance {};
|
||||
|
||||
raii::DebugMessenger m_debug_messenger;
|
||||
|
||||
MessageSeverity m_severities {};
|
||||
|
||||
MessageType m_types {};
|
||||
|
||||
Callback_T m_user_callback;
|
||||
|
||||
std::any m_user_data;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
inline void vkc(VkResult result)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
throw std::runtime_error {
|
||||
std::format("Vulkan call failed with result: {}", std::to_underlying(result))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_xlib.h>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties;
|
||||
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties;
|
||||
extern PFN_vkCreateDevice vk_create_device;
|
||||
extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address;
|
||||
extern PFN_vkDestroyDevice vk_destroy_device;
|
||||
extern PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features;
|
||||
extern PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties;
|
||||
extern PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties;
|
||||
|
||||
// extension instance functions
|
||||
extern PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label;
|
||||
extern PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label;
|
||||
extern PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label;
|
||||
extern PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger;
|
||||
extern PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger;
|
||||
extern PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label;
|
||||
extern PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label;
|
||||
extern PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label;
|
||||
extern PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name;
|
||||
extern PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag;
|
||||
extern PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message;
|
||||
|
||||
// surface instance functions
|
||||
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support;
|
||||
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities;
|
||||
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats;
|
||||
|
||||
// device functions
|
||||
extern PFN_vkGetDeviceQueue vk_get_device_queue;
|
||||
extern PFN_vkCreateCommandPool vk_create_command_pool;
|
||||
extern PFN_vkDestroyCommandPool vk_destroy_command_pool;
|
||||
extern PFN_vkAllocateCommandBuffers vk_allocate_command_buffers;
|
||||
extern PFN_vkFreeCommandBuffers vk_free_command_buffers;
|
||||
extern PFN_vkBeginCommandBuffer vk_begin_command_buffer;
|
||||
extern PFN_vkEndCommandBuffer vk_end_command_buffer;
|
||||
extern PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier;
|
||||
extern PFN_vkQueueSubmit vk_queue_submit;
|
||||
extern PFN_vkQueueWaitIdle vk_queue_wait_idle;
|
||||
extern PFN_vkDeviceWaitIdle vk_device_wait_idle;
|
||||
extern PFN_vkCreateFence vk_create_fence;
|
||||
extern PFN_vkDestroyFence vk_destroy_fence;
|
||||
extern PFN_vkWaitForFences vk_wait_for_fences;
|
||||
extern PFN_vkResetFences vk_reset_fences;
|
||||
extern PFN_vkCreateSemaphore vk_create_semaphore;
|
||||
extern PFN_vkDestroySemaphore vk_destroy_semaphore;
|
||||
extern PFN_vkCreateSwapchainKHR vk_create_swapchain_khr;
|
||||
extern PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr;
|
||||
extern PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr;
|
||||
extern PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr;
|
||||
extern PFN_vkQueuePresentKHR vk_queue_present_khr;
|
||||
extern PFN_vkCreateImageView vk_create_image_view;
|
||||
extern PFN_vkDestroyImageView vk_destroy_image_view;
|
||||
extern PFN_vkCreateRenderPass vk_create_render_pass;
|
||||
extern PFN_vkDestroyRenderPass vk_destroy_render_pass;
|
||||
extern PFN_vkCreateFramebuffer vk_create_frame_buffer;
|
||||
extern PFN_vkDestroyFramebuffer vk_destroy_frame_buffer;
|
||||
extern PFN_vkCreateShaderModule vk_create_shader_module;
|
||||
extern PFN_vkDestroyShaderModule vk_destroy_shader_module;
|
||||
extern PFN_vkCreatePipelineLayout vk_create_pipeline_layout;
|
||||
extern PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout;
|
||||
extern PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines;
|
||||
extern PFN_vkDestroyPipeline vk_destroy_pipeline;
|
||||
extern PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass;
|
||||
extern PFN_vkCmdEndRenderPass vk_cmd_end_render_pass;
|
||||
extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
|
||||
extern PFN_vkCmdDraw vk_cmd_draw;
|
||||
extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
|
||||
extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
|
||||
extern PFN_vkCmdPushConstants vk_cmd_push_constants;
|
||||
extern PFN_vkCmdCopyBuffer vk_cmd_copy_buffer;
|
||||
|
||||
extern PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout;
|
||||
extern PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout;
|
||||
extern PFN_vkCreateDescriptorPool vk_create_descriptor_pool;
|
||||
extern PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool;
|
||||
extern PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets;
|
||||
extern PFN_vkFreeDescriptorSets vk_free_descriptor_sets;
|
||||
|
||||
extern PFN_vkCreateBuffer vk_create_buffer;
|
||||
extern PFN_vkDestroyBuffer vk_destroy_buffer;
|
||||
extern PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements;
|
||||
extern PFN_vkAllocateMemory vk_allocate_memory;
|
||||
extern PFN_vkBindBufferMemory vk_bind_buffer_memory;
|
||||
extern PFN_vkMapMemory vk_map_memory;
|
||||
extern PFN_vkUnmapMemory vk_unmap_memory;
|
||||
extern PFN_vkFreeMemory vk_free_memory;
|
||||
|
||||
extern PFN_vkResetCommandBuffer vk_reset_command_buffer;
|
||||
|
||||
extern PFN_vkCmdBeginRendering vk_cmd_begin_rendering;
|
||||
extern PFN_vkCmdEndRendering vk_cmd_end_rendering;
|
||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/frontend/context/device.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] /* static */ auto IDevice::create(Api target_api, IGpu *gpu, ISurface *surface)
|
||||
-> memory::Scope<IDevice>
|
||||
{
|
||||
ensure(gpu, "Failed to create renderer::IDevice: null gpu");
|
||||
ensure(surface, "Failed to create renderer::IDevice: null surface");
|
||||
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vk::Device>(gpu, surface);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
#include <renderer/frontend/context/gpu.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] /* static */ auto IGpu::create(Api target_api, IInstance *instance)
|
||||
-> memory::Scope<IGpu>
|
||||
{
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vk::Gpu>(instance);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#include <renderer/backend/vk/context/instance.hpp>
|
||||
#include <renderer/frontend/context/instance.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] /* static */ auto IInstance::get(Api target_api) -> IInstance *
|
||||
{
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return vk::Instance::get();
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
#include <renderer/backend/vk/context/surface.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] /* static */ auto ISurface::create(
|
||||
Api target_api,
|
||||
IInstance *instance,
|
||||
const ecs::Entity &surface_entity
|
||||
) -> memory::Scope<ISurface>
|
||||
{
|
||||
ensure(instance, "Failed to create renderer::ISurface: null instance");
|
||||
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vk::Surface>(instance, surface_entity);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#include <renderer/backend/vk/context/swapchain.hpp>
|
||||
#include <renderer/frontend/context/swapchain.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] /* static */ auto ISwapchain::create(
|
||||
Api target_api,
|
||||
ISurface *surface,
|
||||
IGpu *gpu,
|
||||
IDevice *device
|
||||
) -> memory::Scope<ISwapchain>
|
||||
{
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vk::Swapchain>(surface, gpu, device);
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#include <memory/scope.hpp>
|
||||
#include <renderer/backend/vk/messenger.hpp>
|
||||
#include <renderer/frontend/messenger.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
[[nodiscard]] /* static */ auto IMessenger::create(
|
||||
Api target_api,
|
||||
IInstance *instance,
|
||||
CreateInfo info
|
||||
) -> memory::Scope<IMessenger>
|
||||
{
|
||||
ensure(
|
||||
info.severities != MessageSeverity::none,
|
||||
"Failed to create vk::Messenger: severities == none"
|
||||
);
|
||||
|
||||
ensure(info.types != MessageType::none, "Failed to create vk::Messenger: types == none");
|
||||
|
||||
ensure(info.callback, "Failed to create vk::Messenger: null callback");
|
||||
|
||||
switch (target_api)
|
||||
{
|
||||
case Api::vulkan: return memory::create_scope<vk::Messenger>(instance, std::move(info));
|
||||
case Api::none:
|
||||
case Api::metal:
|
||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||
}
|
||||
}
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace constants {
|
||||
|
||||
};
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
enum class Api : uint8_t
|
||||
{
|
||||
none = 0,
|
||||
|
||||
vulkan,
|
||||
direct_x,
|
||||
metal,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/entity.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/api.hpp>
|
||||
#include <renderer/frontend/messenger.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
/** The main rendering engine.
|
||||
*
|
||||
* Responsible for:
|
||||
* - Creating a rendering backend context (vk/dx/mt)
|
||||
* - Connecting the context to the physical devices (select gpu, create surface, logical device)
|
||||
* - Rendering the scene represented in registry via lt::renderer::components.
|
||||
*
|
||||
* @todo(Light): Add DirectX12 support
|
||||
* @todo(Light): Add Metal support
|
||||
*/
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
/** config.max_frames_in_flight should not be higher than this value. */
|
||||
static constexpr auto frames_in_flight_upper_limit = 5u;
|
||||
|
||||
/** config.max_frames_in_flight should not be lower than this value. */
|
||||
static constexpr auto frames_in_flight_lower_limit = 1u;
|
||||
|
||||
struct Configuration
|
||||
{
|
||||
Api target_api;
|
||||
|
||||
uint32_t max_frames_in_flight;
|
||||
};
|
||||
|
||||
struct CreateInfo
|
||||
{
|
||||
Configuration config;
|
||||
|
||||
memory::Ref<ecs::Registry> registry;
|
||||
|
||||
ecs::Entity surface_entity;
|
||||
|
||||
IMessenger::CreateInfo debug_callback_info;
|
||||
};
|
||||
|
||||
System(CreateInfo info);
|
||||
|
||||
~System() override;
|
||||
|
||||
System(System &&) = default;
|
||||
|
||||
System(const System &) = delete;
|
||||
|
||||
auto operator=(System &&) -> System & = default;
|
||||
|
||||
auto operator=(const System &) -> System & = delete;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_surface_resized_events();
|
||||
|
||||
void submit_scene();
|
||||
|
||||
void recreate_swapchain();
|
||||
|
||||
Api m_api;
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
ecs::Entity m_surface_entity;
|
||||
|
||||
memory::Scope<class IMessenger> m_messenger;
|
||||
|
||||
class IInstance *m_instance;
|
||||
|
||||
memory::Scope<class ISurface> m_surface;
|
||||
|
||||
memory::Scope<class IGpu> m_gpu;
|
||||
|
||||
memory::Scope<class IDevice> m_device;
|
||||
|
||||
memory::Scope<class ISwapchain> m_swapchain;
|
||||
|
||||
memory::Scope<class IRenderer> m_renderer;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
|
||||
uint32_t m_frame_idx {};
|
||||
|
||||
uint32_t m_max_frames_in_flight {};
|
||||
};
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,3 +1,114 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/entity.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/api.hpp>
|
||||
#include <renderer/frontend/messenger.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
/** The main rendering engine.
|
||||
*
|
||||
* Responsible for:
|
||||
* - Creating a rendering backend context (vk/dx/mt)
|
||||
* - Connecting the context to the physical devices (select gpu, create surface, logical device)
|
||||
* - Rendering the scene represented in registry via lt::renderer::components.
|
||||
*
|
||||
* @todo(Light): Add DirectX12 support
|
||||
* @todo(Light): Add Metal support
|
||||
*/
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
/** config.max_frames_in_flight should not be higher than this value. */
|
||||
static constexpr auto frames_in_flight_upper_limit = 5u;
|
||||
|
||||
/** config.max_frames_in_flight should not be lower than this value. */
|
||||
static constexpr auto frames_in_flight_lower_limit = 1u;
|
||||
|
||||
struct Configuration
|
||||
{
|
||||
Api target_api;
|
||||
|
||||
uint32_t max_frames_in_flight;
|
||||
};
|
||||
|
||||
struct CreateInfo
|
||||
{
|
||||
Configuration config;
|
||||
|
||||
memory::Ref<ecs::Registry> registry;
|
||||
|
||||
ecs::Entity surface_entity;
|
||||
|
||||
IMessenger::CreateInfo debug_callback_info;
|
||||
};
|
||||
|
||||
System(CreateInfo info);
|
||||
|
||||
~System() override;
|
||||
|
||||
System(System &&) = default;
|
||||
|
||||
System(const System &) = delete;
|
||||
|
||||
auto operator=(System &&) -> System & = default;
|
||||
|
||||
auto operator=(const System &) -> System & = delete;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_surface_resized_events();
|
||||
|
||||
void submit_scene();
|
||||
|
||||
void recreate_swapchain();
|
||||
|
||||
Api m_api;
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
ecs::Entity m_surface_entity;
|
||||
|
||||
memory::Scope<class IMessenger> m_messenger;
|
||||
|
||||
class IInstance *m_instance;
|
||||
|
||||
memory::Scope<class ISurface> m_surface;
|
||||
|
||||
memory::Scope<class IGpu> m_gpu;
|
||||
|
||||
memory::Scope<class IDevice> m_device;
|
||||
|
||||
memory::Scope<class ISwapchain> m_swapchain;
|
||||
|
||||
memory::Scope<class IRenderer> m_renderer;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
|
||||
uint32_t m_frame_idx {};
|
||||
|
||||
uint32_t m_max_frames_in_flight {};
|
||||
};
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
||||
module :private;
|
||||
using namespace lt::renderer;
|
||||
|
||||
#include <camera/components.hpp>
|
||||
#include <math/algebra.hpp>
|
||||
#include <math/components/transform.hpp>
|
||||
|
|
@ -14,8 +125,6 @@
|
|||
#include <renderer/system.hpp>
|
||||
#include <surface/components.hpp>
|
||||
|
||||
namespace lt::renderer {
|
||||
|
||||
System::System(CreateInfo info)
|
||||
: m_surface_entity(info.surface_entity)
|
||||
, m_api(info.config.target_api)
|
||||
|
|
@ -124,5 +233,3 @@ void System::recreate_swapchain()
|
|||
m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
|
||||
m_renderer->replace_swapchain(m_swapchain.get());
|
||||
}
|
||||
|
||||
} // namespace lt::renderer
|
||||
|
|
@ -1,29 +1,22 @@
|
|||
#pragma once
|
||||
export module renderer.test_utils;
|
||||
|
||||
#include <logger/logger.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <renderer/components/messenger.hpp>
|
||||
#include <renderer/frontend/context/device.hpp>
|
||||
#include <renderer/frontend/context/gpu.hpp>
|
||||
#include <renderer/frontend/context/instance.hpp>
|
||||
#include <renderer/frontend/context/surface.hpp>
|
||||
#include <renderer/frontend/context/swapchain.hpp>
|
||||
#include <renderer/frontend/messenger.hpp>
|
||||
#include <renderer/system.hpp>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/system.hpp>
|
||||
#include <test/test.hpp>
|
||||
export import logger;
|
||||
export import surface.system;
|
||||
export import test.test;
|
||||
export import test.expects;
|
||||
export import memory.reference;
|
||||
export import renderer.frontend;
|
||||
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_false;
|
||||
using ::lt::test::expect_not_nullptr;
|
||||
using ::lt::test::expect_throw;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::Suite;
|
||||
using ::std::ignore;
|
||||
export using ::lt::test::Case;
|
||||
export using ::lt::test::expect_eq;
|
||||
export using ::lt::test::expect_false;
|
||||
export using ::lt::test::expect_not_nullptr;
|
||||
export using ::lt::test::expect_throw;
|
||||
export using ::lt::test::expect_true;
|
||||
export using ::lt::test::Suite;
|
||||
export using ::std::ignore;
|
||||
|
||||
namespace constants {
|
||||
export namespace constants {
|
||||
|
||||
constexpr auto api = lt::renderer::Api::vulkan;
|
||||
constexpr auto resolution = lt::math::uvec2 { 800u, 600u };
|
||||
|
|
@ -32,7 +25,7 @@ constexpr auto frames_in_flight = uint32_t { 3u };
|
|||
} // namespace constants
|
||||
|
||||
|
||||
inline void noop_messenger_callback(
|
||||
void noop_messenger_callback(
|
||||
lt::renderer::IMessenger::MessageSeverity severity,
|
||||
lt::renderer::IMessenger::MessageType type,
|
||||
const lt::renderer::IMessenger::MessageData &data,
|
||||
|
|
@ -41,7 +34,7 @@ inline void noop_messenger_callback(
|
|||
{
|
||||
}
|
||||
|
||||
class Fixture_SurfaceSystem
|
||||
export class Fixture_SurfaceSystem
|
||||
{
|
||||
public:
|
||||
Fixture_SurfaceSystem()
|
||||
|
|
@ -96,7 +89,7 @@ private:
|
|||
lt::surface::System m_system = lt::surface::System(m_registry);
|
||||
};
|
||||
|
||||
class Fixture_SurfaceGpu: public Fixture_SurfaceSystem
|
||||
export class Fixture_SurfaceGpu: public Fixture_SurfaceSystem
|
||||
{
|
||||
public:
|
||||
Fixture_SurfaceGpu() = default;
|
||||
|
|
@ -123,7 +116,7 @@ private:
|
|||
};
|
||||
};
|
||||
|
||||
class FixtureDeviceSwapchain: public Fixture_SurfaceGpu
|
||||
export class FixtureDeviceSwapchain: public Fixture_SurfaceGpu
|
||||
{
|
||||
public:
|
||||
FixtureDeviceSwapchain() = default;
|
||||
|
|
@ -209,7 +202,7 @@ private:
|
|||
};
|
||||
};
|
||||
|
||||
class Fixture_RendererSystem: public Fixture_SurfaceSystem
|
||||
export class Fixture_RendererSystem: public Fixture_SurfaceSystem
|
||||
{
|
||||
public:
|
||||
Fixture_RendererSystem() = default;
|
||||
Loading…
Add table
Reference in a new issue