This commit is contained in:
Joshua Ashton 2022-08-04 02:00:54 +00:00
parent 72f6214fdf
commit dc3b3dbe80
18 changed files with 460 additions and 388 deletions

View File

@ -14,7 +14,7 @@ namespace orange::fs
};
template <typename T>
using FileResult = Result<T, FileSystemErrorCode>;
using FileResult = Result<T, FileSystemErrorCode, FileSystemErrorCode::Success, FileSystemErrorCode::Invalid>;
FileResult<Buffer> OpenFileIntoBuffer(const char *path);
}

View File

@ -12,11 +12,12 @@ namespace orange
{
Invalid = -1,
Failed = -2,
NotFound = -3,
Success = 0,
};
template <typename T, typename ErrorCode = BasicErrorCode>
template <typename T, typename ErrorCode = BasicErrorCode, ErrorCode SuccessCode = BasicErrorCode::Success, ErrorCode InvalidCode = BasicErrorCode::Invalid, ErrorCode DefaultFail = BasicErrorCode::Failed>
class Result
{
public:
@ -49,6 +50,31 @@ namespace orange
T& operator *() { return *Get(); }
const T& operator *() const { return *Get(); }
static Result Error(ErrorCode code = DefaultFail)
{
Result res;
res.MakeError(code);
return res;
}
template <typename... Args>
static Result Success(Args&&... args)
{
Result res;
res.Create(Forward<Args>(args)...);
res.MakeSuccess();
return res;
}
ErrorCode Code() const { return m_error; }
template <typename OtherResult>
static Result ForwardError(OtherResult& x)
{
return Error(x.Code());
}
protected:
Result() = default;
@ -70,31 +96,15 @@ namespace orange
}
}
Result& MakeError(ErrorCode code) { m_error = code; return *this; }
Result& MakeSuccess() { m_error = ErrorCode::Success; return *this; }
static Result Error(ErrorCode code)
{
Result<T> res;
res.MakeError(code);
return res;
}
template <typename... Args>
static Result Success(Args&&... args)
{
Result<T> res;
res.Create(Forward<Args>(args)...);
res.MakeSuccess();
return res;
}
Result& MakeError(ErrorCode code) { m_error = code; return *this; }
Result& MakeSuccess() { m_error = SuccessCode; return *this; }
T& RefUnsafe() { return *reinterpret_cast< T*>(&m_data); }
const T& RefUnsafe() const { return *reinterpret_cast<const T*>(&m_data); }
friend T;
AlignedStorage<sizeof(T), alignof(T)> m_data;
ErrorCode m_error = ErrorCode::Invalid;
ErrorCode m_error = InvalidCode;
bool m_created = false;
};
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <Orange/Core/Traits.h>
#include <Orange/Core/AlignedStorage.h>
#include <Orange/Core/Span.h>

View File

@ -35,4 +35,29 @@ namespace orange
{
return static_cast<RemoveReference<T>&&>(arg);
}
template <typename T, size_t N>
[[nodiscard]] constexpr size_t Size(const T (&array)[N]) noexcept
{
(void)array;
return N;
}
template <typename T>
[[nodiscard]] constexpr T Min( const T& valMin, const T& valMax )
{
return valMin < valMax ? valMin : valMax;
}
template <typename T>
[[nodiscard]] constexpr T Max( const T& valMin, const T& valMax )
{
return valMin > valMax ? valMin : valMax;
}
template <typename T>
[[nodiscard]] constexpr T Clamp( const T& val, const T& minVal, const T& maxVal )
{
return Min( Max( val, minVal ), maxVal );
}
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <Orange/Core/Types.h>
#include <Orange/Core/Span.h>
#include <Orange/Core/Result.h>
#include <vulkan/vulkan_core.h>
namespace orange
{
template <typename T>
using VulkanResult = Result<T, VkResult, VK_SUCCESS, VK_ERROR_UNKNOWN, VK_ERROR_UNKNOWN>;
class RenderContext
{
public:
~RenderContext();
static Result<RenderContext> Create(const char *appName);
VkInstance Instance() const { return m_instance; }
VkPhysicalDevice PhysicalDevice() const { return m_physicalDevice; }
VkDevice Device() const { return m_device; }
VkQueue Queue() const { return m_queue; }
protected:
friend class Result<RenderContext>;
RenderContext(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device, VkQueue queue)
: m_instance{ instance }, m_physicalDevice{ physicalDevice }, m_device{ device }, m_queue{ queue } {}
private:
VkInstance m_instance = VK_NULL_HANDLE;
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
VkDevice m_device = VK_NULL_HANDLE;
VkQueue m_queue = VK_NULL_HANDLE;
};
}

View File

@ -1,96 +0,0 @@
#pragma once
#include <Orange/Core/Types.h>
#include <Orange/Core/Span.h>
#include <Orange/Core/Result.h>
#include <Orange/Core/SmallVector.h>
#include <vulkan/vulkan_core.h>
namespace orange
{
class Window;
class PhysicalDevice
{
public:
PhysicalDevice() = default;
PhysicalDevice(const PhysicalDevice&) = default;
PhysicalDevice& operator = (const PhysicalDevice&) = default;
~PhysicalDevice() = default;
static Result<PhysicalDevice> Create(VkPhysicalDevice physicalDevice);
VkPhysicalDevice operator *() { return m_physicalDevice; }
operator bool () const { return m_physicalDevice != VK_NULL_HANDLE && m_graphicsQueueFamilyIndex != ~0u; }
uint32_t GraphicsQueueFamilyIndex() const { return m_graphicsQueueFamilyIndex; }
int Score();
protected:
friend Result<PhysicalDevice>;
PhysicalDevice(VkPhysicalDevice physicalDevice, uint32_t graphicsQueueFamilyIndex);
private:
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
uint32_t m_graphicsQueueFamilyIndex = ~0u;
};
class Instance
{
public:
~Instance();
static Result<Instance> Create(Window& window, const char* name);
VkInstance operator *() { return m_instance; }
Span<PhysicalDevice> PhysicalDevices() { return m_physicalDevices; }
protected:
friend Result<Instance>;
Instance(VkInstance instance, Span<PhysicalDevice> physicalDevice);
private:
VkInstance m_instance = VK_NULL_HANDLE;
SmallVector<PhysicalDevice, 32> m_physicalDevices;
};
class GPUBuffer
{
public:
~GPUBuffer();
static Result<GPUBuffer> Create();
protected:
friend Result<GPUBuffer>;
GPUBuffer(VkDeviceMemory memory, VkBuffer buffer, void* ptr);
private:
VkDeviceMemory m_memory;
VkBuffer m_buffer;
};
class Device
{
public:
~Device();
static Result<Device> Create(Instance& instance, PhysicalDevice physicalDevice);
protected:
friend Result<Device>;
Device(Instance& instance, PhysicalDevice physicalDevice, VkDevice device);
private:
Instance& m_instance;
PhysicalDevice m_physicalDevice;
VkDevice m_device = VK_NULL_HANDLE;
VkQueue m_queue = VK_NULL_HANDLE;
};
class Swapchain
{
public:
~Swapchain();
static Result<Swapchain> Create();
};
PhysicalDevice PickBestPhysicalDevice(Span<PhysicalDevice> physDevs);
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <Orange/Core/Span.h>
#include <Orange/Core/Result.h>
#include <Orange/Core/SmallVector.h>
#include <Orange/Render/RenderContext.h>
namespace orange
{
class Swapchain
{
public:
~Swapchain();
static Result<Swapchain> Create(RenderContext& context, VkSurfaceKHR surface);
protected:
friend class Result<Swapchain>;
Swapchain(VkDevice device, VkSurfaceKHR surface, VkExtent2D extent, VkSwapchainKHR swapchain);
private:
VkDevice m_device;
VkSurfaceKHR m_surface;
VkExtent2D m_extent;
VkSwapchainKHR m_swapchain;
SmallVector<VkImage, 8> m_images;
};
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <Orange/Core/Traits.h>
namespace orange
{
template <typename Func, typename OutArray, typename... Args>
uint32_t VkEnumerate(Func function, OutArray& outArray, Args&&... arguments)
{
uint32_t count = 0;
function(arguments..., &count, nullptr);
outArray.Resize(count);
if (!count)
return 0;
function(Forward<Args>(arguments)..., &count, outArray.Data());
return count;
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <Orange/Core/Result.h>
#include <vulkan/vulkan_core.h>
struct SDL_Window;
@ -11,7 +12,9 @@ namespace orange
public:
~Window();
bool GetInstanceExtensions(uint32_t *count, const char **extensions);
static bool GetInstanceExtensions(Window& window, uint32_t *count, const char **extensions);
Result<VkSurfaceKHR> CreateSurface(VkInstance instance);
static const char* GetError();

View File

@ -1,7 +1,8 @@
#include <Orange/Core/Result.h>
#include <Orange/Render/Window.h>
#include <Orange/Render/Renderer.h>
#include <Orange/Render/RenderContext.h>
#include <Orange/Render/Swapchain.h>
using namespace orange;
@ -13,14 +14,16 @@ int main(int argc, char** argv)
if (!r_window)
return 1;
Result<Instance> r_instance = Instance::Create(*r_window, "Orange");
if (!r_instance)
Result<RenderContext> r_renderContext = RenderContext::Create("Cube Test");
if (!r_renderContext)
return 1;
PhysicalDevice physicalDevice = PickBestPhysicalDevice(r_instance->PhysicalDevices());
Result<VkSurfaceKHR> r_surface = r_window->CreateSurface(r_renderContext->Instance());
if (!r_surface)
return 1;
Result<Device> r_device = Device::Create(*r_instance, physicalDevice);
if (!r_device)
Result<Swapchain> r_swapchain = Swapchain::Create(*r_renderContext, *r_surface);
if (!r_swapchain)
return 1;
return 0;

View File

@ -1,63 +0,0 @@
#include "Orange/Core/Log.h"
#include "Orange/Core/Result.h"
#include <Orange/Render/Renderer.h>
namespace orange
{
static VkDevice CreateDevice(PhysicalDevice physDev)
{
constexpr float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueInfo =
{
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = physDev.GraphicsQueueFamilyIndex(),
.queueCount = 1,
.pQueuePriorities = &queuePriority,
};
VkPhysicalDeviceFeatures features{};
VkDeviceCreateInfo deviceInfo =
{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &queueInfo,
.pEnabledFeatures = &features,
};
VkDevice device = VK_NULL_HANDLE;
if (vkCreateDevice(*physDev, &deviceInfo, nullptr, &device) != VK_SUCCESS)
{
log::err("Failed to create Vulkan logical device");
return VK_NULL_HANDLE;
}
return device;
}
Result<Device> Device::Create(Instance& instance, PhysicalDevice physicalDevice)
{
VkDevice device = VK_NULL_HANDLE;
if (!(device = CreateDevice(physicalDevice)))
{
log::err("Failed to create Vulkan device");
return Result<Device>::Error(BasicErrorCode::Failed);
}
return Result<Device>::Success(instance, physicalDevice, device);
}
Device::Device(Instance& instance, PhysicalDevice physicalDevice, VkDevice device)
: m_instance { instance }
, m_physicalDevice{ physicalDevice }
, m_device { device }
{
vkGetDeviceQueue(m_device, m_physicalDevice.GraphicsQueueFamilyIndex(), 0, &m_queue);
}
Device::~Device()
{
vkDestroyDevice(m_device, nullptr);
}
}

View File

@ -1,109 +0,0 @@
#include <Orange/Core/Log.h>
#include <Orange/Render/Renderer.h>
#include <Orange/Render/Window.h>
namespace orange
{
static VkInstance CreateVkInstance(Window& window, const char* name)
{
uint32_t instanceExtensionCount = {};
if (!window.GetInstanceExtensions(&instanceExtensionCount, nullptr))
{
log::err("Failed to get Window instance extension count: %s", Window::GetError());
return VK_NULL_HANDLE;
}
SmallVector<const char *, 32> instanceExtensions{ instanceExtensionCount };
if (!window.GetInstanceExtensions(&instanceExtensionCount, instanceExtensions.Data()))
{
log::err("Failed to get Window instance extensions: %s", Window::GetError());
return VK_NULL_HANDLE;
}
VkApplicationInfo appInfo =
{
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pApplicationName = name,
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "Orange",
.engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = VK_API_VERSION_1_3,
};
VkInstanceCreateInfo instanceInfo =
{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &appInfo,
.enabledExtensionCount = instanceExtensionCount,
.ppEnabledExtensionNames = instanceExtensions.Data(),
};
VkResult result = VK_SUCCESS;
VkInstance instance;
if ((result = vkCreateInstance(&instanceInfo, nullptr, &instance)) != VK_SUCCESS)
{
log::err("Failed to create Vulkan instance.");
return VK_NULL_HANDLE;
}
return instance;
}
Result<Instance> Instance::Create(Window& window, const char* name)
{
VkInstance instance = VK_NULL_HANDLE;
if (!(instance = CreateVkInstance(window, name)))
{
log::err("Failed to create Vulkan instance");
return Result<Instance>::Error(BasicErrorCode::Failed);
}
SmallVector<PhysicalDevice, 32> physicalDevices;
{
uint32_t vulkanPhysicalDeviceCount = {};
if (vkEnumeratePhysicalDevices(instance, &vulkanPhysicalDeviceCount, nullptr) != VK_SUCCESS)
{
log::err("Failed to get physical device count");
return Result<Instance>::Error(BasicErrorCode::Failed);
}
if (!vulkanPhysicalDeviceCount)
{
log::err("No physical devices found");
return Result<Instance>::Error(BasicErrorCode::Failed);
}
{
SmallVector<VkPhysicalDevice, 32> vulkanPhysicalDevices{ vulkanPhysicalDeviceCount };
if (vkEnumeratePhysicalDevices(instance, &vulkanPhysicalDeviceCount, vulkanPhysicalDevices.Data()) != VK_SUCCESS)
{
log::err("Failed to enumerate physical devices");
return Result<Instance>::Error(BasicErrorCode::Failed);
}
for (auto& physDev : vulkanPhysicalDevices)
{
Result<PhysicalDevice> r_physDev = PhysicalDevice::Create(physDev);
if (!r_physDev)
continue;
physicalDevices.PushBack(*r_physDev);
}
}
}
return Result<Instance>::Success(instance, physicalDevices);
}
Instance::Instance(VkInstance instance, Span<PhysicalDevice> physicalDevices)
: m_instance { instance }
, m_physicalDevices{ physicalDevices }
{
}
Instance::~Instance()
{
vkDestroyInstance(m_instance, nullptr);
}
}

View File

@ -1,65 +0,0 @@
#include "Orange/Core/Log.h"
#include "Orange/Core/Result.h"
#include <Orange/Render/Renderer.h>
namespace orange
{
static uint32_t PickQueueFamilyIndex(VkPhysicalDevice physDev)
{
uint32_t queueFamilyPropertyCount = {};
vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueFamilyPropertyCount, nullptr);
SmallVector<VkQueueFamilyProperties, 32> queueFamilyProperties{ queueFamilyPropertyCount };
vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueFamilyPropertyCount, queueFamilyProperties.Data());
uint32_t index = ~0u;
for (uint32_t i = 0; i < queueFamilyPropertyCount; i++)
{
const auto& family = queueFamilyProperties[i];
if (family.queueFlags & VK_QUEUE_GRAPHICS_BIT)
{
index = i;
break;
}
}
return index;
}
Result<PhysicalDevice> PhysicalDevice::Create(VkPhysicalDevice physicalDevice)
{
uint32_t graphicsQueueFamilyIndex = ~0u;
if ((graphicsQueueFamilyIndex = PickQueueFamilyIndex(physicalDevice)) == ~0u)
{
log::info("Ignoring physical device as it has no graphics queue family");
return Result<PhysicalDevice>::Error(BasicErrorCode::Failed);
}
// TODO: Check if it can present to surface.
return Result<PhysicalDevice>::Success(physicalDevice, graphicsQueueFamilyIndex);
}
int PhysicalDevice::Score()
{
VkPhysicalDeviceProperties2 props = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
vkGetPhysicalDeviceProperties2(m_physicalDevice, &props);
int score = 0;
if (props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ||
props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
score += 10;
if (props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
score += 5;
return score;
}
PhysicalDevice::PhysicalDevice(VkPhysicalDevice physicalDevice, uint32_t graphicsQueueFamilyIndex)
: m_physicalDevice { physicalDevice }
, m_graphicsQueueFamilyIndex{ graphicsQueueFamilyIndex }
{
}
}

View File

@ -0,0 +1,178 @@
#include <Orange/Core/Log.h>
#include <Orange/Core/SmallVector.h>
#include <Orange/Render/VulkanHelpers.h>
#include <Orange/Render/RenderContext.h>
#include <Orange/Render/Window.h>
namespace orange
{
static VulkanResult<VkInstance> CreateVkInstance(const char* appName)
{
SmallVector<const char *, 32> instanceExtensions;
{
auto r_tempWindow = Window::Create();
if (!r_tempWindow)
{
log::err("Failed to create temporary window for grabbing instance extensions: %s", Window::GetError());
return VulkanResult<VkInstance>::Error(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
}
if (!VkEnumerate(Window::GetInstanceExtensions, instanceExtensions, *r_tempWindow))
return VulkanResult<VkInstance>::Error(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
}
VkApplicationInfo appInfo =
{
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pApplicationName = appName,
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "Orange",
.engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = VK_API_VERSION_1_3,
};
VkInstanceCreateInfo instanceInfo =
{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &appInfo,
.enabledExtensionCount = instanceExtensions.Size(),
.ppEnabledExtensionNames = instanceExtensions.Data(),
};
VkResult result = VK_SUCCESS;
VkInstance instance = VK_NULL_HANDLE;
if ((result = vkCreateInstance(&instanceInfo, nullptr, &instance)) != VK_SUCCESS)
{
log::err("Failed to create Vulkan instance.");
return VulkanResult<VkInstance>::Error(result);
}
return VulkanResult<VkInstance>::Success(instance);
}
static Result<uint32_t> PickQueueFamilyIndex(VkPhysicalDevice physicalDevice)
{
SmallVector<VkQueueFamilyProperties, 32> queueFamilyProperties;
VkEnumerate(vkGetPhysicalDeviceQueueFamilyProperties, queueFamilyProperties, physicalDevice);
for (uint32_t i = 0; i < queueFamilyProperties.Size(); i++)
{
const auto& family = queueFamilyProperties[i];
if (family.queueFlags & VK_QUEUE_GRAPHICS_BIT)
return Result<uint32_t>::Success(i);
}
return Result<uint32_t>::Error(BasicErrorCode::NotFound);
}
static int ScorePhysicalDevice(VkPhysicalDevice physicalDevice)
{
VkPhysicalDeviceProperties2 props = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
vkGetPhysicalDeviceProperties2(physicalDevice, &props);
int score = 0;
if (props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ||
props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
score += 10;
if (props.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
score += 5;
return score;
}
static Result<VkPhysicalDevice> PickPhysicalDevice(VkInstance instance)
{
SmallVector<VkPhysicalDevice, 32> physicalDevices;
VkEnumerate(vkEnumeratePhysicalDevices, physicalDevices, instance);
VkPhysicalDevice bestPhysicalDevice = VK_NULL_HANDLE;
int bestScore = -1;
for (auto physicalDevice : physicalDevices)
{
int score = ScorePhysicalDevice(physicalDevice);
if (score > bestScore && PickQueueFamilyIndex(physicalDevice))
{
bestPhysicalDevice = physicalDevice;
bestScore = score;
}
}
if (!bestPhysicalDevice)
{
log::err("Failed to find a suitable physical device");
return Result<VkPhysicalDevice>::Error(BasicErrorCode::Failed);
}
return Result<VkPhysicalDevice>::Success(bestPhysicalDevice);
}
static VulkanResult<VkDevice> CreateVkDevice(VkPhysicalDevice physicalDevice, uint32_t graphicsQueueFamilyIndex)
{
constexpr float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueInfo =
{
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = graphicsQueueFamilyIndex,
.queueCount = 1,
.pQueuePriorities = &queuePriority,
};
const char* deviceExtensions[] =
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
VkPhysicalDeviceFeatures features{};
VkDeviceCreateInfo deviceInfo =
{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &queueInfo,
.enabledExtensionCount = Size(deviceExtensions),
.ppEnabledExtensionNames = deviceExtensions,
.pEnabledFeatures = &features,
};
VkDevice device = VK_NULL_HANDLE;
VkResult result;
if ((result = vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device)) != VK_SUCCESS)
{
log::err("Failed to create Vulkan logical device");
return VulkanResult<VkDevice>::Error(result);
}
return VulkanResult<VkDevice>::Success(device);
}
Result<RenderContext> RenderContext::Create(const char *appName)
{
auto r_instance = CreateVkInstance(appName);
if (!r_instance)
return Result<RenderContext>::Error(BasicErrorCode::Failed);
auto r_physicalDevice = PickPhysicalDevice(*r_instance);
if (!r_physicalDevice)
return Result<RenderContext>::Error(BasicErrorCode::Failed);
uint32_t graphicsQueueFamilyIndex = *PickQueueFamilyIndex(*r_physicalDevice);
auto r_device = CreateVkDevice(*r_physicalDevice, graphicsQueueFamilyIndex);
if (!r_device)
return Result<RenderContext>::Error(BasicErrorCode::Failed);
VkQueue queue = VK_NULL_HANDLE;
vkGetDeviceQueue(*r_device, graphicsQueueFamilyIndex, 0, &queue);
return Result<RenderContext>::Success(*r_instance, *r_physicalDevice, *r_device, queue);
}
RenderContext::~RenderContext()
{
vkDestroyDevice(m_device, nullptr);
vkDestroyInstance(m_instance, nullptr);
}
}

View File

@ -0,0 +1,115 @@
#include <Orange/Core/Log.h>
#include <Orange/Render/Swapchain.h>
#include <Orange/Render/VulkanHelpers.h>
#include <Orange/Render/Window.h>
namespace orange
{
static Result<VkSurfaceFormatKHR> ChooseSwapChainFormat(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
{
SmallVector<VkSurfaceFormatKHR, 32> surfaceFormats;
if (!VkEnumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, surfaceFormats, physicalDevice, surface))
{
log::err("Surface supports no formats");
return Result<VkSurfaceFormatKHR>::Error(BasicErrorCode::NotFound);
}
for (auto& surfaceFormat : surfaceFormats)
{
if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM && surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
return Result<VkSurfaceFormatKHR>::Success(surfaceFormat);
}
return Result<VkSurfaceFormatKHR>::Error(BasicErrorCode::NotFound);
}
static VkPresentModeKHR ChoosePresentMode(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
{
SmallVector<VkPresentModeKHR, 32> presentModes;
VkEnumerate(vkGetPhysicalDeviceSurfacePresentModesKHR, presentModes, physicalDevice, surface);
for (auto& presentMode : presentModes) { if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR) return presentMode; }
for (auto& presentMode : presentModes) { if (presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) return presentMode; }
return VK_PRESENT_MODE_FIFO_KHR;
}
static VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{
if (capabilities.currentExtent.width != ~0u)
return capabilities.currentExtent;
uint32_t width = 1280;
uint32_t height = 720;
return VkExtent2D
{
Clamp(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width),
Clamp(height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height)
};
}
static uint32_t ChooseImageCount(const VkSurfaceCapabilitiesKHR& capabilities)
{
uint32_t imageCount = 3;
if (capabilities.minImageCount != 0)
imageCount = Max(imageCount, capabilities.minImageCount);
if (capabilities.maxImageCount != 0)
imageCount = Min(imageCount, capabilities.maxImageCount);
return imageCount;
}
Result<Swapchain> Swapchain::Create(RenderContext& context, VkSurfaceKHR surface)
{
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.PhysicalDevice(), surface, &capabilities);
Result<VkSurfaceFormatKHR> r_format = ChooseSwapChainFormat(context.PhysicalDevice(), surface);
if (!r_format)
return Result<Swapchain>::ForwardError(r_format);
const VkExtent2D extent = ChooseSwapExtent(capabilities);
VkSwapchainCreateInfoKHR swapchainInfo =
{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.surface = surface,
.minImageCount = ChooseImageCount(capabilities),
.imageFormat = r_format->format,
.imageColorSpace = r_format->colorSpace,
.imageExtent = extent,
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.preTransform = capabilities.currentTransform,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = ChoosePresentMode(context.PhysicalDevice(), surface),
.clipped = VK_TRUE,
.oldSwapchain = VK_NULL_HANDLE, // TODO
};
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
if (vkCreateSwapchainKHR(context.Device(), &swapchainInfo, nullptr, &swapchain) != VK_SUCCESS)
{
log::err("Failed to create swapchain");
return Result<Swapchain>::Error();
}
return Result<Swapchain>::Success(context.Device(), surface, extent, swapchain);
}
Swapchain::Swapchain(VkDevice device, VkSurfaceKHR surface, VkExtent2D extent, VkSwapchainKHR swapchain)
: m_device{ device }, m_surface{ surface }, m_extent{ extent }, m_swapchain{ swapchain }
{
VkEnumerate(vkGetSwapchainImagesKHR, m_images, m_device, m_swapchain);
}
Swapchain::~Swapchain()
{
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
}
}

View File

@ -1,21 +0,0 @@
#include <Orange/Core/Log.h>
#include <Orange/Render/Renderer.h>
namespace orange
{
PhysicalDevice PickBestPhysicalDevice(Span<PhysicalDevice> physDevs)
{
PhysicalDevice bestPhysDev;
int bestScore = -1;
for (auto physDev : physDevs)
{
if (int score = physDev.Score() > bestScore)
{
bestPhysDev = physDev;
bestScore = score;
}
}
return bestPhysDev;
}
}

View File

@ -1,6 +1,7 @@
#include "Orange/Core/Result.h"
#include "Orange/Core/Log.h"
#include <Orange/Render/Window.h>
#include <Orange/Render/RenderContext.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_error.h>
@ -37,9 +38,18 @@ namespace orange
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
bool Window::GetInstanceExtensions(uint32_t *count, const char **extensions)
bool Window::GetInstanceExtensions(Window& window, uint32_t *count, const char **extensions)
{
return SDL_Vulkan_GetInstanceExtensions(m_window, count, extensions) == SDL_TRUE;
return SDL_Vulkan_GetInstanceExtensions(window.m_window, count, extensions) == SDL_TRUE;
}
Result<VkSurfaceKHR> Window::CreateSurface(VkInstance instance)
{
VkSurfaceKHR surface = VK_NULL_HANDLE;
if (SDL_Vulkan_CreateSurface(m_window, instance, &surface) != SDL_TRUE)
return Result<VkSurfaceKHR>::Error(BasicErrorCode::Failed);
return Result<VkSurfaceKHR>::Success(surface);
}
const char* Window::GetError()

View File

@ -1,10 +1,8 @@
orange_src = [
'Core/Log.cpp',
'Render/Instance.cpp',
'Render/PhysicalDevice.cpp',
'Render/Device.cpp',
'Render/Utils.cpp',
'Render/RenderContext_Init.cpp',
'Render/Swapchain.cpp',
'Render/Window.cpp',
]