Replaced pointers with std::vectors, added a few comments, some code refactoring, Fixes #39

This commit is contained in:
saschawillems 2016-02-23 21:21:36 +01:00
parent 5979e31c56
commit fb41887c9d

View file

@ -1,5 +1,8 @@
/* /*
* Class wrapping access to the swap chain * Class wrapping access to the swap chain
*
* A swap chain is a collection of framebuffers used for rendering
* The swap chain images can then presented to the windowing system
* *
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de * Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
* *
@ -13,6 +16,7 @@
#include <fstream> #include <fstream>
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <vector>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <fcntl.h> #include <fcntl.h>
@ -72,17 +76,18 @@ private:
public: public:
VkFormat colorFormat; VkFormat colorFormat;
VkColorSpaceKHR colorSpace; VkColorSpaceKHR colorSpace;
VkImage* swapchainImages;
VkSwapchainKHR swapChain = VK_NULL_HANDLE; VkSwapchainKHR swapChain = VK_NULL_HANDLE;
uint32_t imageCount; uint32_t imageCount;
SwapChainBuffer* buffers; std::vector<VkImage> images;
std::vector<SwapChainBuffer> buffers;
// Index of the deteced graphics and presenting device queue // Index of the deteced graphics and presenting device queue
uint32_t queueNodeIndex = UINT32_MAX; uint32_t queueNodeIndex = UINT32_MAX;
// wip naming // Creates an os specific surface
// Tries to find a graphics and a present queue
void initSwapChain( void initSwapChain(
#ifdef _WIN32 #ifdef _WIN32
void* platformHandle, void* platformWindow void* platformHandle, void* platformWindow
@ -95,9 +100,6 @@ public:
#endif #endif
) )
{ {
uint32_t queueCount;
VkQueueFamilyProperties *queueProps;
VkResult err; VkResult err;
// Create surface depending on OS // Create surface depending on OS
@ -122,29 +124,28 @@ public:
#endif #endif
#endif #endif
uint32_t i; // Get available queue family properties
uint32_t queueCount;
// Get queue properties
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL);
queueProps = (VkQueueFamilyProperties *)malloc(queueCount * sizeof(VkQueueFamilyProperties));
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps);
assert(queueCount >= 1); assert(queueCount >= 1);
std::vector<VkQueueFamilyProperties> queueProps(queueCount);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data());
// Iterate over each queue to learn whether it supports presenting: // Iterate over each queue to learn whether it supports presenting:
VkBool32* supportsPresent = (VkBool32 *)malloc(queueCount * sizeof(VkBool32)); // Find a queue with present support
for (i = 0; i < queueCount; i++) // Will be used to present the swap chain images to the windowing system
std::vector<VkBool32> supportsPresent(queueCount);
for (uint32_t i = 0; i < queueCount; i++)
{ {
fpGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, fpGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &supportsPresent[i]);
surface,
&supportsPresent[i]);
} }
// Search for a graphics and a present queue in the array of queue // Search for a graphics and a present queue in the array of queue
// families, try to find one that supports both // families, try to find one that supports both
uint32_t graphicsQueueNodeIndex = UINT32_MAX; uint32_t graphicsQueueNodeIndex = UINT32_MAX;
uint32_t presentQueueNodeIndex = UINT32_MAX; uint32_t presentQueueNodeIndex = UINT32_MAX;
for (i = 0; i < queueCount; i++) for (uint32_t i = 0; i < queueCount; i++)
{ {
if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
{ {
@ -174,45 +175,49 @@ public:
} }
} }
} }
free(supportsPresent);
// Generate error if could not find both a graphics and a present queue // Exit if either a graphics or a presenting queue hasn't been found
if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX)
{ {
// todo : error message vkTools::exitFatal("Could not find a graphics and/or presenting queue!", "Fatal error");
} }
// todo : Add support for separate graphics and presenting queue
if (graphicsQueueNodeIndex != presentQueueNodeIndex) if (graphicsQueueNodeIndex != presentQueueNodeIndex)
{ {
// todo : error message vkTools::exitFatal("Separate graphics and presenting queues are not supported yet!", "Fatal error");
} }
queueNodeIndex = graphicsQueueNodeIndex; queueNodeIndex = graphicsQueueNodeIndex;
// Get list of supported formats // Get list of supported surface formats
uint32_t formatCount; uint32_t formatCount;
err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL); err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL);
assert(!err); assert(!err);
assert(formatCount > 0);
VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount);
err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfFormats); err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfaceFormats.data());
assert(!err); assert(!err);
// If the format list includes just one entry of VK_FORMAT_UNDEFINED, // If the surface format list only includes one entry with VK_FORMAT_UNDEFINED,
// the surface has no preferred format. Otherwise, at least one // there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM
// supported format will be returned. if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED))
if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
{ {
colorFormat = VK_FORMAT_B8G8R8A8_UNORM; colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
} }
else else
{ {
assert(formatCount >= 1); // Always select the first available color format
colorFormat = surfFormats[0].format; // If you need a specific format (e.g. SRGB) you'd need to
// iterate over the list of available surface format and
// check for it's presence
colorFormat = surfaceFormats[0].format;
} }
colorSpace = surfFormats[0].colorSpace; colorSpace = surfaceFormats[0].colorSpace;
} }
// Assign instance und device handles and get all required function pointers
void init(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device) void init(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device)
{ {
this->instance = instance; this->instance = instance;
@ -229,6 +234,7 @@ public:
GET_DEVICE_PROC_ADDR(device, QueuePresentKHR); GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
} }
// Create the swap chain images with given width and height
void setup(VkCommandBuffer cmdBuffer, uint32_t *width, uint32_t *height) void setup(VkCommandBuffer cmdBuffer, uint32_t *width, uint32_t *height)
{ {
VkResult err; VkResult err;
@ -239,14 +245,15 @@ public:
err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps); err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps);
assert(!err); assert(!err);
// Get available present modes
uint32_t presentModeCount; uint32_t presentModeCount;
err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL); err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL);
assert(!err); assert(!err);
assert(presentModeCount > 0);
// todo : replace with vector? std::vector<VkPresentModeKHR> presentModes(presentModeCount);
VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes); err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
assert(!err); assert(!err);
VkExtent2D swapchainExtent = {}; VkExtent2D swapchainExtent = {};
@ -266,8 +273,7 @@ public:
*height = surfCaps.currentExtent.height; *height = surfCaps.currentExtent.height;
} }
// Try to use mailbox mode // Prefer mailbox mode if present, it's the lowest latency non-tearing present mode
// Low latency and non-tearing
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
for (size_t i = 0; i < presentModeCount; i++) for (size_t i = 0; i < presentModeCount; i++)
{ {
@ -294,7 +300,8 @@ public:
{ {
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
} }
else { else
{
preTransform = surfCaps.currentTransform; preTransform = surfCaps.currentTransform;
} }
@ -320,10 +327,8 @@ public:
err = fpCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain); err = fpCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain);
assert(!err); assert(!err);
// If we just re-created an existing swapchain, we should destroy the old // If an existing sawp chain is re-created, destroy the old swap chain
// swapchain at this point. // This also cleans up all the presentable images
// Note: destroying the swapchain also cleans up all its associated
// presentable images once the platform is done with them.
if (oldSwapchain != VK_NULL_HANDLE) if (oldSwapchain != VK_NULL_HANDLE)
{ {
fpDestroySwapchainKHR(device, oldSwapchain, nullptr); fpDestroySwapchainKHR(device, oldSwapchain, nullptr);
@ -332,14 +337,13 @@ public:
err = fpGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL); err = fpGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL);
assert(!err); assert(!err);
swapchainImages = (VkImage*)malloc(imageCount * sizeof(VkImage)); // Get the swap chain images
assert(swapchainImages); images.resize(imageCount);
err = fpGetSwapchainImagesKHR(device, swapChain, &imageCount, swapchainImages); err = fpGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data());
assert(!err); assert(!err);
buffers = (SwapChainBuffer*)malloc(sizeof(SwapChainBuffer)*imageCount); // Get the swap chain buffers containing the image and imageview
assert(buffers); buffers.resize(imageCount);
//buffers.resize(imageCount);
for (uint32_t i = 0; i < imageCount; i++) for (uint32_t i = 0; i < imageCount; i++)
{ {
VkImageViewCreateInfo colorAttachmentView = {}; VkImageViewCreateInfo colorAttachmentView = {};
@ -360,7 +364,7 @@ public:
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
colorAttachmentView.flags = 0; colorAttachmentView.flags = 0;
buffers[i].image = swapchainImages[i]; buffers[i].image = images[i];
vkTools::setImageLayout( vkTools::setImageLayout(
cmdBuffer, cmdBuffer,