631 lines
26 KiB
C++
631 lines
26 KiB
C++
#include "RenderEngine.h"
|
|
|
|
#include <functional>
|
|
#include <queue>
|
|
#include <set>
|
|
#include <stdexcept>
|
|
#include <fstream>
|
|
|
|
#include "CoreInstance.h"
|
|
#include "Log/Log.h"
|
|
|
|
#include "GLFW/glfw3.h"
|
|
|
|
const std::vector<const char*> RenderEngine::deviceExtensions = {
|
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
|
};
|
|
|
|
#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
|
|
|
|
RenderEngine::SwapchainSupportDetails RenderEngine::query_swapchain_details()
|
|
{
|
|
SwapchainSupportDetails details;
|
|
|
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_, surface_, &details.capabilities);
|
|
|
|
uint32_t surface_format_cnt = 0;
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, nullptr));
|
|
details.formats.resize(surface_format_cnt);
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, details.formats.data()));
|
|
|
|
uint32_t present_modes_cnt = 0;
|
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, nullptr));
|
|
details.present_modes.resize(surface_format_cnt);
|
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, details.present_modes.data()));
|
|
|
|
return details;
|
|
}
|
|
|
|
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 indices.is_complete() && check_device_extensions_support(device);
|
|
}
|
|
|
|
bool RenderEngine::check_device_extensions_support(VkPhysicalDevice device)
|
|
{
|
|
uint32_t extension_count;
|
|
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr));
|
|
std::vector<VkExtensionProperties> available_extensions(extension_count);
|
|
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data()));
|
|
|
|
for (const auto& extension : deviceExtensions)
|
|
{
|
|
bool isFind = false;
|
|
for (const auto& i : available_extensions)
|
|
{
|
|
if (std::strcmp(i.extensionName, extension) == 0)
|
|
{
|
|
isFind = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!isFind)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
VkSurfaceFormatKHR RenderEngine::choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats)
|
|
{
|
|
for (const auto& i : surface_formats)
|
|
{
|
|
if (i.format == VK_FORMAT_B8G8R8A8_SRGB && i.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
|
return i;
|
|
}
|
|
return surface_formats[0];
|
|
}
|
|
|
|
VkPresentModeKHR RenderEngine::choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes, VkPresentModeKHR desired_present_mode)
|
|
{
|
|
for (const auto& i : present_modes)
|
|
{
|
|
if (i == desired_present_mode)
|
|
return i;
|
|
}
|
|
return VK_PRESENT_MODE_FIFO_KHR;
|
|
}
|
|
|
|
VkExtent2D RenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
|
|
{
|
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
|
return capabilities.currentExtent;
|
|
else
|
|
{
|
|
int width, height;
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
VkExtent2D actualExtent = {
|
|
static_cast<uint32_t>(width),
|
|
static_cast<uint32_t>(height)
|
|
};
|
|
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
|
return actualExtent;
|
|
}
|
|
}
|
|
|
|
VkShaderModule RenderEngine::create_shader_module(const std::string code)
|
|
{
|
|
VkShaderModuleCreateInfo shader_module_info{};
|
|
shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
shader_module_info.codeSize = code.size();
|
|
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(code.c_str());
|
|
|
|
VkShaderModule shader_module;
|
|
VK_CHECK(vkCreateShaderModule(device_, &shader_module_info, nullptr, &shader_module));
|
|
return shader_module;
|
|
}
|
|
|
|
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
|
|
const 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 = static_cast<uint32_t>(deviceExtensions.size());
|
|
device_create_info.ppEnabledExtensionNames = deviceExtensions.data();
|
|
|
|
#ifdef _DEBUG
|
|
const 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_swapchain(VkPresentModeKHR desired_present_mode)
|
|
{
|
|
SwapchainSupportDetails swapchain_support = query_swapchain_details();
|
|
VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats);
|
|
VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, desired_present_mode);
|
|
VkExtent2D extent = choose_extent(swapchain_support.capabilities, window_);
|
|
|
|
uint32_t image_count = swapchain_support.capabilities.minImageCount + 1;
|
|
if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount)
|
|
image_count = swapchain_support.capabilities.maxImageCount;
|
|
|
|
VkSwapchainCreateInfoKHR swapchain_create_info{};
|
|
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
swapchain_create_info.surface = surface_;
|
|
swapchain_create_info.minImageCount = image_count;
|
|
swapchain_create_info.imageFormat = surface_format.format;
|
|
swapchain_create_info.imageColorSpace = surface_format.colorSpace;
|
|
swapchain_create_info.imageExtent = extent;
|
|
swapchain_create_info.imageArrayLayers = 1;
|
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform;
|
|
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
swapchain_create_info.presentMode = present_mode;
|
|
swapchain_create_info.clipped = VK_TRUE;
|
|
swapchain_create_info.oldSwapchain = VK_NULL_HANDLE;
|
|
|
|
QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_);
|
|
uint32_t queue_family_indices[] = {family_indices.graphycs_family.value(), family_indices.present_family.value()};
|
|
if (family_indices.graphycs_family != family_indices.present_family)
|
|
{
|
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
swapchain_create_info.queueFamilyIndexCount = 2;
|
|
swapchain_create_info.pQueueFamilyIndices = queue_family_indices;
|
|
}
|
|
else
|
|
{
|
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
swapchain_create_info.queueFamilyIndexCount = 0;
|
|
swapchain_create_info.pQueueFamilyIndices = nullptr;
|
|
}
|
|
|
|
VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_));
|
|
|
|
vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, nullptr);
|
|
swapchain_images_.resize(image_count);
|
|
vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, swapchain_images_.data());
|
|
|
|
swapchain_image_format_ = surface_format.format;
|
|
swapchain_extent_ = extent;
|
|
}
|
|
|
|
void RenderEngine::create_image_views()
|
|
{
|
|
VkImageViewCreateInfo image_view_info{};
|
|
image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
image_view_info.format = swapchain_image_format_;
|
|
image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
image_view_info.subresourceRange.baseMipLevel = 0;
|
|
image_view_info.subresourceRange.levelCount = 1;
|
|
image_view_info.subresourceRange.baseArrayLayer = 0;
|
|
image_view_info.subresourceRange.layerCount = 1;
|
|
|
|
swapchain_image_views_.resize(swapchain_images_.size());
|
|
for (uint32_t i = 0; i < swapchain_images_.size(); ++i)
|
|
{
|
|
image_view_info.image = swapchain_images_[i];
|
|
VK_CHECK(vkCreateImageView(device_, &image_view_info, nullptr, &swapchain_image_views_[i]));
|
|
}
|
|
}
|
|
|
|
void RenderEngine::create_render_pass()
|
|
{
|
|
VkAttachmentDescription attachment_description{};
|
|
attachment_description.format = swapchain_image_format_;
|
|
attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
|
|
VkAttachmentReference attachment_reference{};
|
|
attachment_reference.attachment = 0;
|
|
attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
|
|
VkSubpassDescription subpass_description{};
|
|
subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
subpass_description.colorAttachmentCount = 1;
|
|
subpass_description.pColorAttachments = &attachment_reference;
|
|
|
|
VkRenderPassCreateInfo render_pass_info{};
|
|
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
|
render_pass_info.attachmentCount = 1;
|
|
render_pass_info.pAttachments = &attachment_description;
|
|
render_pass_info.subpassCount = 1;
|
|
render_pass_info.pSubpasses = &subpass_description;
|
|
|
|
VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_));
|
|
}
|
|
|
|
void RenderEngine::create_graphycs_pipeline()
|
|
{
|
|
std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary);
|
|
if (!vertex_shader_file.is_open())
|
|
throw std::runtime_error("Vertex shader not found");
|
|
std::ifstream fragment_shader_file("Shaders/fragment.spv", std::ios::binary);
|
|
if (!fragment_shader_file.is_open()) {
|
|
vertex_shader_file.close();
|
|
throw std::runtime_error("Fragment shader not found");
|
|
}
|
|
|
|
std::string vertex_shader_code((std::istreambuf_iterator<char>(vertex_shader_file)), std::istreambuf_iterator<char>());
|
|
std::string fragment_shader_code((std::istreambuf_iterator<char>(fragment_shader_file)), std::istreambuf_iterator<char>());
|
|
vertex_shader_file.close();
|
|
fragment_shader_file.close();
|
|
|
|
VkShaderModule vertex_shader = create_shader_module(vertex_shader_code);
|
|
VkShaderModule fragment_shader = create_shader_module(fragment_shader_code);
|
|
|
|
VkPipelineShaderStageCreateInfo vertex_shader_stage_info{};
|
|
vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
|
vertex_shader_stage_info.module = vertex_shader;
|
|
vertex_shader_stage_info.pName = "main";
|
|
|
|
VkPipelineShaderStageCreateInfo fragment_shader_stage_info{};
|
|
fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
fragment_shader_stage_info.module = fragment_shader;
|
|
fragment_shader_stage_info.pName = "main";
|
|
|
|
VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info};
|
|
const std::vector<VkDynamicState> dynamic_states = {
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
VK_DYNAMIC_STATE_SCISSOR
|
|
};
|
|
|
|
VkPipelineDynamicStateCreateInfo dynamic_state_info{};
|
|
dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
dynamic_state_info.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
|
|
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_input_info{};
|
|
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
vertex_input_info.vertexAttributeDescriptionCount = 0;
|
|
vertex_input_info.pVertexAttributeDescriptions = nullptr;
|
|
vertex_input_info.vertexBindingDescriptionCount = 0;
|
|
vertex_input_info.pVertexBindingDescriptions = nullptr;
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_info{};
|
|
input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
input_assembly_info.primitiveRestartEnable = VK_FALSE;
|
|
|
|
VkViewport viewport{};
|
|
viewport.x = 0.0f;
|
|
viewport.y = 0.0f;
|
|
viewport.width = static_cast<float>(swapchain_extent_.width);
|
|
viewport.height = static_cast<float>(swapchain_extent_.height);
|
|
viewport.minDepth = 0.0f;
|
|
viewport.maxDepth = 1.0f;
|
|
|
|
VkRect2D scissor{};
|
|
scissor.offset = {0, 0};
|
|
scissor.extent = swapchain_extent_;
|
|
|
|
VkPipelineViewportStateCreateInfo viewport_info{};
|
|
viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
viewport_info.viewportCount = 1;
|
|
viewport_info.pViewports = &viewport;
|
|
viewport_info.scissorCount = 1;
|
|
viewport_info.pScissors = &scissor;
|
|
|
|
VkPipelineRasterizationStateCreateInfo rasterization_info{};
|
|
rasterization_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
rasterization_info.depthClampEnable = VK_FALSE;
|
|
rasterization_info.rasterizerDiscardEnable = VK_FALSE;
|
|
rasterization_info.polygonMode = VK_POLYGON_MODE_FILL;
|
|
rasterization_info.lineWidth = 1.0f;
|
|
rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT;
|
|
rasterization_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
|
rasterization_info.depthBiasEnable = VK_FALSE;
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisample_info{};
|
|
multisample_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
multisample_info.sampleShadingEnable = VK_FALSE;
|
|
multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
VkPipelineColorBlendAttachmentState color_blend_attachment_state{};
|
|
color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
color_blend_attachment_state.blendEnable = VK_TRUE;
|
|
color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
|
|
color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
|
|
VkPipelineColorBlendStateCreateInfo color_blend_info{};
|
|
color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
color_blend_info.logicOpEnable = VK_FALSE;
|
|
color_blend_info.attachmentCount = 1;
|
|
color_blend_info.pAttachments = &color_blend_attachment_state;
|
|
color_blend_info.blendConstants[0] = 0.0f;
|
|
color_blend_info.blendConstants[1] = 0.0f;
|
|
color_blend_info.blendConstants[2] = 0.0f;
|
|
color_blend_info.blendConstants[3] = 0.0f;
|
|
|
|
VkPipelineLayoutCreateInfo pipeline_layout_info{};
|
|
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
|
|
VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_));
|
|
|
|
VkGraphicsPipelineCreateInfo graphics_pipeline_info{};
|
|
graphics_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
graphics_pipeline_info.stageCount = 2;
|
|
graphics_pipeline_info.pStages = shader_stages;
|
|
graphics_pipeline_info.layout = pipeline_layout_;
|
|
graphics_pipeline_info.pColorBlendState = &color_blend_info;
|
|
graphics_pipeline_info.pDynamicState = &dynamic_state_info;
|
|
graphics_pipeline_info.pInputAssemblyState = &input_assembly_info;
|
|
graphics_pipeline_info.pMultisampleState = &multisample_info;
|
|
graphics_pipeline_info.pRasterizationState = &rasterization_info;
|
|
graphics_pipeline_info.pViewportState = &viewport_info;
|
|
graphics_pipeline_info.pVertexInputState = &vertex_input_info;
|
|
graphics_pipeline_info.pDepthStencilState = nullptr;
|
|
graphics_pipeline_info.renderPass = render_pass_;
|
|
graphics_pipeline_info.subpass = 0;
|
|
graphics_pipeline_info.basePipelineHandle = nullptr;
|
|
graphics_pipeline_info.basePipelineIndex = -1;
|
|
|
|
VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphycs_pipeline_));
|
|
|
|
vkDestroyShaderModule(device_, vertex_shader, nullptr);
|
|
vkDestroyShaderModule(device_, fragment_shader, nullptr);
|
|
}
|
|
|
|
void RenderEngine::create_framebuffers()
|
|
{
|
|
framebuffers_.resize(swapchain_images_.size());
|
|
|
|
VkFramebufferCreateInfo framebuffer_info{};
|
|
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
framebuffer_info.renderPass = render_pass_;
|
|
framebuffer_info.attachmentCount = 1;
|
|
framebuffer_info.width = swapchain_extent_.width;
|
|
framebuffer_info.height = swapchain_extent_.height;
|
|
framebuffer_info.layers = 1;
|
|
|
|
for (size_t i = 0; i < framebuffers_.size(); ++i)
|
|
{
|
|
framebuffer_info.pAttachments = &swapchain_image_views_[i];
|
|
VK_CHECK(vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &framebuffers_[i]));
|
|
}
|
|
}
|
|
|
|
void RenderEngine::create_surface()
|
|
{
|
|
VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_));
|
|
}
|
|
|
|
RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode):
|
|
core_(core),
|
|
window_(window)
|
|
#ifdef _DEBUG
|
|
,debug_messenger_(nullptr)
|
|
#endif
|
|
{
|
|
create_instance();
|
|
create_surface();
|
|
pick_physical_device();
|
|
create_logical_device();
|
|
create_swapchain(desired_present_mode);
|
|
create_image_views();
|
|
create_render_pass();
|
|
create_graphycs_pipeline();
|
|
}
|
|
|
|
RenderEngine::~RenderEngine()
|
|
{
|
|
for (auto& i : framebuffers_)
|
|
vkDestroyFramebuffer(device_, i, nullptr);
|
|
|
|
if (graphycs_pipeline_ != VK_NULL_HANDLE)
|
|
vkDestroyPipeline(device_, graphycs_pipeline_, nullptr);
|
|
|
|
if (pipeline_layout_ != VK_NULL_HANDLE)
|
|
vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr);
|
|
|
|
if (render_pass_ != VK_NULL_HANDLE)
|
|
vkDestroyRenderPass(device_, render_pass_, nullptr);
|
|
|
|
for (auto image_view : swapchain_image_views_)
|
|
vkDestroyImageView(device_, image_view, nullptr);
|
|
swapchain_image_views_.clear();
|
|
|
|
if (swapchain_ != VK_NULL_HANDLE)
|
|
vkDestroySwapchainKHR(device_, swapchain_, nullptr);
|
|
|
|
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);
|
|
}
|