mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-19 05:52:11 +01:00
[vulkan] Implement new Vulkan presenter / swap chain
This commit is contained in:
parent
7096937c11
commit
979ccf23e3
@ -1,6 +1,7 @@
|
||||
vkcommon_src = files([
|
||||
'vulkan_loader.cpp',
|
||||
'vulkan_names.cpp',
|
||||
'vulkan_presenter.cpp',
|
||||
])
|
||||
|
||||
thread_dep = dependency('threads')
|
||||
|
389
src/vulkan/vulkan_presenter.cpp
Normal file
389
src/vulkan/vulkan_presenter.cpp
Normal file
@ -0,0 +1,389 @@
|
||||
#include "vulkan_presenter.h"
|
||||
|
||||
#include "../dxvk/dxvk_format.h"
|
||||
|
||||
namespace dxvk::vk {
|
||||
|
||||
Presenter::Presenter(
|
||||
HWND window,
|
||||
const Rc<InstanceFn>& vki,
|
||||
const Rc<DeviceFn>& vkd,
|
||||
PresenterDevice device,
|
||||
const PresenterDesc& desc)
|
||||
: m_vki(vki), m_vkd(vkd), m_device(device) {
|
||||
if (createSurface(window) != VK_SUCCESS)
|
||||
throw DxvkError("Failed to create surface");
|
||||
|
||||
if (recreateSwapChain(desc) != VK_SUCCESS)
|
||||
throw DxvkError("Failed to create swap chain");
|
||||
}
|
||||
|
||||
|
||||
Presenter::~Presenter() {
|
||||
destroySwapchain();
|
||||
destroySurface();
|
||||
}
|
||||
|
||||
|
||||
PresenterInfo Presenter::info() const {
|
||||
return m_info;
|
||||
}
|
||||
|
||||
|
||||
PresenterSync Presenter::getSyncSemaphores() const {
|
||||
return m_semaphores.at(m_frameIndex);
|
||||
}
|
||||
|
||||
|
||||
PresenterImage Presenter::getImage(uint32_t index) const {
|
||||
return m_images.at(index);
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::acquireNextImage(
|
||||
VkSemaphore signal,
|
||||
uint32_t& index) {
|
||||
VkResult status = m_vkd->vkAcquireNextImageKHR(
|
||||
m_vkd->device(), m_swapchain,
|
||||
std::numeric_limits<uint64_t>::max(),
|
||||
signal, VK_NULL_HANDLE, &m_imageIndex);
|
||||
|
||||
if (status != VK_SUCCESS
|
||||
&& status != VK_SUBOPTIMAL_KHR)
|
||||
return status;
|
||||
|
||||
m_frameIndex += 1;
|
||||
m_frameIndex %= m_semaphores.size();
|
||||
|
||||
index = m_imageIndex;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::presentImage(VkSemaphore wait) {
|
||||
VkPresentInfoKHR info;
|
||||
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
info.pNext = nullptr;
|
||||
info.waitSemaphoreCount = 1;
|
||||
info.pWaitSemaphores = &wait;
|
||||
info.swapchainCount = 1;
|
||||
info.pSwapchains = &m_swapchain;
|
||||
info.pImageIndices = &m_imageIndex;
|
||||
info.pResults = nullptr;
|
||||
|
||||
return m_vkd->vkQueuePresentKHR(m_device.queue, &info);
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::recreateSwapChain(const PresenterDesc& desc) {
|
||||
if (m_swapchain)
|
||||
destroySwapchain();
|
||||
|
||||
// Query surface capabilities. Some properties might
|
||||
// have changed, including the size limits and supported
|
||||
// present modes, so we'll just query everything again.
|
||||
VkSurfaceCapabilitiesKHR caps;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> modes;
|
||||
|
||||
VkResult status;
|
||||
|
||||
if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||
m_device.adapter, m_surface, &caps)) != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
if ((status = getSupportedFormats(formats)) != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
if ((status = getSupportedPresentModes(modes)) != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
// Select actual swap chain properties and create swap chain
|
||||
m_info.format = pickFormat(formats.size(), formats.data(), desc.numFormats, desc.formats);
|
||||
m_info.presentMode = pickPresentMode(modes.size(), modes.data(), desc.numPresentModes, desc.presentModes);
|
||||
m_info.imageExtent = pickImageExtent(caps, desc.imageExtent);
|
||||
m_info.imageCount = pickImageCount(caps, m_info.presentMode, desc.imageCount);
|
||||
|
||||
VkSwapchainCreateInfoKHR swapInfo;
|
||||
swapInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
swapInfo.pNext = nullptr;
|
||||
swapInfo.flags = 0;
|
||||
swapInfo.surface = m_surface;
|
||||
swapInfo.minImageCount = m_info.imageCount;
|
||||
swapInfo.imageFormat = m_info.format.format;
|
||||
swapInfo.imageColorSpace = m_info.format.colorSpace;
|
||||
swapInfo.imageExtent = m_info.imageExtent;
|
||||
swapInfo.imageArrayLayers = 1;
|
||||
swapInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
swapInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapInfo.queueFamilyIndexCount = 0;
|
||||
swapInfo.pQueueFamilyIndices = nullptr;
|
||||
swapInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
swapInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
swapInfo.presentMode = m_info.presentMode;
|
||||
swapInfo.clipped = VK_TRUE;
|
||||
swapInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
Logger::info(str::format(
|
||||
"Presenter: Actual swap chain properties:"
|
||||
"\n Format: ", m_info.format.format,
|
||||
"\n Present mode: ", m_info.presentMode,
|
||||
"\n Buffer size: ", m_info.imageExtent.width, "x", m_info.imageExtent.height,
|
||||
"\n Image count: ", m_info.imageCount));
|
||||
|
||||
if ((status = m_vkd->vkCreateSwapchainKHR(m_vkd->device(),
|
||||
&swapInfo, nullptr, &m_swapchain)) != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
// Acquire images and create views
|
||||
std::vector<VkImage> images;
|
||||
|
||||
if ((status = getSwapImages(images)) != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
// Update actual image count
|
||||
m_info.imageCount = images.size();
|
||||
m_images.resize(m_info.imageCount);
|
||||
|
||||
for (uint32_t i = 0; i < m_info.imageCount; i++) {
|
||||
m_images[i].image = images[i];
|
||||
|
||||
VkImageViewCreateInfo viewInfo;
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.pNext = nullptr;
|
||||
viewInfo.flags = 0;
|
||||
viewInfo.image = images[i];
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = m_info.format.format;
|
||||
viewInfo.components = VkComponentMapping {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
|
||||
viewInfo.subresourceRange = {
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
0, 1, 0, 1 };
|
||||
|
||||
if ((status = m_vkd->vkCreateImageView(m_vkd->device(),
|
||||
&viewInfo, nullptr, &m_images[i].view)) != VK_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
// Create one set of semaphores per swap image
|
||||
m_semaphores.resize(m_info.imageCount);
|
||||
|
||||
for (uint32_t i = 0; i < m_info.imageCount; i++) {
|
||||
VkSemaphoreCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
|
||||
if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
|
||||
&info, nullptr, &m_semaphores[i].acquire)) != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
|
||||
&info, nullptr, &m_semaphores[i].present)) != VK_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
// Invalidate indices
|
||||
m_imageIndex = 0;
|
||||
m_frameIndex = 0;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::getSupportedFormats(std::vector<VkSurfaceFormatKHR>& formats) {
|
||||
uint32_t numFormats = 0;
|
||||
|
||||
VkResult status = m_vki->vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||
m_device.adapter, m_surface, &numFormats, nullptr);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
formats.resize(numFormats);
|
||||
|
||||
return m_vki->vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||
m_device.adapter, m_surface, &numFormats, formats.data());
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::getSupportedPresentModes(std::vector<VkPresentModeKHR>& modes) {
|
||||
uint32_t numModes = 0;
|
||||
|
||||
VkResult status = m_vki->vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
m_device.adapter, m_surface, &numModes, nullptr);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
modes.resize(numModes);
|
||||
|
||||
return m_vki->vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
m_device.adapter, m_surface, &numModes, modes.data());
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::getSwapImages(std::vector<VkImage>& images) {
|
||||
uint32_t imageCount = 0;
|
||||
|
||||
VkResult status = m_vkd->vkGetSwapchainImagesKHR(
|
||||
m_vkd->device(), m_swapchain, &imageCount, nullptr);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
images.resize(imageCount);
|
||||
|
||||
return m_vkd->vkGetSwapchainImagesKHR(
|
||||
m_vkd->device(), m_swapchain, &imageCount, images.data());
|
||||
}
|
||||
|
||||
|
||||
VkSurfaceFormatKHR Presenter::pickFormat(
|
||||
uint32_t numSupported,
|
||||
const VkSurfaceFormatKHR* pSupported,
|
||||
uint32_t numDesired,
|
||||
const VkSurfaceFormatKHR* pDesired) {
|
||||
if (numDesired > 0) {
|
||||
// If the implementation allows us to freely choose
|
||||
// the format, we'll just use the preferred format.
|
||||
if (numSupported == 1 && pSupported[0].format == VK_FORMAT_UNDEFINED)
|
||||
return pDesired[0];
|
||||
|
||||
// If the preferred format is explicitly listed in
|
||||
// the array of supported surface formats, use it
|
||||
for (uint32_t i = 0; i < numDesired; i++) {
|
||||
for (uint32_t j = 0; j < numSupported; j++) {
|
||||
if (pSupported[j].format == pDesired[i].format
|
||||
&& pSupported[j].colorSpace == pDesired[i].colorSpace)
|
||||
return pSupported[j];
|
||||
}
|
||||
}
|
||||
|
||||
// If that didn't work, we'll fall back to a format
|
||||
// which has similar properties to the preferred one
|
||||
DxvkFormatFlags prefFlags = imageFormatInfo(pDesired[0].format)->flags;
|
||||
|
||||
for (uint32_t j = 0; j < numSupported; j++) {
|
||||
auto currFlags = imageFormatInfo(pSupported[j].format)->flags;
|
||||
|
||||
if ((currFlags & DxvkFormatFlag::ColorSpaceSrgb)
|
||||
== (prefFlags & DxvkFormatFlag::ColorSpaceSrgb))
|
||||
return pSupported[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, fall back to the first supported format
|
||||
return pSupported[0];
|
||||
}
|
||||
|
||||
|
||||
VkPresentModeKHR Presenter::pickPresentMode(
|
||||
uint32_t numSupported,
|
||||
const VkPresentModeKHR* pSupported,
|
||||
uint32_t numDesired,
|
||||
const VkPresentModeKHR* pDesired) {
|
||||
// Just pick the first desired and supported mode
|
||||
for (uint32_t i = 0; i < numDesired; i++) {
|
||||
for (uint32_t j = 0; j < numSupported; j++) {
|
||||
if (pSupported[j] == pDesired[i])
|
||||
return pSupported[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Guaranteed to be available
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
|
||||
VkExtent2D Presenter::pickImageExtent(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkExtent2D desired) {
|
||||
if (caps.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
||||
return caps.currentExtent;
|
||||
|
||||
VkExtent2D actual;
|
||||
actual.width = clamp(desired.width, caps.minImageExtent.width, caps.maxImageExtent.width);
|
||||
actual.height = clamp(desired.height, caps.minImageExtent.height, caps.maxImageExtent.height);
|
||||
return actual;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Presenter::pickImageCount(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkPresentModeKHR presentMode,
|
||||
uint32_t desired) {
|
||||
uint32_t count = caps.minImageCount;
|
||||
|
||||
if (presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR)
|
||||
count = caps.minImageCount + 1;
|
||||
|
||||
if (count < desired)
|
||||
count = desired;
|
||||
|
||||
if (count > caps.maxImageCount && caps.maxImageCount != 0)
|
||||
count = caps.maxImageCount;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::createSurface(HWND window) {
|
||||
HINSTANCE instance = reinterpret_cast<HINSTANCE>(
|
||||
GetWindowLongPtr(window, GWLP_HINSTANCE));
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR info;
|
||||
info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.hinstance = instance;
|
||||
info.hwnd = window;
|
||||
|
||||
VkResult status = m_vki->vkCreateWin32SurfaceKHR(
|
||||
m_vki->instance(), &info, nullptr, &m_surface);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
VkBool32 supportStatus = VK_FALSE;
|
||||
|
||||
if ((status = m_vki->vkGetPhysicalDeviceSurfaceSupportKHR(m_device.adapter,
|
||||
m_device.queueFamily, m_surface, &supportStatus)) != VK_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (!supportStatus) {
|
||||
m_vki->vkDestroySurfaceKHR(m_vki->instance(), m_surface, nullptr);
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY; // just abuse this
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void Presenter::destroySwapchain() {
|
||||
m_vkd->vkDeviceWaitIdle(m_vkd->device());
|
||||
|
||||
for (const auto& img : m_images)
|
||||
m_vkd->vkDestroyImageView(m_vkd->device(), img.view, nullptr);
|
||||
|
||||
for (const auto& sem : m_semaphores) {
|
||||
m_vkd->vkDestroySemaphore(m_vkd->device(), sem.acquire, nullptr);
|
||||
m_vkd->vkDestroySemaphore(m_vkd->device(), sem.present, nullptr);
|
||||
}
|
||||
|
||||
m_vkd->vkDestroySwapchainKHR(m_vkd->device(), m_swapchain, nullptr);
|
||||
|
||||
m_images.clear();
|
||||
m_semaphores.clear();
|
||||
|
||||
m_swapchain = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
void Presenter::destroySurface() {
|
||||
m_vki->vkDestroySurfaceKHR(m_vki->instance(), m_surface, nullptr);
|
||||
}
|
||||
|
||||
}
|
209
src/vulkan/vulkan_presenter.h
Normal file
209
src/vulkan/vulkan_presenter.h
Normal file
@ -0,0 +1,209 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../util/log/log.h"
|
||||
|
||||
#include "../util/util_error.h"
|
||||
#include "../util/util_math.h"
|
||||
#include "../util/util_string.h"
|
||||
|
||||
#include "vulkan_loader.h"
|
||||
|
||||
namespace dxvk::vk {
|
||||
|
||||
/**
|
||||
* \brief Presenter description
|
||||
*
|
||||
* Contains the desired properties of
|
||||
* the swap chain. This is passed as
|
||||
* an input during swap chain creation.
|
||||
*/
|
||||
struct PresenterDesc {
|
||||
VkExtent2D imageExtent;
|
||||
uint32_t imageCount;
|
||||
uint32_t numFormats;
|
||||
VkSurfaceFormatKHR formats[4];
|
||||
uint32_t numPresentModes;
|
||||
VkPresentModeKHR presentModes[4];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Presenter properties
|
||||
*
|
||||
* Contains the actual properties
|
||||
* of the underlying swap chain.
|
||||
*/
|
||||
struct PresenterInfo {
|
||||
VkSurfaceFormatKHR format;
|
||||
VkPresentModeKHR presentMode;
|
||||
VkExtent2D imageExtent;
|
||||
uint32_t imageCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Adapter and queue
|
||||
*/
|
||||
struct PresenterDevice {
|
||||
uint32_t queueFamily = 0;
|
||||
VkQueue queue = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice adapter = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Swap image and view
|
||||
*/
|
||||
struct PresenterImage {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Presenter semaphores
|
||||
*
|
||||
* Pair of semaphores used for acquire
|
||||
* and present operations, including
|
||||
* the command buffers used in between.
|
||||
*/
|
||||
struct PresenterSync {
|
||||
VkSemaphore acquire;
|
||||
VkSemaphore present;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Vulkan presenter
|
||||
*
|
||||
* Provides abstractions for some of the
|
||||
* more complicated aspects of Vulkan's
|
||||
* window system integration.
|
||||
*/
|
||||
class Presenter : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
Presenter(
|
||||
HWND window,
|
||||
const Rc<InstanceFn>& vki,
|
||||
const Rc<DeviceFn>& vkd,
|
||||
PresenterDevice device,
|
||||
const PresenterDesc& desc);
|
||||
|
||||
~Presenter();
|
||||
|
||||
/**
|
||||
* \brief Actual presenter info
|
||||
* \returns Swap chain properties
|
||||
*/
|
||||
PresenterInfo info() const;
|
||||
|
||||
/**
|
||||
* \breif Retrieves a pair of semaphores
|
||||
*
|
||||
* These semaphores are meant to be used
|
||||
* for acquire and present operations.
|
||||
* \returns Pair of semaphores
|
||||
*/
|
||||
PresenterSync getSyncSemaphores() const;
|
||||
|
||||
/**
|
||||
* \brief Retrieves image by index
|
||||
*
|
||||
* Can be used to create per-image objects.
|
||||
* \param [in] index Image index
|
||||
* \returns Image handle
|
||||
*/
|
||||
PresenterImage getImage(
|
||||
uint32_t index) const;
|
||||
|
||||
/**
|
||||
* \brief Acquires next image
|
||||
*
|
||||
* Potentially blocks the calling thread.
|
||||
* If this returns an error, the swap chain
|
||||
* must be recreated and a new image must
|
||||
* be acquired before proceeding.
|
||||
* \param [in] signal Semaphore to signal
|
||||
* \param [out] index Acquired image index
|
||||
* \returns Status of the operation
|
||||
*/
|
||||
VkResult acquireNextImage(
|
||||
VkSemaphore signal,
|
||||
uint32_t& index);
|
||||
|
||||
/**
|
||||
* \brief Presents current image
|
||||
*
|
||||
* Presents the current image. If this returns
|
||||
* an error, the swap chain must be recreated,
|
||||
* but do not present before acquiring an image.
|
||||
* \param [in] wait Semaphore to wait on
|
||||
* \returns Status of the operation
|
||||
*/
|
||||
VkResult presentImage(
|
||||
VkSemaphore wait);
|
||||
|
||||
/**
|
||||
* \brief Changes presenter properties
|
||||
*
|
||||
* Recreates the swap chain immediately.
|
||||
* \param [in] desc Swap chain description
|
||||
*/
|
||||
VkResult recreateSwapChain(
|
||||
const PresenterDesc& desc);
|
||||
|
||||
private:
|
||||
|
||||
Rc<InstanceFn> m_vki;
|
||||
Rc<DeviceFn> m_vkd;
|
||||
|
||||
PresenterDevice m_device;
|
||||
PresenterInfo m_info;
|
||||
|
||||
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<PresenterImage> m_images;
|
||||
std::vector<PresenterSync> m_semaphores;
|
||||
|
||||
uint32_t m_imageIndex = 0;
|
||||
uint32_t m_frameIndex = 0;
|
||||
|
||||
VkResult getSupportedFormats(
|
||||
std::vector<VkSurfaceFormatKHR>& formats);
|
||||
|
||||
VkResult getSupportedPresentModes(
|
||||
std::vector<VkPresentModeKHR>& modes);
|
||||
|
||||
VkResult getSwapImages(
|
||||
std::vector<VkImage>& images);
|
||||
|
||||
VkSurfaceFormatKHR pickFormat(
|
||||
uint32_t numSupported,
|
||||
const VkSurfaceFormatKHR* pSupported,
|
||||
uint32_t numDesired,
|
||||
const VkSurfaceFormatKHR* pDesired);
|
||||
|
||||
VkPresentModeKHR pickPresentMode(
|
||||
uint32_t numSupported,
|
||||
const VkPresentModeKHR* pSupported,
|
||||
uint32_t numDesired,
|
||||
const VkPresentModeKHR* pDesired);
|
||||
|
||||
VkExtent2D pickImageExtent(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkExtent2D desired);
|
||||
|
||||
uint32_t pickImageCount(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkPresentModeKHR presentMode,
|
||||
uint32_t desired);
|
||||
|
||||
VkResult createSurface(HWND window);
|
||||
|
||||
void destroySwapchain();
|
||||
|
||||
void destroySurface();
|
||||
|
||||
};
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user