src/ngfx/porting/vulkan/VKSwapchain.cpp
Attributes
Name | |
---|---|
const VkPresentModeKHR | PREFERRED_PRESENT_MODE |
Attributes Documentation
variable PREFERRED_PRESENT_MODE
static const VkPresentModeKHR PREFERRED_PRESENT_MODE =
VK_PRESENT_MODE_MAILBOX_KHR;
Source code
/*
* Copyright 2020 GoPro Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "ngfx/porting/vulkan/VKSwapchain.h"
#include "ngfx/core/Util.h"
#include "ngfx/graphics/Config.h"
#include "ngfx/porting/vulkan/VKDebugUtil.h"
#include "ngfx/porting/vulkan/VKDevice.h"
#include "ngfx/porting/vulkan/VKGraphicsContext.h"
#include "ngfx/porting/vulkan/VKSemaphore.h"
using namespace ngfx;
#ifdef ENABLE_VSYNC
static const VkPresentModeKHR PREFERRED_PRESENT_MODE = VK_PRESENT_MODE_FIFO_KHR;
#else
static const VkPresentModeKHR PREFERRED_PRESENT_MODE =
VK_PRESENT_MODE_MAILBOX_KHR;
#endif
void VKSwapchain::chooseNumSwapchainImages() {
numImages = PREFERRED_NUM_SWAPCHAIN_IMAGES;
if ((surfaceCaps.maxImageCount > 0) &&
(numImages > surfaceCaps.maxImageCount)) {
numImages = surfaceCaps.maxImageCount;
}
}
void VKSwapchain::chooseSurfaceFormat() {
for (auto &fmt : surfaceFormats) {
if (fmt.format == VK_FORMAT_B8G8R8A8_UNORM &&
fmt.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
surfaceFormat = fmt;
return;
}
}
surfaceFormat = surfaceFormats[0];
}
void VKSwapchain::getSurfaceCapabilities(VkPhysicalDevice physicalDevice) {
VkResult vkResult;
V(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface->v,
&surfaceCaps));
}
void VKSwapchain::getSurfaceFormats(VkPhysicalDevice physicalDevice) {
VkResult vkResult;
uint32_t surfaceFormatCount;
V(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface->v,
&surfaceFormatCount, nullptr));
assert(surfaceFormatCount > 0);
surfaceFormats.resize(surfaceFormatCount);
V(vkGetPhysicalDeviceSurfaceFormatsKHR(
physicalDevice, surface->v, &surfaceFormatCount, surfaceFormats.data()));
}
void VKSwapchain::choosePresentMode() {
if (!Util::contains(presentModes, PREFERRED_PRESENT_MODE)) {
NGFX_ERR("present mode: %d not supported", PREFERRED_PRESENT_MODE);
} else
presentMode = PREFERRED_PRESENT_MODE;
}
void VKSwapchain::getPresentModes(VkPhysicalDevice physicalDevice) {
VkResult vkResult;
uint32_t presentModeCount;
V(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface->v,
&presentModeCount, nullptr));
assert(presentModeCount > 0);
presentModes.resize(presentModeCount);
V(vkGetPhysicalDeviceSurfacePresentModesKHR(
physicalDevice, surface->v, &presentModeCount, presentModes.data()));
}
void VKSwapchain::chooseCompositeAlphaMode() {
// Choose the first composite alpha format available
std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
};
for (auto &compositeAlphaFlag : compositeAlphaFlags) {
if (surfaceCaps.supportedCompositeAlpha & compositeAlphaFlag) {
compositeAlpha = compositeAlphaFlag;
break;
};
}
}
void VKSwapchain::choosePreTransform() {
if (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
} else {
preTransform = surfaceCaps.currentTransform;
}
}
void VKSwapchain::createSwapchain(const VKDevice &vkDevice, uint32_t w,
uint32_t h) {
VkResult vkResult;
createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.surface = surface->v;
createInfo.minImageCount = numImages;
createInfo.imageFormat = surfaceFormat.format;
createInfo.imageColorSpace = surfaceFormat.colorSpace;
createInfo.imageExtent = surfaceCaps.currentExtent;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
createInfo.imageArrayLayers = 1;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = NULL;
createInfo.presentMode = presentMode;
createInfo.oldSwapchain = VK_NULL_HANDLE;
// Setting clipped to VK_TRUE allows the implementation to discard rendering
// outside of the surface area
createInfo.clipped = VK_TRUE;
createInfo.compositeAlpha = compositeAlpha;
// Enable transfer source on swap chain images if supported
if (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
// Enable transfer destination on swap chain images if supported
if (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
V(vkCreateSwapchainKHR(vkDevice.v, &createInfo, nullptr, &v))
}
void VKSwapchain::getSwapchainImages(VkDevice device) {
VkResult vkResult;
uint32_t imageCount;
V(vkGetSwapchainImagesKHR(device, v, &imageCount, NULL));
images.resize(imageCount);
V(vkGetSwapchainImagesKHR(device, v, &imageCount, images.data()));
}
void VKSwapchain::getQueueFamilyProperties(
const VKPhysicalDevice &vkPhysicalDevice) {
VkResult vkResult;
uint32_t queueFamilyCount =
uint32_t(vkPhysicalDevice.queueFamilyProperties.size());
queueFamilyProperties.resize(queueFamilyCount);
auto physicalDevice = vkPhysicalDevice.v;
for (uint32_t queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount;
queueFamilyIndex++) {
auto &queueFamilyProps = queueFamilyProperties[queueFamilyIndex];
V(vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex,
surface->v,
&queueFamilyProps.supportsPresent));
}
}
void VKSwapchain::createSwapchainImageViews(const VKDevice &vkDevice) {
uint32_t imageCount = uint32_t(images.size());
imageViews.resize(imageCount);
for (uint32_t i = 0; i < imageCount; i++) {
auto &imageView = imageViews[i];
imageView.create(vkDevice.v, images[i], VK_IMAGE_VIEW_TYPE_2D,
surfaceFormat.format);
}
}
VKSwapchain::VKSwapchain(VKGraphicsContext *ctx, VKSurface *surface) {
this->ctx = ctx;
auto &vkDevice = ctx->vkDevice;
this->device = vkDevice.v;
this->surface = surface;
chooseNumSwapchainImages();
auto physicalDevice = vkDevice.vkPhysicalDevice->v;
getSurfaceCapabilities(physicalDevice);
getSurfaceFormats(physicalDevice);
getPresentModes(physicalDevice);
getQueueFamilyProperties(*vkDevice.vkPhysicalDevice);
assert(queueFamilyProperties[vkDevice.queueFamilyIndices.graphics]
.supportsPresent);
chooseSurfaceFormat();
choosePresentMode();
chooseCompositeAlphaMode();
choosePreTransform();
createSwapchain(vkDevice, surface->w, surface->h);
getSwapchainImages(vkDevice.v);
createSwapchainImageViews(vkDevice);
}
VKSwapchain::~VKSwapchain() {
if (v)
VK_TRACE(vkDestroySwapchainKHR(device, v, nullptr));
surface->destroy();
};
void VKSwapchain::acquireNextImage() {
VkResult vkResult;
Semaphore *semaphore = ctx->presentCompleteSemaphore;
uint32_t *imageIndex = &ctx->currentImageIndex;
V(vkAcquireNextImageKHR(device, v, UINT64_MAX, vk(semaphore)->v,
VK_NULL_HANDLE, imageIndex));
auto waitFence = ctx->frameFences[ctx->currentImageIndex];
waitFence->wait();
waitFence->reset();
}
Updated on 3 April 2021 at 20:21:52 PDT