summaryrefslogtreecommitdiff
path: root/deimos
diff options
context:
space:
mode:
Diffstat (limited to 'deimos')
-rw-r--r--deimos/core/allocator.h15
-rw-r--r--deimos/core/base.h14
-rw-r--r--deimos/render/backend.h6
-rw-r--r--deimos/vulkan/vulkan_backend.cpp109
-rw-r--r--deimos/vulkan/vulkan_device_functions.inc9
-rw-r--r--deimos/vulkan/vulkan_instance_functions.inc3
6 files changed, 153 insertions, 3 deletions
diff --git a/deimos/core/allocator.h b/deimos/core/allocator.h
index 9e8dd87..f6adea2 100644
--- a/deimos/core/allocator.h
+++ b/deimos/core/allocator.h
@@ -143,6 +143,21 @@ public:
std::forward<A5>(arg5));
}
+ template<typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
+ constexpr gsl::owner<T*> New(
+ A0&& arg0, A1&& arg1, A2&& arg2, A3&& arg3, A4&& arg4, A5&& arg5, A6&& arg6,
+ const SourceLocation& source_location = {})
+ {
+ return NewInner<T>(source_location,
+ std::forward<A0>(arg0),
+ std::forward<A1>(arg1),
+ std::forward<A2>(arg2),
+ std::forward<A3>(arg3),
+ std::forward<A4>(arg4),
+ std::forward<A5>(arg5),
+ std::forward<A6>(arg6));
+ }
+
template<typename T>
void Delete(gsl::owner<T*> t, const SourceLocation& source_location = {})
{
diff --git a/deimos/core/base.h b/deimos/core/base.h
index 0c15ccd..4c74b33 100644
--- a/deimos/core/base.h
+++ b/deimos/core/base.h
@@ -64,8 +64,9 @@ struct SourceLocation
{}
};
-template<typename T> T Min(T a, T b) { return (a < b) ? a : b; }
-template<typename T> T Max(T a, T b) { return (a > b) ? a : b; }
+template<typename T> constexpr T Min(T a, T b) { return (a < b) ? a : b; }
+template<typename T> constexpr T Max(T a, T b) { return (a > b) ? a : b; }
+template<typename T> constexpr T Clamp(T x, T min, T max) { return Min(Max(x, min), max); }
[[maybe_unused]] static constexpr int64_t Kilobytes = 1024;
[[maybe_unused]] static constexpr int64_t Megabytes = 1024 * 1024;
@@ -151,6 +152,15 @@ public:
Expects(offset + size <= m_size);
return Span(m_begin + offset, size);
}
+
+ bool Contains(const T& v) const
+ {
+ for (const T& p: *this)
+ {
+ if (p == v) { return true; }
+ }
+ return false;
+ }
};
template<typename T>
diff --git a/deimos/render/backend.h b/deimos/render/backend.h
index cba8d90..bb94cb9 100644
--- a/deimos/render/backend.h
+++ b/deimos/render/backend.h
@@ -1,10 +1,13 @@
#pragma once
#include <deimos/core/base.h>
+#include <deimos/core/status.h>
namespace deimos
{
+struct RenderSwapchain{};
+
class IRenderBackend
{
public:
@@ -14,6 +17,9 @@ public:
virtual void BeginFrame() = 0;
virtual void EndFrame() = 0;
+
+ virtual StatusOr<gsl::owner<RenderSwapchain*>> CreateSwapchain() = 0;
+ virtual void DestroySwapchain(gsl::owner<RenderSwapchain*>) = 0;
};
} // namespace deimos
diff --git a/deimos/vulkan/vulkan_backend.cpp b/deimos/vulkan/vulkan_backend.cpp
index 87e4451..cc54d4d 100644
--- a/deimos/vulkan/vulkan_backend.cpp
+++ b/deimos/vulkan/vulkan_backend.cpp
@@ -22,8 +22,14 @@ VulkanLoaderApi* vulkan_loader_api;
const VkAllocationCallbacks* kVkAlloc = nullptr;
+struct VulkanSwapchain: public RenderSwapchain
+{
+ VkSwapchainKHR swapchain{};
+};
+
class VulkanBackendImpl : public IVulkanBackend, public IRenderBackend
{
+ Allocator* m_allocator;
VulkanApi* m_vk;
VkInstance m_instance;
VkPhysicalDevice m_physical_device;
@@ -41,12 +47,14 @@ class VulkanBackendImpl : public IVulkanBackend, public IRenderBackend
public:
VulkanBackendImpl(
+ Allocator* allocator,
VulkanApi* vk,
VkInstance instance,
VkPhysicalDevice physical_device,
uint32_t queue_family,
VkSurfaceKHR surface,
VkDevice device) :
+ m_allocator{allocator},
m_vk{vk}, m_instance{instance}, m_physical_device{physical_device},
m_queue_family{queue_family}, m_surface{surface}, m_device{device}
{
@@ -80,6 +88,106 @@ public:
m_vk->DeviceWaitIdle(m_device);
m_vk->DestroyCommandPool(m_device, m_frame_resources.cmd_pool, kVkAlloc);
}
+
+ StatusOr<gsl::owner<RenderSwapchain*>> CreateSwapchain() override
+ {
+ auto temp_alloc = temp_api->Acquire();
+
+ VkSurfaceCapabilitiesKHR caps;
+ VkResult res = m_vk->GetPhysicalDeviceSurfaceCapabilitiesKHR(m_physical_device, m_surface, &caps);
+ if (res != VK_SUCCESS)
+ {
+ return RuntimeError("Couldn't retrieve Vulkan surface capabitilies");
+ }
+
+ uint32_t format_count = 0;
+ uint32_t present_mode_count = 0;
+
+ m_vk->GetPhysicalDeviceSurfaceFormatsKHR(m_physical_device, m_surface, &format_count, nullptr);
+ m_vk->GetPhysicalDeviceSurfacePresentModesKHR(m_physical_device, m_surface, &present_mode_count, nullptr);
+
+ auto formats = temp_alloc.allocator().NewArray<VkSurfaceFormatKHR>(format_count);
+ auto present_modes = temp_alloc.allocator().NewArray<VkPresentModeKHR>(present_mode_count);
+
+ m_vk->GetPhysicalDeviceSurfaceFormatsKHR(m_physical_device, m_surface, &format_count, formats.data());
+ m_vk->GetPhysicalDeviceSurfacePresentModesKHR(m_physical_device, m_surface, &present_mode_count, present_modes.data());
+
+ VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
+ if (present_modes.Contains(VK_PRESENT_MODE_MAILBOX_KHR))
+ {
+ present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
+ }
+
+ static constexpr VkFormat kAcceptableFormats[] = {
+ VK_FORMAT_R8G8B8_SRGB,
+ VK_FORMAT_B8G8R8_SRGB,
+ VK_FORMAT_R8G8B8A8_SRGB,
+ VK_FORMAT_B8G8R8A8_SRGB,
+ };
+
+ bool has_format = false;
+ VkSurfaceFormatKHR format;
+ for (const auto& candidate: kAcceptableFormats)
+ {
+ for (const auto& f: formats)
+ {
+ if (f.format == candidate && f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
+ {
+ has_format = true;
+ format = f;
+ break;
+ }
+ }
+
+ if (has_format) { break; }
+ }
+
+
+ if (!has_format)
+ {
+ return RuntimeError("No acceptable Vulkan swapchain format found");
+ }
+
+ VkSwapchainCreateInfoKHR create_info = {
+ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ .pNext = nullptr,
+ .flags = 0,
+ .surface = m_surface,
+ .minImageCount = Clamp<uint32_t>(2, caps.minImageCount, caps.maxImageCount),
+ .imageFormat = format.format,
+ .imageColorSpace = format.colorSpace,
+ .imageExtent = caps.currentExtent,
+ .imageArrayLayers = 1,
+ .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+ .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .queueFamilyIndexCount = 0,
+ .pQueueFamilyIndices = nullptr,
+ .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+ .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ .presentMode = present_mode,
+ .clipped = VK_TRUE,
+ .oldSwapchain = VK_NULL_HANDLE,
+ };
+
+ VkSwapchainKHR vk_swapchain{};
+ res = m_vk->CreateSwapchainKHR(m_device, &create_info, kVkAlloc, &vk_swapchain);
+ if (res != VK_SUCCESS)
+ {
+ return RuntimeError("Error when creating Vulkan swapchain");
+ }
+
+ auto* swapchain = m_allocator->New<VulkanSwapchain>();
+ swapchain->swapchain = vk_swapchain;
+
+ return swapchain;
+ }
+
+ void DestroySwapchain(gsl::owner<RenderSwapchain*> swapchain) override
+ {
+ auto* vk_swapchain = (VulkanSwapchain*)swapchain;
+ m_vk->DestroySwapchainKHR(m_device, vk_swapchain->swapchain, kVkAlloc);
+ m_allocator->Delete(swapchain);
+ }
};
StatusOr<VkInstance> CreateInstance(VulkanApi* vk)
@@ -315,6 +423,7 @@ StatusOr<gsl::owner<IVulkanBackend*>> InitializeVulkan(Allocator* allocator, OsW
vulkan_loader_api->LoadDevice(vk, device);
return allocator->New<VulkanBackendImpl>(
+ allocator,
vk, instance, physical_device,
queue_family, surface, device);
}
diff --git a/deimos/vulkan/vulkan_device_functions.inc b/deimos/vulkan/vulkan_device_functions.inc
index f83ebb7..f6e6a30 100644
--- a/deimos/vulkan/vulkan_device_functions.inc
+++ b/deimos/vulkan/vulkan_device_functions.inc
@@ -1,8 +1,15 @@
// NOLINTBEGIN
FN(DestroyDevice)
+FN(DeviceWaitIdle)
+
FN(GetDeviceQueue)
FN(CreateCommandPool)
FN(ResetCommandPool)
FN(DestroyCommandPool)
-FN(DeviceWaitIdle)
+
+FN(CreateSwapchainKHR)
+FN(DestroySwapchainKHR)
+FN(GetSwapchainImagesKHR)
+FN(AcquireNextImageKHR)
+FN(QueuePresentKHR)
// NOLINTEND
diff --git a/deimos/vulkan/vulkan_instance_functions.inc b/deimos/vulkan/vulkan_instance_functions.inc
index 0a46455..89ace12 100644
--- a/deimos/vulkan/vulkan_instance_functions.inc
+++ b/deimos/vulkan/vulkan_instance_functions.inc
@@ -10,4 +10,7 @@ FN(GetDeviceProcAddr)
FN(CreateWin32SurfaceKHR)
FN(DestroySurfaceKHR)
FN(GetPhysicalDeviceSurfaceSupportKHR)
+FN(GetPhysicalDeviceSurfaceCapabilitiesKHR)
+FN(GetPhysicalDeviceSurfaceFormatsKHR)
+FN(GetPhysicalDeviceSurfacePresentModesKHR)
// NOLINTEND