mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-30 16:10:53 +00:00
200 lines
5.8 KiB
C
200 lines
5.8 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_MATH_H
|
|
# include <math.h>
|
|
#endif
|
|
|
|
#include "QF/cvar.h"
|
|
#include "QF/mathlib.h"
|
|
#include "QF/sys.h"
|
|
#include "QF/Vulkan/qf_vid.h"
|
|
#include "QF/Vulkan/cvars.h"
|
|
#include "QF/Vulkan/command.h"
|
|
#include "QF/Vulkan/device.h"
|
|
#include "QF/Vulkan/image.h"
|
|
#include "QF/Vulkan/instance.h"
|
|
#include "QF/Vulkan/swapchain.h"
|
|
|
|
#include "compat.h"
|
|
#include "d_iface.h"
|
|
#include "r_internal.h"
|
|
#include "vid_vulkan.h"
|
|
|
|
#include "util.h"
|
|
|
|
qfv_swapchain_t *
|
|
QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain)
|
|
{
|
|
qfv_instfuncs_t *ifuncs = ctx->instance->funcs;
|
|
qfv_devfuncs_t *dfuncs = ctx->device->funcs;
|
|
qfv_queue_t *queue = &ctx->device->queue;
|
|
VkPhysicalDevice physDev = ctx->device->physDev->dev;
|
|
|
|
VkBool32 supported;
|
|
ifuncs->vkGetPhysicalDeviceSurfaceSupportKHR (physDev,
|
|
queue->queueFamily,
|
|
ctx->surface,
|
|
&supported);
|
|
if (!supported) {
|
|
Sys_Error ("unsupported surface for swapchain");
|
|
}
|
|
|
|
uint32_t numModes;
|
|
VkPresentModeKHR *modes;
|
|
VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;
|
|
ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (physDev,
|
|
ctx->surface,
|
|
&numModes, 0);
|
|
modes = alloca (numModes * sizeof (VkPresentModeKHR));
|
|
ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (physDev,
|
|
ctx->surface,
|
|
&numModes, modes);
|
|
for (uint32_t i = 0; i < numModes; i++) {
|
|
if ((int) modes[i] == vulkan_presentation_mode->int_val) {
|
|
useMode = modes[i];
|
|
}
|
|
}
|
|
Sys_MaskPrintf (SYS_VULKAN, "presentation mode: %d (%d)\n", useMode,
|
|
vulkan_presentation_mode->int_val);
|
|
|
|
VkSurfaceCapabilitiesKHR surfCaps;
|
|
ifuncs->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (physDev,
|
|
ctx->surface,
|
|
&surfCaps);
|
|
uint32_t numImages = surfCaps.minImageCount + 1;
|
|
if (surfCaps.maxImageCount > 0 && numImages > surfCaps.maxImageCount) {
|
|
numImages = surfCaps.maxImageCount;
|
|
}
|
|
|
|
VkExtent2D imageSize = {viddef.width, viddef.height};
|
|
if (surfCaps.currentExtent.width == ~0u) {
|
|
imageSize.width = bound (surfCaps.minImageExtent.width,
|
|
imageSize.width,
|
|
surfCaps.maxImageExtent.width);
|
|
imageSize.height = bound (surfCaps.minImageExtent.height,
|
|
imageSize.height,
|
|
surfCaps.maxImageExtent.height);
|
|
} else {
|
|
imageSize = surfCaps.currentExtent;
|
|
}
|
|
Sys_MaskPrintf (SYS_VULKAN, "%d [%d, %d]\n", numImages,
|
|
imageSize.width, imageSize.height);
|
|
|
|
VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
imageUsage &= surfCaps.supportedUsageFlags;
|
|
|
|
VkSurfaceTransformFlagBitsKHR surfTransform
|
|
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
|
|
|
uint32_t numFormats;
|
|
ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (physDev,
|
|
ctx->surface,
|
|
&numFormats, 0);
|
|
VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats));
|
|
ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (physDev,
|
|
ctx->surface,
|
|
&numFormats, formats);
|
|
VkSurfaceFormatKHR useFormat = {VK_FORMAT_R8G8B8A8_UNORM,
|
|
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
|
|
if (numFormats > 1) {
|
|
uint32_t i;
|
|
for (i = 0; i < numFormats; i++) {
|
|
if (formats[i].format == useFormat.format
|
|
&& formats[i].colorSpace == useFormat.colorSpace) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == numFormats) {
|
|
useFormat = formats[0];
|
|
}
|
|
} else if (numFormats == 1 && formats[0].format != VK_FORMAT_UNDEFINED) {
|
|
useFormat = formats[0];
|
|
}
|
|
|
|
VkSwapchainCreateInfoKHR createInfo = {
|
|
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 0, 0,
|
|
ctx->surface,
|
|
numImages,
|
|
useFormat.format, useFormat.colorSpace,
|
|
imageSize,
|
|
1, // array layers
|
|
imageUsage,
|
|
VK_SHARING_MODE_EXCLUSIVE,
|
|
0, 0,
|
|
surfTransform,
|
|
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
|
useMode,
|
|
VK_TRUE,
|
|
old_swapchain
|
|
};
|
|
|
|
VkDevice dev = ctx->device->dev;
|
|
VkSwapchainKHR swapchain;
|
|
dfuncs->vkCreateSwapchainKHR (dev, &createInfo, 0, &swapchain);
|
|
|
|
if (old_swapchain != swapchain) {
|
|
dfuncs->vkDestroySwapchainKHR (dev, old_swapchain, 0);
|
|
}
|
|
|
|
dfuncs->vkGetSwapchainImagesKHR (dev, swapchain, &numImages, 0);
|
|
qfv_swapchain_t *sc = malloc (sizeof (qfv_swapchain_t));
|
|
sc->device = ctx->device;
|
|
sc->surface = ctx->surface;
|
|
sc->swapchain = swapchain;
|
|
sc->format = useFormat.format;
|
|
sc->extent = imageSize;
|
|
sc->numImages = numImages;
|
|
sc->images = DARRAY_ALLOCFIXED (qfv_imageset_t, numImages, malloc);
|
|
sc->imageViews = DARRAY_ALLOCFIXED (qfv_imageviewset_t, numImages, malloc);
|
|
dfuncs->vkGetSwapchainImagesKHR (dev, swapchain, &numImages, sc->images->a);
|
|
for (uint32_t i = 0; i < numImages; i++) {
|
|
sc->imageViews->a[i]
|
|
= QFV_CreateImageView (ctx->device, sc->images->a[i],
|
|
VK_IMAGE_VIEW_TYPE_2D, sc->format,
|
|
VK_IMAGE_ASPECT_COLOR_BIT);
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
void
|
|
QFV_DestroySwapchain (qfv_swapchain_t *swapchain)
|
|
{
|
|
qfv_device_t *device = swapchain->device;
|
|
VkDevice dev = device->dev;
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
|
for (size_t i = 0; i < swapchain->imageViews->size; i++) {
|
|
dfunc->vkDestroyImageView (dev, swapchain->imageViews->a[i], 0);
|
|
}
|
|
free (swapchain->images);
|
|
free (swapchain->imageViews);
|
|
dfunc->vkDestroySwapchainKHR (dev, swapchain->swapchain, 0);
|
|
free (swapchain);
|
|
}
|
|
|
|
int
|
|
QFV_AcquireNextImage (qfv_swapchain_t *swapchain, VkSemaphore semaphore,
|
|
VkFence fence, uint32_t *imageIndex)
|
|
{
|
|
qfv_device_t *device = swapchain->device;
|
|
VkDevice dev = device->dev;
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
|
uint64_t timeout = 2000000000;
|
|
*imageIndex = ~0u;
|
|
VkResult res = dfunc->vkAcquireNextImageKHR (dev, swapchain->swapchain,
|
|
timeout, semaphore, fence,
|
|
imageIndex);
|
|
switch (res) {
|
|
case VK_SUCCESS:
|
|
case VK_TIMEOUT:
|
|
case VK_NOT_READY:
|
|
return 1;
|
|
case VK_SUBOPTIMAL_KHR:
|
|
case VK_ERROR_OUT_OF_DATE_KHR:
|
|
return 0;
|
|
default:
|
|
Sys_Error ("vkAcquireNextImageKHR failed: %d", res);
|
|
}
|
|
}
|