Work
This commit is contained in:
parent
72f6214fdf
commit
dc3b3dbe80
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <Orange/Core/Traits.h>
|
||||
#include <Orange/Core/AlignedStorage.h>
|
||||
#include <Orange/Core/Span.h>
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 }
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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',
|
||||
]
|
||||
|
||||
|
|
Loading…
Reference in New Issue