251 lines
9.0 KiB
C++
251 lines
9.0 KiB
C++
#include "RenderEngine.h"
|
|
|
|
#include <queue>
|
|
#include <set>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
#include "CoreInstance.h"
|
|
#include "Log/Log.h"
|
|
|
|
#include "GLFW/glfw3.h"
|
|
|
|
#ifdef _DEBUG
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
void* pUserData) {
|
|
|
|
std::string msg = "validation layer: ";
|
|
msg += pCallbackData->pMessage;
|
|
Log(msg);
|
|
|
|
return VK_FALSE;
|
|
}
|
|
|
|
VkResult RenderEngine::enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info)
|
|
{
|
|
PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT"));
|
|
return debug_creator(instance_, create_info, nullptr, &debug_messenger_);
|
|
}
|
|
#endif
|
|
|
|
std::vector<const char*> RenderEngine::get_required_extensions()
|
|
{
|
|
uint32_t extensions_count = 0;
|
|
const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count);
|
|
std::vector<const char*> extensions(glfw_extension, glfw_extension + extensions_count);
|
|
|
|
#ifdef _DEBUG
|
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
#endif
|
|
return extensions;
|
|
}
|
|
|
|
|
|
bool RenderEngine::QueueFamilyIndices::is_complete()
|
|
{
|
|
return graphycs_family.has_value() && present_family.has_value();
|
|
}
|
|
|
|
bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface)
|
|
{
|
|
VkPhysicalDeviceProperties device_properties;
|
|
VkPhysicalDeviceFeatures device_features;
|
|
vkGetPhysicalDeviceProperties(device, &device_properties);
|
|
vkGetPhysicalDeviceFeatures(device, &device_features);
|
|
|
|
QueueFamilyIndices indices = find_queue_family_indices(device, surface);
|
|
|
|
return device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|
|
&& device_features.geometryShader
|
|
&& indices.is_complete();
|
|
}
|
|
|
|
RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface)
|
|
{
|
|
QueueFamilyIndices queue_family_indices;
|
|
|
|
uint32_t queueFamilyCount = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr);
|
|
std::vector<VkQueueFamilyProperties> family_propertieses(queueFamilyCount);
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_propertieses.data());
|
|
|
|
for (uint32_t i = 0; i < family_propertieses.size(); ++i)
|
|
{
|
|
if (family_propertieses[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
|
queue_family_indices.graphycs_family = i;
|
|
|
|
VkBool32 present_support = false;
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support));
|
|
if (present_support)
|
|
queue_family_indices.present_family = i;
|
|
if(queue_family_indices.is_complete())
|
|
break;
|
|
}
|
|
|
|
return queue_family_indices;
|
|
}
|
|
|
|
void RenderEngine::create_instance()
|
|
{
|
|
std::vector<const char*> extensions = get_required_extensions();
|
|
|
|
VkApplicationInfo app_info{};
|
|
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
app_info.apiVersion = VK_API_VERSION_1_0;
|
|
app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0);
|
|
app_info.pApplicationName = core_.getGameName().c_str();
|
|
app_info.pEngineName = "UwU Engine";
|
|
app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0);
|
|
|
|
|
|
VkInstanceCreateInfo instance_create_info{};
|
|
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
instance_create_info.pApplicationInfo = &app_info;
|
|
instance_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
|
instance_create_info.ppEnabledExtensionNames = extensions.data();
|
|
#ifdef _DEBUG
|
|
std::vector<const char*> layers_validation = {
|
|
"VK_LAYER_KHRONOS_validation"
|
|
};
|
|
instance_create_info.enabledLayerCount = static_cast<uint32_t>(layers_validation.size());
|
|
instance_create_info.ppEnabledLayerNames = layers_validation.data();
|
|
VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{};
|
|
debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
|
debug_messenger_create_info.pfnUserCallback = &debugCallback;
|
|
instance_create_info.pNext = &debug_messenger_create_info;
|
|
#endif
|
|
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_));
|
|
#ifdef _DEBUG
|
|
VK_CHECK(enable_layer_validation(&debug_messenger_create_info));
|
|
#endif
|
|
}
|
|
|
|
void RenderEngine::pick_physical_device()
|
|
{
|
|
uint32_t device_count = 0;
|
|
std::vector<VkPhysicalDevice> devices;
|
|
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr));
|
|
devices.resize(device_count);
|
|
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data()));
|
|
|
|
for (const auto& device : devices)
|
|
{
|
|
if (is_device_suitable(device, surface_))
|
|
{
|
|
physical_device_ = device;
|
|
VkPhysicalDeviceProperties device_properties;
|
|
vkGetPhysicalDeviceProperties(physical_device_, &device_properties);
|
|
Log("Using device: " + std::string(device_properties.deviceName));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (VK_NULL_HANDLE == physical_device_)
|
|
throw std::runtime_error("No suitable device found");
|
|
}
|
|
|
|
void RenderEngine::create_logical_device()
|
|
{
|
|
QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_);
|
|
|
|
VkPhysicalDeviceFeatures device_features{};
|
|
|
|
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
|
std::set<uint32_t> unique_queue_families = {indices.graphycs_family.value(), indices.present_family.value()};
|
|
|
|
float queue_priority = 1.0f;
|
|
VkDeviceQueueCreateInfo device_queue_create_info{};
|
|
device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
device_queue_create_info.pQueuePriorities = &queue_priority;
|
|
for (auto queue_family : unique_queue_families)
|
|
{
|
|
device_queue_create_info.queueFamilyIndex = queue_family;
|
|
device_queue_create_info.queueCount = 1;
|
|
queue_create_infos.push_back(device_queue_create_info);
|
|
}
|
|
|
|
VkDeviceCreateInfo device_create_info{};
|
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
device_create_info.queueCreateInfoCount = static_cast<uint32_t>(unique_queue_families.size());
|
|
device_create_info.pQueueCreateInfos = queue_create_infos.data();
|
|
device_create_info.pEnabledFeatures = &device_features;
|
|
device_create_info.enabledExtensionCount = 0;
|
|
device_create_info.ppEnabledExtensionNames = nullptr;
|
|
|
|
#ifdef _DEBUG
|
|
std::vector<const char*> layers_validation = {
|
|
"VK_LAYER_KHRONOS_validation"
|
|
};
|
|
device_create_info.enabledLayerCount = static_cast<uint32_t>(layers_validation.size());
|
|
device_create_info.ppEnabledLayerNames = layers_validation.data();
|
|
#else
|
|
device_create_info.enabledLayerCount = 0;
|
|
device_create_info.ppEnabledLayerNames = nullptr;
|
|
|
|
#endif
|
|
VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_));
|
|
vkGetDeviceQueue(device_, indices.graphycs_family.value(), 0, &graphics_queue_);
|
|
vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_);
|
|
}
|
|
|
|
void RenderEngine::create_surface()
|
|
{
|
|
VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_));
|
|
}
|
|
|
|
RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window):
|
|
core_(core),
|
|
window_(window)
|
|
#ifdef _DEBUG
|
|
,debug_messenger_(nullptr)
|
|
#endif
|
|
{
|
|
create_instance();
|
|
create_surface();
|
|
pick_physical_device();
|
|
create_logical_device();
|
|
}
|
|
|
|
RenderEngine::~RenderEngine()
|
|
{
|
|
if (device_ != VK_NULL_HANDLE)
|
|
vkDestroyDevice(device_, nullptr);
|
|
|
|
if (surface_ != VK_NULL_HANDLE)
|
|
vkDestroySurfaceKHR(instance_, surface_, nullptr);
|
|
|
|
#ifdef _DEBUG
|
|
if (debug_messenger_ != nullptr && instance_ != nullptr) {
|
|
PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT"));
|
|
destroyer_messenger(instance_, debug_messenger_, nullptr);
|
|
}
|
|
#endif
|
|
|
|
if (instance_ != VK_NULL_HANDLE)
|
|
vkDestroyInstance(instance_, nullptr);
|
|
|
|
if (window_ != nullptr)
|
|
glfwDestroyWindow(window_);
|
|
glfwTerminate();
|
|
}
|
|
|
|
void RenderEngine::start()
|
|
{
|
|
while (!glfwWindowShouldClose(window_))
|
|
{
|
|
glfwSwapBuffers(window_);
|
|
glfwPollEvents();
|
|
}
|
|
}
|
|
|
|
void RenderEngine::stop_render()
|
|
{
|
|
if (window_ != nullptr && !glfwWindowShouldClose(window_))
|
|
glfwSetWindowShouldClose(window_, true);
|
|
}
|