swaping the chain
This commit is contained in:
@@ -6,27 +6,10 @@
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct QueueFamilyIndices {
|
||||
std::optional<uint32_t> graphicsFamily;
|
||||
std::optional<uint32_t> presentFamily;
|
||||
|
||||
bool isComplete()
|
||||
{
|
||||
return graphicsFamily.has_value() && presentFamily.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct SwapChainSupportDetails {
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
};
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
@@ -112,6 +95,11 @@ std::vector<const char*> getRequiredExtensions()
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
yolo::info("Requested instance extensions:");
|
||||
for (const auto& extension : extensions) {
|
||||
yolo::info("\t{}", extension);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@@ -149,39 +137,6 @@ QueueFamilyIndices device_get_queue_families(GraphicsDevice* g, VkPhysicalDevice
|
||||
return indices;
|
||||
}
|
||||
|
||||
bool device_evaluate(GraphicsDevice* g, VkPhysicalDevice device)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||
|
||||
yolo::info("Found device {}", deviceProperties.deviceName);
|
||||
// Discrete GPUs have a significant performance advantage
|
||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||
yolo::info("Device {} is a discrete GPU", deviceProperties.deviceName);
|
||||
score += 1000;
|
||||
}
|
||||
// We really want to favour ones with RayTracing support
|
||||
|
||||
// Maximum possible size of textures affects graphics quality
|
||||
score += deviceProperties.limits.maxImageDimension2D;
|
||||
|
||||
// Application won't function without geometry shaders
|
||||
if (!deviceFeatures.geometryShader)
|
||||
return 0;
|
||||
|
||||
// Ensure that the device can process the graphics commands that we need
|
||||
QueueFamilyIndices indices = device_get_queue_families(g, device);
|
||||
if (!indices.isComplete())
|
||||
return 0;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
bool device_evaluate_extensions(VkPhysicalDevice device, std::vector<const char*> extensions)
|
||||
{
|
||||
uint32_t extensionCount;
|
||||
@@ -199,39 +154,54 @@ bool device_evaluate_extensions(VkPhysicalDevice device, std::vector<const char*
|
||||
return requiredExtensions.empty();
|
||||
}
|
||||
|
||||
SwapChainSupportDetails device_get_swap_chain_support(GraphicsDevice* g, VkPhysicalDevice device)
|
||||
bool device_evaluate(GraphicsDevice* g, VkPhysicalDevice device)
|
||||
{
|
||||
SwapChainSupportDetails details;
|
||||
int score = 0;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, g->VulkanSurface, &details.capabilities);
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, g->VulkanSurface, &formatCount, nullptr);
|
||||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||
|
||||
if (formatCount != 0) {
|
||||
details.formats.resize(formatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, g->VulkanSurface, &formatCount, details.formats.data());
|
||||
yolo::info("Found device {}", deviceProperties.deviceName);
|
||||
// Discrete GPUs have a significant performance advantage
|
||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||
yolo::info("Device {} is a discrete GPU", deviceProperties.deviceName);
|
||||
score += 1000;
|
||||
}
|
||||
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, g->VulkanSurface, &presentModeCount, nullptr);
|
||||
|
||||
if (presentModeCount != 0) {
|
||||
details.presentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, g->VulkanSurface, &presentModeCount, details.presentModes.data());
|
||||
// does the device support the extensions we need?
|
||||
if (!device_evaluate_extensions(device, DEVICE_EXTENSIONS)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return details;
|
||||
// Maximum possible size of textures affects graphics quality
|
||||
score += deviceProperties.limits.maxImageDimension2D;
|
||||
|
||||
// Application won't function without geometry shaders
|
||||
if (!deviceFeatures.geometryShader)
|
||||
return 0;
|
||||
|
||||
// Ensure that the device can process the graphics commands that we need
|
||||
QueueFamilyIndices indices = device_get_queue_families(g, device);
|
||||
if (!indices.isComplete())
|
||||
return 0;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
GraphicsDevice* device_create()
|
||||
{
|
||||
GraphicsDevice* device = new GraphicsDevice();
|
||||
device_create_vulkan_instance(device);
|
||||
device_vulkan_debugger(device);
|
||||
window_set_surface(device);
|
||||
device->SurfaceSize = window_get_size();
|
||||
device_create_vulkan_physical_device(device);
|
||||
device_create_vulkan_logical_device(device);
|
||||
device_create_command_pool(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
@@ -371,7 +341,12 @@ void device_create_vulkan_logical_device(GraphicsDevice* device)
|
||||
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
|
||||
createInfo.enabledExtensionCount = 0;
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(DEVICE_EXTENSIONS.size());
|
||||
createInfo.ppEnabledExtensionNames = DEVICE_EXTENSIONS.data();
|
||||
yolo::info("Requested device extensions:");
|
||||
for (const auto& extension : DEVICE_EXTENSIONS) {
|
||||
yolo::info("\t{}", extension);
|
||||
}
|
||||
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(VALIDATION_LAYERS.size());
|
||||
@@ -389,4 +364,19 @@ void device_create_vulkan_logical_device(GraphicsDevice* device)
|
||||
vkGetDeviceQueue(device->VulkanDevice, indices.presentFamily.value(), 0, &device->VulkanPresentQueue);
|
||||
}
|
||||
|
||||
void device_create_command_pool(GraphicsDevice* device)
|
||||
{
|
||||
QueueFamilyIndices queueFamilyIndices = device_get_queue_families(device, device->VulkanPhysicalDevice);
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = {};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
|
||||
if (vkCreateCommandPool(device->VulkanDevice, &poolInfo, nullptr, &device->VulkanCommandPool) != VK_SUCCESS) {
|
||||
yolo::error("failed to create command pool!");
|
||||
}
|
||||
yolo::info("Vulkan command pool created");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
#define VALIDATION_LAYERS_ENABLED true
|
||||
@@ -11,6 +13,10 @@ const std::vector<const char*> VALIDATION_LAYERS = {
|
||||
};
|
||||
#endif
|
||||
|
||||
const std::vector<const char*> DEVICE_EXTENSIONS = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
typedef struct GraphicsDevice {
|
||||
VkInstance VulkanInstance;
|
||||
VkDebugUtilsMessengerEXT VulkanDebugMessenger;
|
||||
@@ -19,9 +25,21 @@ typedef struct GraphicsDevice {
|
||||
VkSurfaceKHR VulkanSurface;
|
||||
VkQueue VulkanGraphicsQueue;
|
||||
VkQueue VulkanPresentQueue;
|
||||
VkSwapchainKHR VulkanSwapChain;
|
||||
VkCommandPool VulkanCommandPool;
|
||||
|
||||
glm::ivec2 SurfaceSize;
|
||||
} GraphicsDevice;
|
||||
|
||||
struct QueueFamilyIndices {
|
||||
std::optional<uint32_t> graphicsFamily;
|
||||
std::optional<uint32_t> presentFamily;
|
||||
|
||||
bool isComplete()
|
||||
{
|
||||
return graphicsFamily.has_value() && presentFamily.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
// MUST ONLY BE CALLED AFTER GLFW INIT
|
||||
GraphicsDevice* device_create();
|
||||
void device_cleanup(GraphicsDevice* device);
|
||||
@@ -30,4 +48,8 @@ void device_create_vulkan_instance(GraphicsDevice* device);
|
||||
void device_vulkan_debugger(GraphicsDevice* device);
|
||||
void device_create_vulkan_physical_device(GraphicsDevice* device);
|
||||
void device_create_vulkan_logical_device(GraphicsDevice* device);
|
||||
void device_create_command_pool(GraphicsDevice* device);
|
||||
|
||||
QueueFamilyIndices device_get_queue_families(GraphicsDevice* g, VkPhysicalDevice device);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
#include "pipeline.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
#include "swapchain.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
Pipeline* pipeline_create(GraphicsDevice* device)
|
||||
{
|
||||
Pipeline* pipeline = new Pipeline();
|
||||
|
||||
pipeline->Device = device;
|
||||
pipeline->Swap = swapchain_create(device, device->SurfaceSize);
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
void pipeline_cleanup(Pipeline* pipeline)
|
||||
{
|
||||
delete pipeline;
|
||||
}
|
||||
|
||||
} // namespace inferno::graphics
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
struct SwapChain;
|
||||
|
||||
typedef struct Pipeline {
|
||||
VkPipelineLayout Layout;
|
||||
VkPipeline Pipeline;
|
||||
|
||||
GraphicsDevice* Device;
|
||||
SwapChain* Swap;
|
||||
} Pipeline;
|
||||
|
||||
Pipeline* pipeline_create(GraphicsDevice* device);
|
||||
void pipeline_cleanup(Pipeline* pipeline);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct SwapChainSupportDetails {
|
||||
VkSurfaceCapabilitiesKHR Capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> Formats;
|
||||
std::vector<VkPresentModeKHR> PresentModes;
|
||||
};
|
||||
|
||||
SwapChainSupportDetails device_get_swapchain_support(GraphicsDevice* g, VkPhysicalDevice device)
|
||||
{
|
||||
SwapChainSupportDetails details;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, g->VulkanSurface, &details.Capabilities);
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, g->VulkanSurface, &formatCount, nullptr);
|
||||
|
||||
if (formatCount != 0) {
|
||||
details.Formats.resize(formatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, g->VulkanSurface, &formatCount, details.Formats.data());
|
||||
}
|
||||
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, g->VulkanSurface, &presentModeCount, nullptr);
|
||||
|
||||
if (presentModeCount != 0) {
|
||||
details.PresentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, g->VulkanSurface, &presentModeCount, details.PresentModes.data());
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR device_choose_swap_surface_format(const std::vector<VkSurfaceFormatKHR>& availableFormats)
|
||||
{
|
||||
for (const auto& availableFormat : availableFormats) {
|
||||
if (
|
||||
availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||
return availableFormat;
|
||||
}
|
||||
}
|
||||
|
||||
return availableFormats[0];
|
||||
}
|
||||
|
||||
VkPresentModeKHR device_choose_swap_present_mode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
||||
{
|
||||
for (const auto& availablePresentMode : availablePresentModes) {
|
||||
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||
return availablePresentMode;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
VkExtent2D device_choose_swap_extent(const VkSurfaceCapabilitiesKHR& capabilities, int width, int height)
|
||||
{
|
||||
if (capabilities.currentExtent.width != UINT32_MAX) {
|
||||
return capabilities.currentExtent;
|
||||
} else {
|
||||
VkExtent2D actualExtent = { (uint32_t)width, (uint32_t)height };
|
||||
|
||||
actualExtent.width = std::max(
|
||||
capabilities.minImageExtent.width,
|
||||
std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||
|
||||
actualExtent.height = std::max(
|
||||
capabilities.minImageExtent.height,
|
||||
std::min(capabilities.maxImageExtent.height, actualExtent.height));
|
||||
|
||||
return actualExtent;
|
||||
}
|
||||
}
|
||||
|
||||
SwapChain* swapchain_create(GraphicsDevice* device, glm::ivec2 surface_size)
|
||||
{
|
||||
SwapChain* swapchain = new SwapChain();
|
||||
|
||||
SwapChainSupportDetails swapChainSupport = device_get_swapchain_support(device, device->VulkanPhysicalDevice);
|
||||
|
||||
VkSurfaceFormatKHR surfaceFormat = device_choose_swap_surface_format(swapChainSupport.Formats);
|
||||
VkPresentModeKHR presentMode = device_choose_swap_present_mode(swapChainSupport.PresentModes);
|
||||
VkExtent2D extent = device_choose_swap_extent(swapChainSupport.Capabilities, surface_size.x, surface_size.y);
|
||||
uint32_t imageCount = swapChainSupport.Capabilities.minImageCount + 1;
|
||||
|
||||
if (swapChainSupport.Capabilities.maxImageCount > 0 && imageCount > swapChainSupport.Capabilities.maxImageCount) {
|
||||
imageCount = swapChainSupport.Capabilities.maxImageCount;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
createInfo.surface = device->VulkanSurface;
|
||||
createInfo.minImageCount = imageCount;
|
||||
|
||||
createInfo.imageFormat = surfaceFormat.format;
|
||||
createInfo.imageColorSpace = surfaceFormat.colorSpace;
|
||||
createInfo.imageExtent = extent;
|
||||
createInfo.imageArrayLayers = 1;
|
||||
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
QueueFamilyIndices indices = device_get_queue_families(device, device->VulkanPhysicalDevice);
|
||||
uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
|
||||
|
||||
if (indices.graphicsFamily != indices.presentFamily) {
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
createInfo.queueFamilyIndexCount = 2;
|
||||
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
||||
} else {
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
createInfo.queueFamilyIndexCount = 0; // Optional
|
||||
createInfo.pQueueFamilyIndices = nullptr; // Optional
|
||||
}
|
||||
|
||||
createInfo.preTransform = swapChainSupport.Capabilities.currentTransform;
|
||||
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
createInfo.presentMode = presentMode;
|
||||
createInfo.clipped = VK_TRUE;
|
||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
if (vkCreateSwapchainKHR(device->VulkanDevice, &createInfo, nullptr, &swapchain->Handle) != VK_SUCCESS) {
|
||||
yolo::error("failed to create swap chain!");
|
||||
exit(1);
|
||||
}
|
||||
yolo::info("Swap chain created");
|
||||
|
||||
vkGetSwapchainImagesKHR(device->VulkanDevice, swapchain->Handle, &imageCount, nullptr);
|
||||
swapchain->Images.resize(imageCount);
|
||||
vkGetSwapchainImagesKHR(device->VulkanDevice, swapchain->Handle, &imageCount, swapchain->Images.data());
|
||||
|
||||
swapchain->ImageFormat = surfaceFormat.format;
|
||||
swapchain->Extent = extent;
|
||||
swapchain->Device = device;
|
||||
|
||||
return swapchain;
|
||||
}
|
||||
|
||||
void swapchain_cleanup(SwapChain* swapchain)
|
||||
{
|
||||
vkDestroySwapchainKHR(swapchain->Device->VulkanDevice, swapchain->Handle, nullptr);
|
||||
delete swapchain;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
|
||||
typedef struct SwapChain {
|
||||
VkSwapchainKHR Handle;
|
||||
VkFormat ImageFormat;
|
||||
VkExtent2D Extent;
|
||||
|
||||
std::vector<VkImage> Images;
|
||||
|
||||
GraphicsDevice* Device;
|
||||
} SwapChain;
|
||||
|
||||
SwapChain* swapchain_create(GraphicsDevice* device, glm::ivec2 surface_size);
|
||||
void swapchain_cleanup(SwapChain* swapchain);
|
||||
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ InfernoApp* inferno_create()
|
||||
|
||||
// Create window
|
||||
graphics::window_create("Inferno v" INFERNO_VERSION, 1920, 1080);
|
||||
graphics::GraphicsDevice* d = graphics::device_create();
|
||||
|
||||
graphics::GraphicsDevice* device = graphics::device_create();
|
||||
graphics::Pipeline* p = graphics::pipeline_create(device);
|
||||
|
||||
// // setup the scene
|
||||
// scene::Material* basicMaterial = new scene::Material("basic");
|
||||
|
||||
Reference in New Issue
Block a user