179 lines
6.3 KiB
C++
179 lines
6.3 KiB
C++
|
#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);
|
||
|
}
|
||
|
|
||
|
}
|