From dc3b3dbe8041c9bdfec2901562c19a76be985a67 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Thu, 4 Aug 2022 02:00:54 +0000 Subject: [PATCH] Work --- include/Orange/Core/FileSystem.h | 2 +- include/Orange/Core/Result.h | 50 ++++--- include/Orange/Core/SmallVector.h | 1 + include/Orange/Core/Traits.h | 25 ++++ include/Orange/Render/RenderContext.h | 35 +++++ include/Orange/Render/Renderer.h | 96 ------------ include/Orange/Render/Swapchain.h | 28 ++++ include/Orange/Render/VulkanHelpers.h | 20 +++ include/Orange/Render/Window.h | 5 +- src/Apps/Tools/CubeTest.cpp | 15 +- src/Orange/Render/Device.cpp | 63 -------- src/Orange/Render/Instance.cpp | 109 -------------- src/Orange/Render/PhysicalDevice.cpp | 65 --------- src/Orange/Render/RenderContext_Init.cpp | 178 +++++++++++++++++++++++ src/Orange/Render/Swapchain.cpp | 115 +++++++++++++++ src/Orange/Render/Utils.cpp | 21 --- src/Orange/Render/Window.cpp | 14 +- src/Orange/meson.build | 6 +- 18 files changed, 460 insertions(+), 388 deletions(-) create mode 100644 include/Orange/Render/RenderContext.h delete mode 100644 include/Orange/Render/Renderer.h create mode 100644 include/Orange/Render/Swapchain.h create mode 100644 include/Orange/Render/VulkanHelpers.h delete mode 100644 src/Orange/Render/Device.cpp delete mode 100644 src/Orange/Render/Instance.cpp delete mode 100644 src/Orange/Render/PhysicalDevice.cpp create mode 100644 src/Orange/Render/RenderContext_Init.cpp create mode 100644 src/Orange/Render/Swapchain.cpp delete mode 100644 src/Orange/Render/Utils.cpp diff --git a/include/Orange/Core/FileSystem.h b/include/Orange/Core/FileSystem.h index 275bc71..3ca1870 100644 --- a/include/Orange/Core/FileSystem.h +++ b/include/Orange/Core/FileSystem.h @@ -14,7 +14,7 @@ namespace orange::fs }; template - using FileResult = Result; + using FileResult = Result; FileResult OpenFileIntoBuffer(const char *path); } diff --git a/include/Orange/Core/Result.h b/include/Orange/Core/Result.h index 1960d11..ae18424 100644 --- a/include/Orange/Core/Result.h +++ b/include/Orange/Core/Result.h @@ -12,11 +12,12 @@ namespace orange { Invalid = -1, Failed = -2, + NotFound = -3, Success = 0, }; - template + template 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 + static Result Success(Args&&... args) + { + Result res; + res.Create(Forward(args)...); + res.MakeSuccess(); + return res; + } + + ErrorCode Code() const { return m_error; } + + template + 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 res; - res.MakeError(code); - return res; - } - - template - static Result Success(Args&&... args) - { - Result res; - res.Create(Forward(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(&m_data); } friend T; AlignedStorage m_data; - ErrorCode m_error = ErrorCode::Invalid; + ErrorCode m_error = InvalidCode; bool m_created = false; }; } diff --git a/include/Orange/Core/SmallVector.h b/include/Orange/Core/SmallVector.h index 4a30cdb..9ee2802 100644 --- a/include/Orange/Core/SmallVector.h +++ b/include/Orange/Core/SmallVector.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/include/Orange/Core/Traits.h b/include/Orange/Core/Traits.h index 012039a..494771a 100644 --- a/include/Orange/Core/Traits.h +++ b/include/Orange/Core/Traits.h @@ -35,4 +35,29 @@ namespace orange { return static_cast&&>(arg); } + + template + [[nodiscard]] constexpr size_t Size(const T (&array)[N]) noexcept + { + (void)array; + return N; + } + + template + [[nodiscard]] constexpr T Min( const T& valMin, const T& valMax ) + { + return valMin < valMax ? valMin : valMax; + } + + template + [[nodiscard]] constexpr T Max( const T& valMin, const T& valMax ) + { + return valMin > valMax ? valMin : valMax; + } + + template + [[nodiscard]] constexpr T Clamp( const T& val, const T& minVal, const T& maxVal ) + { + return Min( Max( val, minVal ), maxVal ); + } } diff --git a/include/Orange/Render/RenderContext.h b/include/Orange/Render/RenderContext.h new file mode 100644 index 0000000..6ffcd79 --- /dev/null +++ b/include/Orange/Render/RenderContext.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +#include + +namespace orange +{ + template + using VulkanResult = Result; + + class RenderContext + { + public: + ~RenderContext(); + + static Result 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(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; + }; +} \ No newline at end of file diff --git a/include/Orange/Render/Renderer.h b/include/Orange/Render/Renderer.h deleted file mode 100644 index b93c93f..0000000 --- a/include/Orange/Render/Renderer.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -namespace orange -{ - class Window; - - class PhysicalDevice - { - public: - PhysicalDevice() = default; - PhysicalDevice(const PhysicalDevice&) = default; - PhysicalDevice& operator = (const PhysicalDevice&) = default; - - ~PhysicalDevice() = default; - - static Result 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(VkPhysicalDevice physicalDevice, uint32_t graphicsQueueFamilyIndex); - private: - VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; - uint32_t m_graphicsQueueFamilyIndex = ~0u; - }; - - class Instance - { - public: - ~Instance(); - - static Result Create(Window& window, const char* name); - - VkInstance operator *() { return m_instance; } - - Span PhysicalDevices() { return m_physicalDevices; } - protected: - friend Result; - Instance(VkInstance instance, Span physicalDevice); - private: - VkInstance m_instance = VK_NULL_HANDLE; - - SmallVector m_physicalDevices; - }; - - class GPUBuffer - { - public: - ~GPUBuffer(); - - static Result Create(); - protected: - friend Result; - GPUBuffer(VkDeviceMemory memory, VkBuffer buffer, void* ptr); - private: - VkDeviceMemory m_memory; - VkBuffer m_buffer; - }; - - class Device - { - public: - ~Device(); - - static Result Create(Instance& instance, PhysicalDevice physicalDevice); - protected: - friend Result; - 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 Create(); - }; - - PhysicalDevice PickBestPhysicalDevice(Span physDevs); -} \ No newline at end of file diff --git a/include/Orange/Render/Swapchain.h b/include/Orange/Render/Swapchain.h new file mode 100644 index 0000000..900e080 --- /dev/null +++ b/include/Orange/Render/Swapchain.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include + +namespace orange +{ + class Swapchain + { + public: + ~Swapchain(); + + static Result Create(RenderContext& context, VkSurfaceKHR surface); + protected: + friend class Result; + Swapchain(VkDevice device, VkSurfaceKHR surface, VkExtent2D extent, VkSwapchainKHR swapchain); + private: + VkDevice m_device; + VkSurfaceKHR m_surface; + VkExtent2D m_extent; + VkSwapchainKHR m_swapchain; + + SmallVector m_images; + }; +} \ No newline at end of file diff --git a/include/Orange/Render/VulkanHelpers.h b/include/Orange/Render/VulkanHelpers.h new file mode 100644 index 0000000..74c3db0 --- /dev/null +++ b/include/Orange/Render/VulkanHelpers.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace orange +{ + template + 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(arguments)..., &count, outArray.Data()); + return count; + } +} diff --git a/include/Orange/Render/Window.h b/include/Orange/Render/Window.h index a830a95..a1c4053 100644 --- a/include/Orange/Render/Window.h +++ b/include/Orange/Render/Window.h @@ -1,6 +1,7 @@ #pragma once #include +#include 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 CreateSurface(VkInstance instance); static const char* GetError(); diff --git a/src/Apps/Tools/CubeTest.cpp b/src/Apps/Tools/CubeTest.cpp index 182bded..0d408c5 100644 --- a/src/Apps/Tools/CubeTest.cpp +++ b/src/Apps/Tools/CubeTest.cpp @@ -1,7 +1,8 @@ #include #include -#include +#include +#include using namespace orange; @@ -13,14 +14,16 @@ int main(int argc, char** argv) if (!r_window) return 1; - Result r_instance = Instance::Create(*r_window, "Orange"); - if (!r_instance) + Result r_renderContext = RenderContext::Create("Cube Test"); + if (!r_renderContext) return 1; - PhysicalDevice physicalDevice = PickBestPhysicalDevice(r_instance->PhysicalDevices()); + Result r_surface = r_window->CreateSurface(r_renderContext->Instance()); + if (!r_surface) + return 1; - Result r_device = Device::Create(*r_instance, physicalDevice); - if (!r_device) + Result r_swapchain = Swapchain::Create(*r_renderContext, *r_surface); + if (!r_swapchain) return 1; return 0; diff --git a/src/Orange/Render/Device.cpp b/src/Orange/Render/Device.cpp deleted file mode 100644 index 64ea588..0000000 --- a/src/Orange/Render/Device.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "Orange/Core/Log.h" -#include "Orange/Core/Result.h" -#include - -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::Create(Instance& instance, PhysicalDevice physicalDevice) - { - VkDevice device = VK_NULL_HANDLE; - if (!(device = CreateDevice(physicalDevice))) - { - log::err("Failed to create Vulkan device"); - return Result::Error(BasicErrorCode::Failed); - } - - return Result::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); - } - -} diff --git a/src/Orange/Render/Instance.cpp b/src/Orange/Render/Instance.cpp deleted file mode 100644 index e3a7761..0000000 --- a/src/Orange/Render/Instance.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include - -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 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::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::Error(BasicErrorCode::Failed); - } - - SmallVector physicalDevices; - { - uint32_t vulkanPhysicalDeviceCount = {}; - if (vkEnumeratePhysicalDevices(instance, &vulkanPhysicalDeviceCount, nullptr) != VK_SUCCESS) - { - log::err("Failed to get physical device count"); - return Result::Error(BasicErrorCode::Failed); - } - - if (!vulkanPhysicalDeviceCount) - { - log::err("No physical devices found"); - return Result::Error(BasicErrorCode::Failed); - } - - { - SmallVector vulkanPhysicalDevices{ vulkanPhysicalDeviceCount }; - if (vkEnumeratePhysicalDevices(instance, &vulkanPhysicalDeviceCount, vulkanPhysicalDevices.Data()) != VK_SUCCESS) - { - log::err("Failed to enumerate physical devices"); - return Result::Error(BasicErrorCode::Failed); - } - - for (auto& physDev : vulkanPhysicalDevices) - { - Result r_physDev = PhysicalDevice::Create(physDev); - if (!r_physDev) - continue; - - physicalDevices.PushBack(*r_physDev); - } - } - } - - return Result::Success(instance, physicalDevices); - } - - Instance::Instance(VkInstance instance, Span physicalDevices) - : m_instance { instance } - , m_physicalDevices{ physicalDevices } - { - } - - Instance::~Instance() - { - vkDestroyInstance(m_instance, nullptr); - } - -} diff --git a/src/Orange/Render/PhysicalDevice.cpp b/src/Orange/Render/PhysicalDevice.cpp deleted file mode 100644 index 598ff0a..0000000 --- a/src/Orange/Render/PhysicalDevice.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "Orange/Core/Log.h" -#include "Orange/Core/Result.h" -#include - -namespace orange -{ - static uint32_t PickQueueFamilyIndex(VkPhysicalDevice physDev) - { - uint32_t queueFamilyPropertyCount = {}; - vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueFamilyPropertyCount, nullptr); - - SmallVector 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::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::Error(BasicErrorCode::Failed); - } - - // TODO: Check if it can present to surface. - - return Result::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 } - { - } - -} diff --git a/src/Orange/Render/RenderContext_Init.cpp b/src/Orange/Render/RenderContext_Init.cpp new file mode 100644 index 0000000..277e709 --- /dev/null +++ b/src/Orange/Render/RenderContext_Init.cpp @@ -0,0 +1,178 @@ +#include +#include + +#include +#include +#include + +namespace orange +{ + static VulkanResult CreateVkInstance(const char* appName) + { + SmallVector 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::Error(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR); + } + + if (!VkEnumerate(Window::GetInstanceExtensions, instanceExtensions, *r_tempWindow)) + return VulkanResult::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::Error(result); + } + + return VulkanResult::Success(instance); + } + + static Result PickQueueFamilyIndex(VkPhysicalDevice physicalDevice) + { + SmallVector 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::Success(i); + } + return Result::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 PickPhysicalDevice(VkInstance instance) + { + SmallVector 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::Error(BasicErrorCode::Failed); + } + + return Result::Success(bestPhysicalDevice); + } + + static VulkanResult 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::Error(result); + } + + return VulkanResult::Success(device); + } + + Result RenderContext::Create(const char *appName) + { + auto r_instance = CreateVkInstance(appName); + if (!r_instance) + return Result::Error(BasicErrorCode::Failed); + + auto r_physicalDevice = PickPhysicalDevice(*r_instance); + if (!r_physicalDevice) + return Result::Error(BasicErrorCode::Failed); + + uint32_t graphicsQueueFamilyIndex = *PickQueueFamilyIndex(*r_physicalDevice); + + auto r_device = CreateVkDevice(*r_physicalDevice, graphicsQueueFamilyIndex); + if (!r_device) + return Result::Error(BasicErrorCode::Failed); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(*r_device, graphicsQueueFamilyIndex, 0, &queue); + + return Result::Success(*r_instance, *r_physicalDevice, *r_device, queue); + } + + RenderContext::~RenderContext() + { + vkDestroyDevice(m_device, nullptr); + vkDestroyInstance(m_instance, nullptr); + } + +} diff --git a/src/Orange/Render/Swapchain.cpp b/src/Orange/Render/Swapchain.cpp new file mode 100644 index 0000000..8fecdcd --- /dev/null +++ b/src/Orange/Render/Swapchain.cpp @@ -0,0 +1,115 @@ +#include + +#include +#include +#include + +namespace orange +{ + static Result ChooseSwapChainFormat(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) + { + SmallVector surfaceFormats; + if (!VkEnumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, surfaceFormats, physicalDevice, surface)) + { + log::err("Surface supports no formats"); + return Result::Error(BasicErrorCode::NotFound); + } + + for (auto& surfaceFormat : surfaceFormats) + { + if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM && surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + return Result::Success(surfaceFormat); + } + + return Result::Error(BasicErrorCode::NotFound); + } + + static VkPresentModeKHR ChoosePresentMode(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) + { + SmallVector 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::Create(RenderContext& context, VkSurfaceKHR surface) + { + VkSurfaceCapabilitiesKHR capabilities; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.PhysicalDevice(), surface, &capabilities); + + Result r_format = ChooseSwapChainFormat(context.PhysicalDevice(), surface); + if (!r_format) + return Result::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::Error(); + } + + return Result::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); + } +} \ No newline at end of file diff --git a/src/Orange/Render/Utils.cpp b/src/Orange/Render/Utils.cpp deleted file mode 100644 index 8def08c..0000000 --- a/src/Orange/Render/Utils.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -namespace orange -{ - PhysicalDevice PickBestPhysicalDevice(Span physDevs) - { - PhysicalDevice bestPhysDev; - int bestScore = -1; - for (auto physDev : physDevs) - { - if (int score = physDev.Score() > bestScore) - { - bestPhysDev = physDev; - bestScore = score; - } - } - - return bestPhysDev; - } -} \ No newline at end of file diff --git a/src/Orange/Render/Window.cpp b/src/Orange/Render/Window.cpp index c28d450..c40bb4c 100644 --- a/src/Orange/Render/Window.cpp +++ b/src/Orange/Render/Window.cpp @@ -1,6 +1,7 @@ #include "Orange/Core/Result.h" #include "Orange/Core/Log.h" #include +#include #include #include @@ -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 Window::CreateSurface(VkInstance instance) + { + VkSurfaceKHR surface = VK_NULL_HANDLE; + if (SDL_Vulkan_CreateSurface(m_window, instance, &surface) != SDL_TRUE) + return Result::Error(BasicErrorCode::Failed); + + return Result::Success(surface); } const char* Window::GetError() diff --git a/src/Orange/meson.build b/src/Orange/meson.build index 775df3d..a0e5cfd 100644 --- a/src/Orange/meson.build +++ b/src/Orange/meson.build @@ -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', ]