[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kwin/fredrik/vulkan] libkwineffects: Add libkwinvulkanutils
From: Fredrik_Höglund <null () kde ! org>
Date: 2018-02-16 17:01:48
Message-ID: E1emjOO-0004Yx-AR () code ! kde ! org
[Download RAW message or body]
Git commit a39b24ec410ab7f066b159d0cf6d2f42329495ff by Fredrik Höglund.
Committed on 16/02/2018 at 16:57.
Pushed by fredrik into branch 'fredrik/vulkan'.
Add libkwinvulkanutils
This library provides C++ wrappers for a number of Vulkan objects.
The main point of these wrappers is to have objects that know how to
delete themselves, and that also inherit from a common base class that
has a virtual destructor. The wrappers also provide type safety on
32-bit platforms, where non-dispatchable Vulkan handles are typedefs
of uint64_t.
These objects can be made refcounted by wrapping them in an
std::shared_ptr. This allows each frame to hold a list of references
to busy objects.
In addition to the above mentioned wrappers, the library also provides
a set of utilty classes. These include UploadManager, which is used
for uploading vertices and uniforms; and PipelineManager, which creates
and manages the core graphics pipelines and associated layouts.
M +21 -0 libkwineffects/CMakeLists.txt
A +1835 -0 libkwineffects/kwinvulkanutils.cpp [License: GPL (v2)]
A +3528 -0 libkwineffects/kwinvulkanutils.h [License: GPL (v2)]
A +200 -0 libkwineffects/kwinvulkanutils_funcs.cpp [License: GPL (v2)]
A +123 -0 libkwineffects/kwinvulkanutils_funcs.h [License: GPL (v2)]
M +1 -0 libkwineffects/logging.cpp
M +1 -0 libkwineffects/logging_p.h
https://commits.kde.org/kwin/a39b24ec410ab7f066b159d0cf6d2f42329495ff
diff --git a/libkwineffects/CMakeLists.txt b/libkwineffects/CMakeLists.txt
index 97717197d..4d8815713 100644
--- a/libkwineffects/CMakeLists.txt
+++ b/libkwineffects/CMakeLists.txt
@@ -104,6 +104,25 @@ set_target_properties(kwinglutils PROPERTIES OUTPUT_NAME \
${KWIN_NAME}glutils)
target_link_libraries(kwinglutils PUBLIC ${epoxy_LIBRARY})
+if (Vulkan_FOUND)
+ set(kwin_VULKANUTILSLIB_SRCS
+ kwinvulkanutils.cpp
+ kwinvulkanutils_funcs.cpp
+ logging.cpp
+ )
+
+ add_library(kwinvulkanutils SHARED ${kwin_VULKANUTILSLIB_SRCS})
+ generate_export_header(kwinvulkanutils BASE_NAME kwinvulkanutils \
EXPORT_FILE_NAME kwinvulkanutils_export.h) + set_target_properties(kwinvulkanutils \
PROPERTIES + OUTPUT_NAME ${KWIN_NAME}vulkanutils
+ VERSION ${KWINEFFECTS_VERSION_STRING}
+ SOVERSION ${KWINEFFECTS_SOVERSION}
+ )
+
+ target_link_libraries(kwinvulkanutils PUBLIC Qt5::Core Qt5::Gui KF5::ConfigCore \
KF5::CoreAddons KF5::WindowSystem Vulkan::Vulkan) + install(TARGETS \
kwinvulkanutils EXPORT kdeworkspaceLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) \
+endif() +
install( FILES
kwinglobals.h
kwineffects.h
@@ -113,8 +132,10 @@ install( FILES
kwinglutils_funcs.h
kwingltexture.h
kwinxrenderutils.h
+ kwinvulkanutils.h
${CMAKE_CURRENT_BINARY_DIR}/kwinconfig.h
${CMAKE_CURRENT_BINARY_DIR}/kwineffects_export.h
${CMAKE_CURRENT_BINARY_DIR}/kwinglutils_export.h
+ ${CMAKE_CURRENT_BINARY_DIR}/kwinvulkanutils_export.h
${CMAKE_CURRENT_BINARY_DIR}/kwinxrenderutils_export.h
DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel)
diff --git a/libkwineffects/kwinvulkanutils.cpp b/libkwineffects/kwinvulkanutils.cpp
new file mode 100644
index 000000000..95616945c
--- /dev/null
+++ b/libkwineffects/kwinvulkanutils.cpp
@@ -0,0 +1,1835 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright © 2017-2018 Fredrik Höglund <fredrik@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+
+#include "kwinvulkanutils.h"
+
+#include "kwineffects.h"
+#include "../utils.h"
+#include "logging_p.h"
+
+#include <QFile>
+#include <QDebug>
+
+
+namespace KWin {
+
+
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+
+
+// Finds the first struct of type sType in the pNext chain given by pNext
+static const void *findNextImpl(const void *pNext, VkStructureType sType)
+{
+ struct Header {
+ VkStructureType sType;
+ const void *pNext;
+ };
+
+ while (pNext) {
+ const Header *header = static_cast<const Header *>(pNext);
+ if (header->sType == sType)
+ return pNext;
+
+ pNext = header->pNext;
+ }
+
+ return nullptr;
+}
+
+
+// Returns the VkStructureType enumerator corresponding to T
+template <typename T> constexpr VkStructureType getStructureType() { return \
VK_STRUCTURE_TYPE_MAX_ENUM; } +
+template <> constexpr VkStructureType \
getStructureType<VkMemoryDedicatedRequirementsKHR>() { return \
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR; } +template <> constexpr \
VkStructureType getStructureType<VkImportMemoryFdInfoKHR>() { return \
VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; } +template <> constexpr VkStructureType \
getStructureType<VkExportMemoryAllocateInfoKHR>() { return \
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; } +
+
+// Finds the first struct of type T in the pNext chain given by pNext
+template <typename T>
+const T *findNext(const void *pNext)
+{
+ const VkStructureType sType = getStructureType<T>();
+ static_assert(sType != VK_STRUCTURE_TYPE_MAX_ENUM);
+ return static_cast<const T *>(findNextImpl(pNext, sType));
+}
+
+
+
+// ------------------------------------------------------------------
+
+
+
+VulkanDeviceMemoryAllocator::VulkanDeviceMemoryAllocator(VulkanDevice *device, const \
std::vector<const char *> &enabledDeviceExtensions) + : m_device(device)
+{
+ VulkanPhysicalDevice gpu = device->physicalDevice();
+ gpu.getMemoryProperties(&m_memoryProperties);
+
+ auto extensionEnabled = [&](const char *extension) -> bool {
+ return std::find_if(enabledDeviceExtensions.cbegin(), \
enabledDeviceExtensions.cend(), + [=](const char *entry) { \
return strcmp(extension, entry) == 0; }) != enabledDeviceExtensions.cend(); + };
+
+ m_haveExternalMemory = \
extensionEnabled(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); + m_haveExternalMemoryFd \
= extensionEnabled(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); + \
m_haveDedicatedAllocation = \
extensionEnabled(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + \
m_haveGetMemoryRequirements2 = \
extensionEnabled(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + \
m_haveBindMemory2 = extensionEnabled(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); \
+ m_haveExternalMemoryDmaBuf = \
extensionEnabled(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); +}
+
+
+VulkanDeviceMemoryAllocator::~VulkanDeviceMemoryAllocator()
+{
+}
+
+
+int VulkanDeviceMemoryAllocator::findMemoryType(uint32_t memoryTypeBits, \
VkMemoryPropertyFlags mask) const +{
+ for (unsigned int i = 0; i < m_memoryProperties.memoryTypeCount; i++) {
+ if (memoryTypeBits & (1 << i) &&
+ (m_memoryProperties.memoryTypes[i].propertyFlags & mask) == mask) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+std::shared_ptr<VulkanDeviceMemory> \
VulkanDeviceMemoryAllocator::allocateMemory(VkDeviceSize size, + \
uint32_t memoryTypeBits, + \
VkMemoryPropertyFlags optimal, + \
VkMemoryPropertyFlags required) +{
+ return allocateMemoryInternal(size, memoryTypeBits, optimal, required, nullptr);
+}
+
+
+std::shared_ptr<VulkanDeviceMemory> \
VulkanDeviceMemoryAllocator::allocateMemory(std::shared_ptr<VulkanImage> &image, + \
VkMemoryPropertyFlags optimal, VkMemoryPropertyFlags required) +{
+ // Out
+ VkMemoryDedicatedRequirementsKHR dedicatedRequirements = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR,
+ .pNext = nullptr,
+ .prefersDedicatedAllocation = VK_FALSE,
+ .requiresDedicatedAllocation = VK_FALSE
+ };
+
+ VkMemoryRequirements2KHR memoryRequirements2 = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR,
+ .pNext = &dedicatedRequirements,
+ .memoryRequirements = {}
+ };
+
+ if (m_haveGetMemoryRequirements2 && m_haveDedicatedAllocation) {
+ m_device->getImageMemoryRequirements2KHR(VkImageMemoryRequirementsInfo2KHR {
+ .sType = \
VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR, + \
.pNext = nullptr, + .image = \
image->handle() + }, \
&memoryRequirements2); + } else {
+ m_device->getImageMemoryRequirements(image->handle(), \
&memoryRequirements2.memoryRequirements); + }
+
+ const VkMemoryRequirements &memoryRequirements = \
memoryRequirements2.memoryRequirements; +
+ const VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
+ .pNext = nullptr,
+ .image = image->handle(),
+ .buffer = VK_NULL_HANDLE
+ };
+
+ const void *pAllocateInfoNext = nullptr;
+
+ if (dedicatedRequirements.prefersDedicatedAllocation || \
dedicatedRequirements.requiresDedicatedAllocation) + pAllocateInfoNext = \
&dedicatedAllocateInfo; +
+ auto memory = allocateMemoryInternal(memoryRequirements.size, \
memoryRequirements.memoryTypeBits, + optimal, \
required, pAllocateInfoNext); +
+ if (memory) {
+ m_device->bindImageMemory(image->handle(), memory->handle(), 0);
+ }
+
+ return memory;
+}
+
+
+std::shared_ptr<VulkanDeviceMemory> \
VulkanDeviceMemoryAllocator::allocateMemory(std::shared_ptr<VulkanBuffer> &buffer, + \
VkMemoryPropertyFlags optimal, VkMemoryPropertyFlags required) +{
+ // Out
+ VkMemoryDedicatedRequirementsKHR dedicatedRequirements = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR,
+ .pNext = nullptr,
+ .prefersDedicatedAllocation = VK_FALSE,
+ .requiresDedicatedAllocation = VK_FALSE
+ };
+
+ VkMemoryRequirements2KHR memoryRequirements2 = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR,
+ .pNext = &dedicatedRequirements,
+ .memoryRequirements = {}
+ };
+
+ if (m_haveGetMemoryRequirements2 && m_haveDedicatedAllocation) {
+ m_device->getBufferMemoryRequirements2KHR(VkBufferMemoryRequirementsInfo2KHR \
{ + .sType = \
VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR, + \
.pNext = nullptr, + .buffer = \
buffer->handle() + }, \
&memoryRequirements2); + } else {
+ m_device->getBufferMemoryRequirements(buffer->handle(), \
&memoryRequirements2.memoryRequirements); + }
+
+ const VkMemoryRequirements &memoryRequirements = \
memoryRequirements2.memoryRequirements; +
+ const VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
+ .pNext = nullptr,
+ .image = VK_NULL_HANDLE,
+ .buffer = buffer->handle()
+ };
+
+ const void *pAllocateInfoNext = nullptr;
+
+ if (dedicatedRequirements.prefersDedicatedAllocation || \
dedicatedRequirements.requiresDedicatedAllocation) + pAllocateInfoNext = \
&dedicatedAllocateInfo; +
+ auto memory = allocateMemoryInternal(memoryRequirements.size, \
memoryRequirements.memoryTypeBits, + optimal, \
required, pAllocateInfoNext); +
+ if (memory) {
+ m_device->bindBufferMemory(buffer->handle(), memory->handle(), 0);
+ }
+
+ return memory;
+}
+
+
+std::shared_ptr<VulkanDeviceMemory> \
VulkanDeviceMemoryAllocator::allocateMemoryInternal(VkDeviceSize size, + \
uint32_t memoryTypeBits, + \
VkMemoryPropertyFlags optimal, + \
VkMemoryPropertyFlags required, + \
const void *pAllocateInfoNext) +{
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+ int index = -1;
+
+ const auto *dedicatedRequirements = \
findNext<VkMemoryDedicatedRequirementsKHR>(pAllocateInfoNext); + const auto \
*importMemoryFdInfo = findNext<VkImportMemoryFdInfoKHR>(pAllocateInfoNext); + \
const auto *exportMemoryAllocateInfo = \
findNext<VkExportMemoryAllocateInfoKHR>(pAllocateInfoNext); +
+ while (memory == VK_NULL_HANDLE) {
+ index = findMemoryType(memoryTypeBits, optimal);
+
+ if (index == -1)
+ index = findMemoryType(memoryTypeBits, required);
+
+ if (index == -1)
+ break;
+
+ const VkMemoryAllocateInfo allocateInfo = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .pNext = pAllocateInfoNext,
+ .allocationSize = size,
+ .memoryTypeIndex = (uint32_t) index
+ };
+
+ VkResult result = m_device->allocateMemory(&allocateInfo, nullptr, &memory);
+ if (result != VK_SUCCESS) {
+ if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
+ // Clear the memory type bit and try again
+ memoryTypeBits &= ~(1 << index);
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (memory == VK_NULL_HANDLE) {
+ qCCritical(LIBKWINVULKANUTILS) << "Failed to allocate" << size << "bytes of \
device memory"; + return std::shared_ptr<VulkanDeviceMemory>();
+ }
+
+ return std::make_shared<VulkanDeviceMemory>(VulkanDeviceMemory::CreateInfo {
+ .device = m_device,
+ .memory = memory,
+ .size = size,
+ .flags = \
m_memoryProperties.memoryTypes[index].propertyFlags, + \
.exportableHandleTypes = exportMemoryAllocateInfo ? + \
exportMemoryAllocateInfo->handleTypes : 0, + \
.dedicated = dedicatedRequirements != nullptr, + \
.imported = importMemoryFdInfo != nullptr + \
}); +}
+
+
+
+// --------------------------------------------------------------------
+
+
+
+VulkanShaderModule::VulkanShaderModule(VulkanDevice *device, const QString \
&fileName) + : VulkanObject(),
+ m_device(device),
+ m_shaderModule(VK_NULL_HANDLE)
+{
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ qCCritical(LIBKWINVULKANUTILS) << "Failed to open" << fileName << "for \
reading"; + return;
+ }
+
+ const QByteArray code = file.readAll();
+
+ const VkShaderModuleCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .codeSize = (size_t) code.size(),
+ .pCode = (uint32_t *) code.constData()
+ };
+
+ if (m_device->createShaderModule(&createInfo, nullptr, &m_shaderModule) != \
VK_SUCCESS) { + qCCritical(LIBKWINVULKANUTILS) << "Failed to create shader \
module for" << fileName; + }
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+
+VulkanPipelineManager::VulkanPipelineManager(VulkanDevice *device, \
VulkanPipelineCache *cache, + VkSampler \
nearestSampler, VkSampler linearSampler, + \
VkRenderPass swapchainRenderPass, VkRenderPass offscreenRenderPass, + \
bool havePushDescriptors) + : m_device(device),
+ m_pipelineCache(cache),
+ m_nearestSampler(nearestSampler),
+ m_linearSampler(linearSampler),
+ m_havePushDescriptors(havePushDescriptors)
+{
+ m_renderPasses[SwapchainRenderPass] = swapchainRenderPass;
+ m_renderPasses[OffscreenRenderPass] = offscreenRenderPass;
+
+ for (int i = 0; i < MaterialCount; i++) {
+ m_descriptorSetLayout[i] = VK_NULL_HANDLE;
+ m_pipelineLayout[i] = VK_NULL_HANDLE;
+ m_pushDescriptorSetLayout[i] = VK_NULL_HANDLE;
+ m_pushDescriptorPipelineLayout[i] = VK_NULL_HANDLE;
+ }
+
+ const struct {
+ QString fileName;
+ VulkanShaderModule &module;
+ } modules[] = {
+ { QStringLiteral(":/resources/shaders/vulkan/color_vert.spv"), \
m_colorVertexShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/texture_vert.spv"), \
m_textureVertexShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/crossfade_vert.spv"), \
m_crossFadeVertexShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/updatedecoration_vert.spv"), \
m_updateDecorationVertexShader }, +
+ { QStringLiteral(":/resources/shaders/vulkan/color_frag.spv"), \
m_colorFragmentShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/texture_frag.spv"), \
m_textureFragmentShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/modulate_frag.spv"), \
m_modulateFragmentShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/desaturate_frag.spv"), \
m_desaturateFragmentShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/crossfade_frag.spv"), \
m_crossFadeFragmentShader }, + { \
QStringLiteral(":/resources/shaders/vulkan/updatedecoration_frag.spv"), \
m_updateDecorationFragmentShader }, + };
+
+ m_valid = true;
+
+ for (auto &entry : modules) {
+ entry.module = VulkanShaderModule(m_device, entry.fileName);
+ m_valid = m_valid && entry.module.isValid();
+ }
+
+ m_valid = m_valid && createDescriptorSetLayouts();
+ m_valid = m_valid && createPipelineLayouts();
+}
+
+
+VulkanPipelineManager::~VulkanPipelineManager()
+{
+ for (const std::pair<uint64_t, VkPipeline> &entry : m_pipelines) {
+ m_device->destroyPipeline(entry.second);
+ }
+
+ for (auto layout : m_pipelineLayout) {
+ if (layout) {
+ m_device->destroyPipelineLayout(layout);
+ }
+ }
+
+ for (auto layout : m_pushDescriptorPipelineLayout) {
+ if (layout) {
+ m_device->destroyPipelineLayout(layout);
+ }
+ }
+
+ for (auto layout : m_descriptorSetLayout) {
+ if (layout) {
+ m_device->destroyDescriptorSetLayout(layout);
+ }
+ }
+
+ for (auto layout : m_pushDescriptorSetLayout) {
+ if (layout) {
+ m_device->destroyDescriptorSetLayout(layout);
+ }
+ }
+}
+
+
+bool VulkanPipelineManager::createDescriptorSetLayouts()
+{
+ bool valid = true;
+
+ struct CreateInfo {
+ VkDescriptorSetLayoutCreateFlags flags;
+ std::initializer_list<VkDescriptorSetLayoutBinding> bindings;
+ };
+
+ auto create = [&](const CreateInfo &info) -> VkDescriptorSetLayout {
+ VkDescriptorSetLayout layout;
+ VkResult result;
+
+ if ((info.flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) \
&& !m_havePushDescriptors) + return VK_NULL_HANDLE;
+
+ result = m_device->createDescriptorSetLayout({
+ .sType = \
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + \
.pNext = nullptr, + .flags = \
info.flags, + .bindingCount = \
(uint32_t) info.bindings.size(), + \
.pBindings = info.bindings.begin() + \
}, nullptr, &layout); +
+ if (result != VK_SUCCESS) {
+ qCCritical(LIBKWINVULKANUTILS) << "Failed to create a descriptor set \
layout"; + valid = false;
+ }
+
+ return layout;
+ };
+
+
+ // layout (set = N, binding = 0) uniform UBO {
+ // mat4 matrix;
+ // vec4 color;
+ // }
+ m_descriptorSetLayout[FlatColor] =
+ create({
+ .flags = 0,
+ .bindings = {
+ {
+ .binding = 0,
+ .descriptorType = \
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + \
.descriptorCount = 1, + .stageFlags = \
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + \
.pImmutableSamplers = nullptr + }
+ }
+ });
+
+ m_pushDescriptorSetLayout[FlatColor] =
+ create({
+ .flags = \
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, + \
.bindings = { + {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | \
VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = \
nullptr + }
+ }
+ });
+
+
+ // layout (set = N, binding = 0) uniform sampler2D texture;
+ // layout (set = N, binding = 1) uniform UBO {
+ // mat4 matrix;
+ // ...
+ // }
+ m_descriptorSetLayout[Texture] =
+ create({
+ .flags = 0,
+ .bindings = {
+ {
+ .binding = 0,
+ .descriptorType = \
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + \
.descriptorCount = 1, + .stageFlags = \
VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = \
nullptr + },
+ {
+ .binding = 1,
+ .descriptorType = \
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + \
.descriptorCount = 1, + .stageFlags = \
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + \
.pImmutableSamplers = nullptr + }
+ }
+ });
+
+ m_pushDescriptorSetLayout[Texture] =
+ create({
+ .flags = \
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, + \
.bindings = { + {
+ .binding = 0,
+ .descriptorType = \
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + \
.descriptorCount = 1, + .stageFlags = \
VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = \
nullptr + },
+ {
+ .binding = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | \
VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = \
nullptr + }
+ }
+ });
+
+ // layout (set = N, binding = 0) uniform texture2D textures[2];
+ // layout (set = N, binding = 1) uniform sampler sampler {
+ // layout (set = N, binding = 2) uniform UBO {
+ // mat4 matrix;
+ // ...
+ // }
+ m_descriptorSetLayout[TwoTextures] =
+ create({
+ .flags = 0,
+ .bindings = {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ .descriptorCount = 2,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr
+ },
+ {
+ .binding = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr
+ },
+ {
+ .binding = 2,
+ .descriptorType = \
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + \
.descriptorCount = 1, + .stageFlags = \
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + \
.pImmutableSamplers = nullptr + }
+ }
+ });
+
+
+ m_pushDescriptorSetLayout[TwoTextures] =
+ create({
+ .flags = \
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, + \
.bindings = { + {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ .descriptorCount = 2,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr
+ },
+ {
+ .binding = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr
+ },
+ {
+ .binding = 2,
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | \
VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = \
nullptr + }
+ }
+ });
+
+ // layout (set = N, binding = 0) uniform texture2D textures[4];
+ // layout (set = N, binding = 1) uniform sampler sampler {
+ m_descriptorSetLayout[DecorationStagingImages] =
+ create({
+ .flags = 0,
+ .bindings = {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ .descriptorCount = 4,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr
+ },
+ {
+ .binding = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = &m_nearestSampler
+ }
+ }
+ });
+
+ m_pushDescriptorSetLayout[DecorationStagingImages] =
+ create({
+ .flags = \
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, + \
.bindings = { + {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ .descriptorCount = 4,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr
+ },
+ {
+ .binding = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = &m_nearestSampler
+ }
+ }
+ });
+
+ return valid;
+}
+
+
+bool VulkanPipelineManager::createPipelineLayouts()
+{
+ bool valid = true;
+
+ auto create = [&](const std::initializer_list<VkDescriptorSetLayout> setLayouts,
+ const std::initializer_list<VkPushConstantRange> \
pushConstantRanges = {}) { + VkPipelineLayout layout = VK_NULL_HANDLE;
+ VkResult result = m_device->createPipelineLayout({
+ .sType = \
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + \
.pNext = nullptr, + \
.flags = 0, + \
.setLayoutCount = (uint32_t) setLayouts.size(), + \
.pSetLayouts = setLayouts.begin(), + \
.pushConstantRangeCount = (uint32_t) pushConstantRanges.size(), + \
.pPushConstantRanges = pushConstantRanges.begin() + \
}, nullptr, &layout); + if (result != VK_SUCCESS) {
+ qCCritical(LIBKWINVULKANUTILS) << "Failed to create a pipeline layout";
+ valid = false;
+ }
+
+ return layout;
+ };
+
+ for (int i = 0; i <= TwoTextures; i++) {
+ m_pipelineLayout[i] = create({m_descriptorSetLayout[i]});
+
+ if (m_havePushDescriptors)
+ m_pushDescriptorPipelineLayout[i] = \
create({m_pushDescriptorSetLayout[i]}); + else
+ m_pushDescriptorPipelineLayout[i] = VK_NULL_HANDLE;
+ }
+
+ m_pipelineLayout[DecorationStagingImages] =
+ create({
+ m_descriptorSetLayout[DecorationStagingImages]
+ },
+ {
+ {
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .offset = 0,
+ .size = sizeof(uint32_t)
+ }
+ });
+
+ if (m_havePushDescriptors) {
+ m_pushDescriptorPipelineLayout[DecorationStagingImages] =
+ create({
+ m_pushDescriptorSetLayout[DecorationStagingImages]
+ },
+ {
+ {
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .offset = 0,
+ .size = sizeof(uint32_t)
+ }
+ });
+ } else {
+ m_pushDescriptorPipelineLayout[DecorationStagingImages] = VK_NULL_HANDLE;
+ }
+
+ return valid;
+}
+
+
+VkPipeline VulkanPipelineManager::createPipeline(Material material, Traits traits, \
DescriptorType descriptorType, Topology topology, VkRenderPass renderPass) +{
+ // Viewport state
+ // --------------
+ static const VkViewport viewport = {
+ .x = 0.0f,
+ .y = 0.0f,
+ .width = 1.0f,
+ .height = 1.0f,
+ .minDepth = 0.0f,
+ .maxDepth = 1.0f
+ };
+
+ static const VkRect2D scissor = {
+ .offset = { 0, 0 },
+ .extent = { 1, 1 }
+ };
+
+ const VkPipelineViewportStateCreateInfo viewportState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .viewportCount = 1,
+ .pViewports = &viewport,
+ .scissorCount = 1,
+ .pScissors = &scissor
+ };
+
+
+ // Rasterization state
+ // -------------------
+ static const VkPipelineRasterizationStateCreateInfo rasterizationState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .depthClampEnable = VK_FALSE,
+ .rasterizerDiscardEnable = VK_FALSE,
+ .polygonMode = VK_POLYGON_MODE_FILL,
+ .cullMode = VK_CULL_MODE_NONE,
+ .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
+ .depthBiasEnable = VK_FALSE,
+ .depthBiasConstantFactor = 0.0f,
+ .depthBiasClamp = 0.0f,
+ .depthBiasSlopeFactor = 0.0f,
+ .lineWidth = 1.0f
+ };
+
+
+ // Multisample state
+ // -----------------
+ static const VkPipelineMultisampleStateCreateInfo multisampleState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
+ .sampleShadingEnable = VK_FALSE,
+ .minSampleShading = 1.0f,
+ .pSampleMask = nullptr,
+ .alphaToCoverageEnable = VK_FALSE,
+ .alphaToOneEnable = VK_FALSE
+ };
+
+
+ // Dynamic states
+ //---------------
+ static const VkDynamicState dynamicStates[] {
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ };
+
+ const VkPipelineDynamicStateCreateInfo dynamicState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .dynamicStateCount = ARRAY_SIZE(dynamicStates),
+ .pDynamicStates = dynamicStates
+ };
+
+
+ // Depth-stencil state
+ // -------------------
+ static const VkPipelineDepthStencilStateCreateInfo depthStencilState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .depthTestEnable = VK_FALSE,
+ .depthWriteEnable = VK_FALSE,
+ .depthCompareOp = VK_COMPARE_OP_LESS,
+ .depthBoundsTestEnable = VK_FALSE,
+ .stencilTestEnable = VK_FALSE,
+ .front = {
+ .failOp = VK_STENCIL_OP_KEEP,
+ .passOp = VK_STENCIL_OP_KEEP,
+ .depthFailOp = VK_STENCIL_OP_KEEP,
+ .compareOp = VK_COMPARE_OP_NEVER,
+ .compareMask = 0,
+ .writeMask = 0,
+ .reference = 0
+ },
+ .back = {
+ .failOp = VK_STENCIL_OP_KEEP,
+ .passOp = VK_STENCIL_OP_KEEP,
+ .depthFailOp = VK_STENCIL_OP_KEEP,
+ .compareOp = VK_COMPARE_OP_NEVER,
+ .compareMask = 0,
+ .writeMask = 0,
+ .reference = 0
+ },
+ .minDepthBounds = 0.0f,
+ .maxDepthBounds = 1.0f
+ };
+
+
+ // Color blend attachment states
+ // -----------------------------
+ static const VkPipelineColorBlendAttachmentState preMultipliedBlendAttachment {
+ .blendEnable = VK_TRUE,
+ .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
+ .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+ .colorBlendOp = VK_BLEND_OP_ADD,
+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+ .alphaBlendOp = VK_BLEND_OP_ADD,
+ .colorWriteMask = 0xf
+ };
+
+ static const VkPipelineColorBlendAttachmentState opaqueBlendAttachment {
+ .blendEnable = VK_TRUE,
+ .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
+ .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .colorBlendOp = VK_BLEND_OP_ADD,
+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
+ .alphaBlendOp = VK_BLEND_OP_ADD,
+ .colorWriteMask = 0xf
+ };
+
+
+ // Color blend states
+ // ------------------
+ const VkPipelineColorBlendStateCreateInfo preMultipliedAlphaBlendState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .logicOpEnable = VK_FALSE,
+ .logicOp = VK_LOGIC_OP_COPY,
+ .attachmentCount = 1,
+ .pAttachments = &preMultipliedBlendAttachment,
+ .blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }
+ };
+
+ const VkPipelineColorBlendStateCreateInfo opaqueBlendState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .logicOpEnable = VK_FALSE,
+ .logicOp = VK_LOGIC_OP_COPY,
+ .attachmentCount = 1,
+ .pAttachments = &opaqueBlendAttachment,
+ .blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }
+ };
+
+
+
+ // Input assembly states
+ // ---------------------
+ const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .topology = (VkPrimitiveTopology) topology,
+ .primitiveRestartEnable = VK_FALSE
+ };
+
+
+ // Color inputs
+ // ------------
+ static const VkVertexInputAttributeDescription colorVertexInputAttribs[] = {
+ { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = \
0 }, + };
+
+ static const VkVertexInputBindingDescription colorVertexInputBindings[] {
+ { .binding = 0, .stride = sizeof(QVector2D), .inputRate = \
VK_VERTEX_INPUT_RATE_VERTEX }, + };
+
+ const VkPipelineVertexInputStateCreateInfo colorVertexInputState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .vertexBindingDescriptionCount = ARRAY_SIZE(colorVertexInputBindings),
+ .pVertexBindingDescriptions = colorVertexInputBindings,
+ .vertexAttributeDescriptionCount = ARRAY_SIZE(colorVertexInputAttribs),
+ .pVertexAttributeDescriptions = colorVertexInputAttribs
+ };
+
+
+ // Texture inputs
+ // --------------
+ static const VkVertexInputAttributeDescription textureVertexInputAttribs[] = {
+ { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = \
offsetof(GLVertex2D, position) }, + { .location = 1, .binding = 0, .format = \
VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(GLVertex2D, texcoord) }, + };
+
+ static const VkVertexInputBindingDescription textureVertexInputBindings[] {
+ { .binding = 0, .stride = sizeof(GLVertex2D), .inputRate = \
VK_VERTEX_INPUT_RATE_VERTEX }, + };
+
+ const VkPipelineVertexInputStateCreateInfo textureVertexInputState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .vertexBindingDescriptionCount = ARRAY_SIZE(textureVertexInputBindings),
+ .pVertexBindingDescriptions = textureVertexInputBindings,
+ .vertexAttributeDescriptionCount = ARRAY_SIZE(textureVertexInputAttribs),
+ .pVertexAttributeDescriptions = textureVertexInputAttribs
+ };
+
+
+ // Cross-fade inputs
+ // -----------------
+ static const VkVertexInputAttributeDescription crossFadeVertexInputAttribs[] = {
+ { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = \
offsetof(GLCrossFadeVertex2D, position) }, + { .location = 1, .binding = 0, \
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(GLCrossFadeVertex2D, texcoord1) \
}, + { .location = 2, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset \
= offsetof(GLCrossFadeVertex2D, texcoord2) }, + };
+
+ static const VkVertexInputBindingDescription crossFadeVertexInputBindings[] {
+ { .binding = 0, .stride = sizeof(GLCrossFadeVertex2D), .inputRate = \
VK_VERTEX_INPUT_RATE_VERTEX }, + };
+
+ const VkPipelineVertexInputStateCreateInfo crossFadeVertexInputState {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .vertexBindingDescriptionCount = ARRAY_SIZE(crossFadeVertexInputBindings),
+ .pVertexBindingDescriptions = crossFadeVertexInputBindings,
+ .vertexAttributeDescriptionCount = ARRAY_SIZE(crossFadeVertexInputAttribs),
+ .pVertexAttributeDescriptions = crossFadeVertexInputAttribs
+ };
+
+ const VkPipelineVertexInputStateCreateInfo *vertexInputState = nullptr;
+ const VkPipelineColorBlendStateCreateInfo *blendState = nullptr;
+ VkShaderModule fs = VK_NULL_HANDLE;
+ VkShaderModule vs = VK_NULL_HANDLE;
+ VkPipelineLayout layout;
+
+ if (descriptorType == PushDescriptors)
+ layout = m_pushDescriptorPipelineLayout[material];
+ else
+ layout = m_pipelineLayout[material];
+
+ if (traits & PreMultipliedAlphaBlend)
+ blendState = &preMultipliedAlphaBlendState;
+ else
+ blendState = &opaqueBlendState;
+
+ switch (material) {
+ case FlatColor:
+ vertexInputState = &colorVertexInputState;
+ vs = m_colorVertexShader;
+ fs = m_colorFragmentShader;
+ break;
+
+ case Texture:
+ vertexInputState = &textureVertexInputState;
+ vs = m_textureVertexShader;
+ if (traits & Desaturate)
+ fs = m_desaturateFragmentShader;
+ else if (traits & Modulate)
+ fs = m_modulateFragmentShader;
+ else
+ fs = m_textureFragmentShader;
+ break;
+
+ case TwoTextures:
+ vertexInputState = &crossFadeVertexInputState;
+ vs = m_crossFadeVertexShader;
+ fs = m_crossFadeFragmentShader;
+ break;
+
+ case DecorationStagingImages:
+ vertexInputState = &textureVertexInputState;
+ vs = m_updateDecorationVertexShader;
+ fs = m_updateDecorationFragmentShader;
+ break;
+
+ default:
+ break;
+ };
+
+
+ // Shader stages
+ // -------------
+ const VkPipelineShaderStageCreateInfo pipelineStages[] {
+ // Vertex shader
+ {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .stage = VK_SHADER_STAGE_VERTEX_BIT,
+ .module = vs,
+ .pName = "main",
+ .pSpecializationInfo = nullptr
+ },
+ // Fragment shader
+ {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .module = fs,
+ .pName = "main",
+ .pSpecializationInfo = nullptr
+ }
+ };
+
+ const VkGraphicsPipelineCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .stageCount = ARRAY_SIZE(pipelineStages),
+ .pStages = pipelineStages,
+ .pVertexInputState = vertexInputState,
+ .pInputAssemblyState = &inputAssemblyState,
+ .pTessellationState = nullptr,
+ .pViewportState = &viewportState,
+ .pRasterizationState = &rasterizationState,
+ .pMultisampleState = &multisampleState,
+ .pDepthStencilState = &depthStencilState,
+ .pColorBlendState = blendState,
+ .pDynamicState = &dynamicState,
+ .layout = layout,
+ .renderPass = renderPass,
+ .subpass = 0,
+ .basePipelineHandle = VK_NULL_HANDLE,
+ .basePipelineIndex = 0
+ };
+
+ VkPipeline pipeline;
+ const VkResult result = \
m_device->createGraphicsPipelines(m_pipelineCache->handle(), 1, &createInfo, nullptr, \
&pipeline); +
+ if (result != VK_SUCCESS) {
+ qCCritical(LIBKWINVULKANUTILS) << "vkCreateGraphicsPipelines returned" << \
enumToString(result); + return VK_NULL_HANDLE;
+ }
+
+ return pipeline;
+}
+
+
+std::tuple<VkPipeline, VkPipelineLayout> VulkanPipelineManager::pipeline(Material \
material, + \
Traits traits, + \
DescriptorType descriptorType, + \
Topology topology, + \
RenderPassType renderPassType) +{
+ union {
+ struct {
+ unsigned material:3;
+ unsigned traits:5;
+ unsigned topology:3;
+ unsigned descriptorType:1;
+ unsigned renderPassType:1;
+ unsigned unused:19;
+ } u;
+ uint32_t value;
+ } key;
+
+ key.value = 0;
+
+ key.u.material = material;
+ key.u.traits = traits;
+ key.u.topology = topology;
+ key.u.descriptorType = descriptorType;
+ key.u.renderPassType = renderPassType;
+
+ VkPipeline &pipe = m_pipelines[key.value];
+
+ if (pipe == VK_NULL_HANDLE)
+ pipe = createPipeline(material, traits, descriptorType, topology, \
m_renderPasses[renderPassType]); +
+ const VkPipelineLayout layout = descriptorType == PushDescriptors ?
+ m_pushDescriptorPipelineLayout[material] :
+ m_pipelineLayout[material];
+
+ return std::tuple<VkPipeline, VkPipelineLayout>(pipe, layout);
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+
+class VulkanCircularAllocatorBase::CircularBuffer : public \
std::enable_shared_from_this<CircularBuffer> +{
+public:
+ struct BusyOffset {
+ BusyOffset(const BusyOffset &) = delete;
+ BusyOffset(BusyOffset &&) = default;
+ ~BusyOffset() { if (m_buffer) m_buffer->m_tail = m_offset; }
+ BusyOffset &operator = (const BusyOffset &) = delete;
+ BusyOffset &operator = (BusyOffset &&) = default;
+ std::shared_ptr<CircularBuffer> m_buffer;
+ uint32_t m_offset;
+ };
+
+ CircularBuffer(const std::shared_ptr<VulkanBuffer> &buffer, const \
std::shared_ptr<VulkanDeviceMemory> &memory, uint8_t *data, uint32_t size) + : \
m_buffer(buffer), m_memory(memory), m_size(size), m_data(data) {} +
+ CircularBuffer(const std::shared_ptr<VulkanDeviceMemory> &memory, uint8_t *data, \
uint32_t size) + : m_buffer(nullptr), m_memory(memory), m_size(size), \
m_data(data) {} +
+ bool allocate(size_t size, uint32_t alignment, uint32_t *pOffset);
+
+ bool isBusy() const { return m_head != m_lastBusyOffset; }
+
+ void getNonCoherentAllocatedRanges(std::back_insert_iterator<std::vector<VkMappedMemoryRange>> \
&it, VkDeviceSize nonCoherentAtomSize); + BusyOffset busyOffset();
+
+ std::shared_ptr<VulkanBuffer> buffer() const { return m_buffer; }
+ std::shared_ptr<VulkanDeviceMemory> memory() const { return m_memory; }
+ VkDeviceMemory memoryHandle() const { return m_memory->handle(); }
+ uint32_t size() const { return m_size; }
+ uint8_t *data() const { return m_data; }
+
+private:
+ std::shared_ptr<VulkanBuffer> m_buffer;
+ std::shared_ptr<VulkanDeviceMemory> m_memory;
+ uint32_t m_head = 0;
+ uint32_t m_tail = 0;
+ uint32_t m_size = 0;
+ uint32_t m_nextWrapAroundOffset = 0;
+ uint32_t m_lastBusyOffset = 0;
+ uint32_t m_flushedOffset = 0;
+ uint8_t *m_data = nullptr;
+
+ friend class BusyOffset;
+};
+
+
+bool VulkanCircularAllocatorBase::CircularBuffer::allocate(size_t allocationSize, \
uint32_t alignment, uint32_t *pOffset) +{
+ // Make sure the allocation will fit in the buffer
+ if (allocationSize > m_size)
+ return false;
+
+ // Align the offset
+ uint32_t offset = align(m_head, alignment);
+
+ // Handle wrap around
+ uint32_t wrapAroundOffset = m_nextWrapAroundOffset;
+ if (offset + allocationSize > wrapAroundOffset) {
+ offset = wrapAroundOffset;
+ wrapAroundOffset += m_size;
+ }
+
+ // Make sure there is enough free space for the allocation
+ if (m_tail + m_size - offset < allocationSize)
+ return false;
+
+ m_head = offset + allocationSize;
+ m_nextWrapAroundOffset = wrapAroundOffset;
+
+ *pOffset = offset & (m_size - 1);
+ return true;
+}
+
+
+void VulkanCircularAllocatorBase::CircularBuffer::getNonCoherentAllocatedRanges(std::back_insert_iterator<std::vector<VkMappedMemoryRange>> \
&it, VkDeviceSize nonCoherentAtomSize) +{
+ if (!m_memory || m_memory->isHostCoherent())
+ return;
+
+ if (m_flushedOffset == m_head)
+ return;
+
+ uint32_t start = m_flushedOffset & ~(nonCoherentAtomSize - 1); // Round down
+ uint32_t end = align(m_head, nonCoherentAtomSize); // Round up
+
+ if ((end - start) >= m_buffer->size()) {
+ *it++ = VkMappedMemoryRange {
+ .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+ .pNext = nullptr,
+ .memory = m_memory->handle(),
+ .offset = 0,
+ .size = VK_WHOLE_SIZE
+ };
+ } else {
+ const uint32_t mask = m_buffer->size() - 1;
+ start &= mask;
+ end &= mask;
+
+ assert(!(m_memory->size() & (nonCoherentAtomSize - 1)));
+ assert(end <= m_memory->size());
+
+ if (start < end) {
+ *it++ = VkMappedMemoryRange {
+ .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+ .pNext = nullptr,
+ .memory = m_memory->handle(),
+ .offset = start,
+ .size = end - start
+ };
+ } else {
+ // We have wrapped around and have dirty ranges at both the beginning
+ // and the end of the buffer
+ *it++ = VkMappedMemoryRange {
+ .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+ .pNext = nullptr,
+ .memory = m_memory->handle(),
+ .offset = 0,
+ .size = end
+ };
+
+ *it++ = VkMappedMemoryRange {
+ .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+ .pNext = nullptr,
+ .memory = m_memory->handle(),
+ .offset = start,
+ .size = m_memory->size() - start
+ };
+ }
+ }
+
+ m_flushedOffset = m_head;
+}
+
+
+VulkanCircularAllocatorBase::CircularBuffer::BusyOffset \
VulkanCircularAllocatorBase::CircularBuffer::busyOffset() +{
+ if (m_lastBusyOffset != m_head) {
+ m_lastBusyOffset = m_head;
+ return BusyOffset{shared_from_this(), m_head};
+ }
+
+ return BusyOffset{nullptr, 0};
+}
+
+
+
+// -------------------------------------------------------------------
+
+
+
+VulkanCircularAllocatorBase::VulkanCircularAllocatorBase(VulkanDevice *device, \
uint32_t nonCoherentAtomSize) + : m_device(device),
+ m_nonCoherentAtomSize(nonCoherentAtomSize)
+{
+}
+
+
+VulkanCircularAllocatorBase::~VulkanCircularAllocatorBase()
+{
+}
+
+
+void VulkanCircularAllocatorBase::getNonCoherentAllocatedRanges(std::back_insert_iterator<std::vector<VkMappedMemoryRange>> \
it) +{
+ for (auto &buffer : m_orphanedBuffers)
+ buffer->getNonCoherentAllocatedRanges(it, m_nonCoherentAtomSize);
+
+ if (m_circularBuffer)
+ m_circularBuffer->getNonCoherentAllocatedRanges(it, m_nonCoherentAtomSize);
+}
+
+
+std::shared_ptr<VulkanObject> VulkanCircularAllocatorBase::createFrameBoundary()
+{
+ struct FrameBoundary : public VulkanObject
+ {
+ FrameBoundary(CircularBuffer::BusyOffset &&offset, \
std::vector<std::shared_ptr<CircularBuffer>> &&buffers) + : \
offset(std::move(offset)), buffers(std::move(buffers)) {} + \
CircularBuffer::BusyOffset offset; + \
std::vector<std::shared_ptr<CircularBuffer>> buffers; + };
+
+ std::shared_ptr<FrameBoundary> boundary;
+
+ if (m_circularBuffer)
+ boundary = std::make_shared<FrameBoundary>(m_circularBuffer->busyOffset(), \
std::move(m_orphanedBuffers)); + else
+ boundary = std::make_shared<FrameBoundary>(CircularBuffer::BusyOffset{nullptr, \
0}, std::move(m_orphanedBuffers)); +
+ m_orphanedBuffers = std::vector<std::shared_ptr<CircularBuffer>>();
+ return boundary;
+}
+
+
+
+// -------------------------------------------------------------------
+
+
+
+VulkanUploadManager::VulkanUploadManager(VulkanDevice *device,
+ VulkanDeviceMemoryAllocator *allocator,
+ size_t initialSize,
+ VkBufferUsageFlags bufferUsage,
+ VkMemoryPropertyFlags optimalFlags,
+ const VkPhysicalDeviceLimits &limits)
+ : VulkanCircularAllocatorBase(device, limits.nonCoherentAtomSize),
+ m_allocator(allocator),
+ m_initialSize(initialSize),
+ m_bufferUsage(bufferUsage),
+ m_optimalMemoryFlags(optimalFlags),
+ m_minTexelBufferOffsetAlignment(limits.minTexelBufferOffsetAlignment),
+ m_minUniformBufferOffsetAlignment(limits.minUniformBufferOffsetAlignment),
+ m_minStorageBufferOffsetAlignment(limits.minStorageBufferOffsetAlignment)
+{
+ // The size must be a power-of-two
+ assert(initialSize == (initialSize & -initialSize));
+}
+
+
+VulkanUploadManager::~VulkanUploadManager()
+{
+}
+
+
+VulkanBufferRange VulkanUploadManager::allocate(size_t size, uint32_t alignment)
+{
+ uint32_t offset = 0;
+
+ if (!m_circularBuffer || !m_circularBuffer->allocate(size, alignment, &offset)) \
{ + reallocate(size);
+
+ if (!m_circularBuffer || !m_circularBuffer->allocate(size, alignment, \
&offset)) + return VulkanBufferRange();
+ }
+
+ return VulkanBufferRange(m_circularBuffer->buffer(), offset, size, \
m_circularBuffer->data() + offset); +}
+
+
+void VulkanUploadManager::reallocate(size_t minimumSize)
+{
+ size_t newSize = (m_circularBuffer && m_circularBuffer->size() > 0) ? \
m_circularBuffer->size() * 2 : m_initialSize; + while (newSize < minimumSize)
+ newSize *= 2;
+
+ newSize = align(newSize, m_nonCoherentAtomSize);
+
+ // The size must be a power-of-two
+ assert(newSize == (newSize & -newSize));
+
+ if (m_circularBuffer && m_circularBuffer->isBusy())
+ m_orphanedBuffers.push_back(m_circularBuffer);
+
+ m_circularBuffer = nullptr;
+
+ auto buffer = std::make_shared<VulkanBuffer>(m_device,
+ VkBufferCreateInfo {
+ .sType = \
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + \
.pNext = nullptr, + .flags = 0,
+ .size = newSize,
+ .usage = m_bufferUsage,
+ .sharingMode = \
VK_SHARING_MODE_EXCLUSIVE, + \
.queueFamilyIndexCount = 0, + \
.pQueueFamilyIndices = nullptr + });
+
+ if (buffer && buffer->isValid()) {
+ auto memory = m_allocator->allocateMemory(buffer, m_optimalMemoryFlags, \
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (memory && memory->isValid()) {
+ uint8_t *data = nullptr;
+ memory->map(0, (void **) &data);
+
+ m_circularBuffer = std::make_shared<CircularBuffer>(buffer, memory, \
data, newSize); + }
+ }
+}
+
+
+
+// -------------------------------------------------------------------
+
+
+
+VulkanStagingImageAllocator::VulkanStagingImageAllocator(VulkanDevice *device,
+ VulkanDeviceMemoryAllocator \
*allocator, + size_t \
initialSize, + \
VkMemoryPropertyFlags optimalMemoryFlags, + \
const VkPhysicalDeviceLimits &limits) + : VulkanCircularAllocatorBase(device, \
limits.nonCoherentAtomSize), + m_allocator(allocator),
+ m_initialSize(initialSize),
+ m_optimalMemoryFlags(optimalMemoryFlags)
+{
+ // The size must be a power-of-two
+ assert(initialSize == (initialSize & -initialSize));
+}
+
+
+VulkanStagingImageAllocator::~VulkanStagingImageAllocator()
+{
+}
+
+
+std::shared_ptr<VulkanStagingImage> VulkanStagingImageAllocator::createImage(const \
VkImageCreateInfo &createInfo) +{
+ auto image = std::make_shared<VulkanStagingImage>(m_device, createInfo);
+ if (!image->isValid())
+ return nullptr;
+
+ VkMemoryRequirements memoryRequirements;
+ m_device->getImageMemoryRequirements(image->handle(), &memoryRequirements);
+
+ uint32_t offset = 0;
+ if (!m_circularBuffer || !m_circularBuffer->allocate(memoryRequirements.size, \
memoryRequirements.alignment, &offset)) { + \
reallocate(memoryRequirements.size, memoryRequirements.memoryTypeBits); +
+ if (!m_circularBuffer || \
!m_circularBuffer->allocate(memoryRequirements.size, memoryRequirements.alignment, \
&offset)) + return nullptr;
+ }
+
+ m_device->bindImageMemory(image->handle(), m_circularBuffer->memoryHandle(), \
offset); + image->setData(m_circularBuffer->data() + offset);
+
+ return image;
+}
+
+
+void VulkanStagingImageAllocator::reallocate(size_t minimumSize, uint32_t \
memoryTypeBits) +{
+ size_t newSize = (m_circularBuffer && m_circularBuffer->size() > 0) ? \
m_circularBuffer->size() * 2 : m_initialSize; + while (newSize < minimumSize)
+ newSize *= 2;
+
+ newSize = align(newSize, m_nonCoherentAtomSize);
+
+ // The size must be a power-of-two
+ assert(newSize == (newSize & -newSize));
+
+ if (m_circularBuffer && m_circularBuffer->isBusy())
+ m_orphanedBuffers.push_back(m_circularBuffer);
+
+ m_circularBuffer = nullptr;
+
+ if (auto memory = m_allocator->allocateMemory(newSize, memoryTypeBits, \
m_optimalMemoryFlags, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + uint8_t *data \
= nullptr; + memory->map(0, (void **) &data);
+
+ m_circularBuffer = std::make_shared<CircularBuffer>(memory, data, newSize);
+ }
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+#define CASE(x) case (x): return QByteArrayLiteral(#x);
+
+QByteArray enumToString(VkResult result)
+{
+ switch (result) {
+ CASE(VK_SUCCESS)
+ CASE(VK_NOT_READY)
+ CASE(VK_TIMEOUT)
+ CASE(VK_EVENT_SET)
+ CASE(VK_EVENT_RESET)
+ CASE(VK_INCOMPLETE)
+ CASE(VK_ERROR_OUT_OF_HOST_MEMORY)
+ CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY)
+ CASE(VK_ERROR_INITIALIZATION_FAILED)
+ CASE(VK_ERROR_DEVICE_LOST)
+ CASE(VK_ERROR_MEMORY_MAP_FAILED)
+ CASE(VK_ERROR_LAYER_NOT_PRESENT)
+ CASE(VK_ERROR_EXTENSION_NOT_PRESENT)
+ CASE(VK_ERROR_FEATURE_NOT_PRESENT)
+ CASE(VK_ERROR_INCOMPATIBLE_DRIVER)
+ CASE(VK_ERROR_TOO_MANY_OBJECTS)
+ CASE(VK_ERROR_FORMAT_NOT_SUPPORTED)
+ CASE(VK_ERROR_FRAGMENTED_POOL)
+ CASE(VK_ERROR_SURFACE_LOST_KHR)
+ CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR)
+ CASE(VK_SUBOPTIMAL_KHR)
+ CASE(VK_ERROR_OUT_OF_DATE_KHR)
+ CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)
+ CASE(VK_ERROR_VALIDATION_FAILED_EXT)
+ CASE(VK_ERROR_INVALID_SHADER_NV)
+ CASE(VK_ERROR_OUT_OF_POOL_MEMORY_KHR)
+ CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR)
+ default: return QByteArray::number(result);
+ }
+}
+
+#undef CASE
+
+QByteArray enumToString(VkFormat format)
+{
+ static const char * const formats[] = {
+ "VK_FORMAT_UNDEFINED",
+ "VK_FORMAT_R4G4_UNORM_PACK8",
+ "VK_FORMAT_R4G4B4A4_UNORM_PACK16",
+ "VK_FORMAT_B4G4R4A4_UNORM_PACK16",
+ "VK_FORMAT_R5G6B5_UNORM_PACK16",
+ "VK_FORMAT_B5G6R5_UNORM_PACK16",
+ "VK_FORMAT_R5G5B5A1_UNORM_PACK16",
+ "VK_FORMAT_B5G5R5A1_UNORM_PACK16",
+ "VK_FORMAT_A1R5G5B5_UNORM_PACK16",
+ "VK_FORMAT_R8_UNORM",
+ "VK_FORMAT_R8_SNORM",
+ "VK_FORMAT_R8_USCALED",
+ "VK_FORMAT_R8_SSCALED",
+ "VK_FORMAT_R8_UINT",
+ "VK_FORMAT_R8_SINT",
+ "VK_FORMAT_R8_SRGB",
+ "VK_FORMAT_R8G8_UNORM",
+ "VK_FORMAT_R8G8_SNORM",
+ "VK_FORMAT_R8G8_USCALED",
+ "VK_FORMAT_R8G8_SSCALED",
+ "VK_FORMAT_R8G8_UINT",
+ "VK_FORMAT_R8G8_SINT",
+ "VK_FORMAT_R8G8_SRGB",
+ "VK_FORMAT_R8G8B8_UNORM",
+ "VK_FORMAT_R8G8B8_SNORM",
+ "VK_FORMAT_R8G8B8_USCALED",
+ "VK_FORMAT_R8G8B8_SSCALED",
+ "VK_FORMAT_R8G8B8_UINT",
+ "VK_FORMAT_R8G8B8_SINT",
+ "VK_FORMAT_R8G8B8_SRGB",
+ "VK_FORMAT_B8G8R8_UNORM",
+ "VK_FORMAT_B8G8R8_SNORM",
+ "VK_FORMAT_B8G8R8_USCALED",
+ "VK_FORMAT_B8G8R8_SSCALED",
+ "VK_FORMAT_B8G8R8_UINT",
+ "VK_FORMAT_B8G8R8_SINT",
+ "VK_FORMAT_B8G8R8_SRGB",
+ "VK_FORMAT_R8G8B8A8_UNORM",
+ "VK_FORMAT_R8G8B8A8_SNORM",
+ "VK_FORMAT_R8G8B8A8_USCALED",
+ "VK_FORMAT_R8G8B8A8_SSCALED",
+ "VK_FORMAT_R8G8B8A8_UINT",
+ "VK_FORMAT_R8G8B8A8_SINT",
+ "VK_FORMAT_R8G8B8A8_SRGB",
+ "VK_FORMAT_B8G8R8A8_UNORM",
+ "VK_FORMAT_B8G8R8A8_SNORM",
+ "VK_FORMAT_B8G8R8A8_USCALED",
+ "VK_FORMAT_B8G8R8A8_SSCALED",
+ "VK_FORMAT_B8G8R8A8_UINT",
+ "VK_FORMAT_B8G8R8A8_SINT",
+ "VK_FORMAT_B8G8R8A8_SRGB",
+ "VK_FORMAT_A8B8G8R8_UNORM_PACK32",
+ "VK_FORMAT_A8B8G8R8_SNORM_PACK32",
+ "VK_FORMAT_A8B8G8R8_USCALED_PACK32",
+ "VK_FORMAT_A8B8G8R8_SSCALED_PACK32",
+ "VK_FORMAT_A8B8G8R8_UINT_PACK32",
+ "VK_FORMAT_A8B8G8R8_SINT_PACK32",
+ "VK_FORMAT_A8B8G8R8_SRGB_PACK32",
+ "VK_FORMAT_A2R10G10B10_UNORM_PACK32",
+ "VK_FORMAT_A2R10G10B10_SNORM_PACK32",
+ "VK_FORMAT_A2R10G10B10_USCALED_PACK32",
+ "VK_FORMAT_A2R10G10B10_SSCALED_PACK32",
+ "VK_FORMAT_A2R10G10B10_UINT_PACK32",
+ "VK_FORMAT_A2R10G10B10_SINT_PACK32",
+ "VK_FORMAT_A2B10G10R10_UNORM_PACK32",
+ "VK_FORMAT_A2B10G10R10_SNORM_PACK32",
+ "VK_FORMAT_A2B10G10R10_USCALED_PACK32",
+ "VK_FORMAT_A2B10G10R10_SSCALED_PACK32",
+ "VK_FORMAT_A2B10G10R10_UINT_PACK32",
+ "VK_FORMAT_A2B10G10R10_SINT_PACK32",
+ "VK_FORMAT_R16_UNORM",
+ "VK_FORMAT_R16_SNORM",
+ "VK_FORMAT_R16_USCALED",
+ "VK_FORMAT_R16_SSCALED",
+ "VK_FORMAT_R16_UINT",
+ "VK_FORMAT_R16_SINT",
+ "VK_FORMAT_R16_SFLOAT",
+ "VK_FORMAT_R16G16_UNORM",
+ "VK_FORMAT_R16G16_SNORM",
+ "VK_FORMAT_R16G16_USCALED",
+ "VK_FORMAT_R16G16_SSCALED",
+ "VK_FORMAT_R16G16_UINT",
+ "VK_FORMAT_R16G16_SINT",
+ "VK_FORMAT_R16G16_SFLOAT",
+ "VK_FORMAT_R16G16B16_UNORM",
+ "VK_FORMAT_R16G16B16_SNORM",
+ "VK_FORMAT_R16G16B16_USCALED",
+ "VK_FORMAT_R16G16B16_SSCALED",
+ "VK_FORMAT_R16G16B16_UINT",
+ "VK_FORMAT_R16G16B16_SINT",
+ "VK_FORMAT_R16G16B16_SFLOAT",
+ "VK_FORMAT_R16G16B16A16_UNORM",
+ "VK_FORMAT_R16G16B16A16_SNORM",
+ "VK_FORMAT_R16G16B16A16_USCALED",
+ "VK_FORMAT_R16G16B16A16_SSCALED",
+ "VK_FORMAT_R16G16B16A16_UINT",
+ "VK_FORMAT_R16G16B16A16_SINT",
+ "VK_FORMAT_R16G16B16A16_SFLOAT",
+ "VK_FORMAT_R32_UINT",
+ "VK_FORMAT_R32_SINT",
+ "VK_FORMAT_R32_SFLOAT",
+ "VK_FORMAT_R32G32_UINT",
+ "VK_FORMAT_R32G32_SINT",
+ "VK_FORMAT_R32G32_SFLOAT",
+ "VK_FORMAT_R32G32B32_UINT",
+ "VK_FORMAT_R32G32B32_SINT",
+ "VK_FORMAT_R32G32B32_SFLOAT",
+ "VK_FORMAT_R32G32B32A32_UINT",
+ "VK_FORMAT_R32G32B32A32_SINT",
+ "VK_FORMAT_R32G32B32A32_SFLOAT",
+ "VK_FORMAT_R64_UINT",
+ "VK_FORMAT_R64_SINT",
+ "VK_FORMAT_R64_SFLOAT",
+ "VK_FORMAT_R64G64_UINT",
+ "VK_FORMAT_R64G64_SINT",
+ "VK_FORMAT_R64G64_SFLOAT",
+ "VK_FORMAT_R64G64B64_UINT",
+ "VK_FORMAT_R64G64B64_SINT",
+ "VK_FORMAT_R64G64B64_SFLOAT",
+ "VK_FORMAT_R64G64B64A64_UINT",
+ "VK_FORMAT_R64G64B64A64_SINT",
+ "VK_FORMAT_R64G64B64A64_SFLOAT",
+ "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
+ "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32",
+ "VK_FORMAT_D16_UNORM",
+ "VK_FORMAT_X8_D24_UNORM_PACK32",
+ "VK_FORMAT_D32_SFLOAT",
+ "VK_FORMAT_S8_UINT",
+ "VK_FORMAT_D16_UNORM_S8_UINT",
+ "VK_FORMAT_D24_UNORM_S8_UINT",
+ "VK_FORMAT_D32_SFLOAT_S8_UINT",
+ "VK_FORMAT_BC1_RGB_UNORM_BLOCK",
+ "VK_FORMAT_BC1_RGB_SRGB_BLOCK",
+ "VK_FORMAT_BC1_RGBA_UNORM_BLOCK",
+ "VK_FORMAT_BC1_RGBA_SRGB_BLOCK",
+ "VK_FORMAT_BC2_UNORM_BLOCK",
+ "VK_FORMAT_BC2_SRGB_BLOCK",
+ "VK_FORMAT_BC3_UNORM_BLOCK",
+ "VK_FORMAT_BC3_SRGB_BLOCK",
+ "VK_FORMAT_BC4_UNORM_BLOCK",
+ "VK_FORMAT_BC4_SNORM_BLOCK",
+ "VK_FORMAT_BC5_UNORM_BLOCK",
+ "VK_FORMAT_BC5_SNORM_BLOCK",
+ "VK_FORMAT_BC6H_UFLOAT_BLOCK",
+ "VK_FORMAT_BC6H_SFLOAT_BLOCK",
+ "VK_FORMAT_BC7_UNORM_BLOCK",
+ "VK_FORMAT_BC7_SRGB_BLOCK",
+ "VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK",
+ "VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK",
+ "VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK",
+ "VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK",
+ "VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK",
+ "VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK",
+ "VK_FORMAT_EAC_R11_UNORM_BLOCK",
+ "VK_FORMAT_EAC_R11_SNORM_BLOCK",
+ "VK_FORMAT_EAC_R11G11_UNORM_BLOCK",
+ "VK_FORMAT_EAC_R11G11_SNORM_BLOCK",
+ "VK_FORMAT_ASTC_4x4_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_4x4_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_5x4_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_5x4_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_5x5_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_5x5_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_6x5_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_6x5_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_6x6_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_6x6_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_8x5_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_8x5_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_8x6_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_8x6_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_8x8_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_8x8_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_10x5_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_10x5_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_10x6_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_10x6_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_10x8_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_10x8_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_10x10_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_10x10_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_12x10_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_12x10_SRGB_BLOCK",
+ "VK_FORMAT_ASTC_12x12_UNORM_BLOCK",
+ "VK_FORMAT_ASTC_12x12_SRGB_BLOCK"
+ };
+
+ if (format >= VK_FORMAT_UNDEFINED &&
+ format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK) {
+ return formats[format];
+ }
+
+ static const char * const pvrtc_formats[] = {
+ "VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG",
+ "VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG",
+ "VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG",
+ "VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG",
+ "VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG",
+ "VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG",
+ "VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG",
+ "VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG"
+ };
+
+ if (format >= VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG &&
+ format <= VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG) {
+ return pvrtc_formats[format - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG];
+ }
+
+ static const char * const ycbcr_formats[] = {
+ "VK_FORMAT_G8B8G8R8_422_UNORM_KHR",
+ "VK_FORMAT_B8G8R8G8_422_UNORM_KHR",
+ "VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR",
+ "VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR",
+ "VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR",
+ "VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR",
+ "VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR",
+ "VK_FORMAT_R10X6_UNORM_PACK16_KHR",
+ "VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR",
+ "VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR",
+ "VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR",
+ "VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR",
+ "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR",
+ "VK_FORMAT_R12X4_UNORM_PACK16_KHR",
+ "VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR",
+ "VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR",
+ "VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR",
+ "VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR",
+ "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR",
+ "VK_FORMAT_G16B16G16R16_422_UNORM_KHR",
+ "VK_FORMAT_B16G16R16G16_422_UNORM_KHR",
+ "VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR",
+ "VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR",
+ "VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR",
+ "VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR",
+ "VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR",
+ };
+
+ if (format >= VK_FORMAT_G8B8G8R8_422_UNORM_KHR &&
+ format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR) {
+ return ycbcr_formats[format - VK_FORMAT_G8B8G8R8_422_UNORM_KHR];
+ }
+
+ return QByteArray::number(format);
+}
+
+
+QByteArray enumToString(VkPresentModeKHR mode)
+{
+ static const char * const modes[] = {
+ "VK_PRESENT_MODE_IMMEDIATE_KHR",
+ "VK_PRESENT_MODE_MAILBOX_KHR",
+ "VK_PRESENT_MODE_FIFO_KHR",
+ "VK_PRESENT_MODE_FIFO_RELAXED_KHR"
+ };
+
+ if (mode >= VK_PRESENT_MODE_IMMEDIATE_KHR && mode <= \
VK_PRESENT_MODE_FIFO_RELAXED_KHR) + return modes[mode];
+
+ return QByteArray::number(mode);
+}
+
+
+QByteArray enumToString(VkPhysicalDeviceType physicalDeviceType)
+{
+ static const char * const types[] = {
+ "VK_PHYSICAL_DEVICE_TYPE_OTHER",
+ "VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU",
+ "VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU",
+ "VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU",
+ "VK_PHYSICAL_DEVICE_TYPE_CPU"
+ };
+
+ if (physicalDeviceType >= VK_PHYSICAL_DEVICE_TYPE_OTHER &&
+ physicalDeviceType <= VK_PHYSICAL_DEVICE_TYPE_CPU)
+ return types[physicalDeviceType];
+
+ return QByteArray::number(physicalDeviceType);
+}
+
+
+QByteArray vendorName(uint32_t vendorID)
+{
+ switch (vendorID) {
+ case 0x1002:
+ return QByteArrayLiteral("0x1002 (Advanced Micro Devices, Inc.)");
+ case 0x1010:
+ return QByteArrayLiteral("0x1010 (Imagination Technologies)");
+ case 0x10de:
+ return QByteArrayLiteral("0x10de (NVIDIA Corporation)");
+ case 0x13b5:
+ return QByteArrayLiteral("0x13b5 (ARM Limited)");
+ case 0x14e4:
+ return QByteArrayLiteral("0x14e4 (Broadcom Corporation)");
+ case 0x5143:
+ return QByteArrayLiteral("0x5143 (Qualcomm Technologies, Inc.)");
+ case 0x8086:
+ return QByteArrayLiteral("0x8086 (Intel)");
+ case 0x10001:
+ return QByteArrayLiteral("0x10001 (Vivante Corporation)");
+ case 0x10002:
+ return QByteArrayLiteral("0x10002 (VeriSilicon Holdings Co., Ltd.)");
+ default:
+ return QByteArrayLiteral("0x") + QByteArray::number(vendorID, 16);
+ }
+}
+
+
+QByteArray driverVersionString(uint32_t vendorID, uint32_t driverVersion)
+{
+ QString string;
+ QTextStream stream(&string);
+
+ switch (vendorID) {
+ case 0x1002: // AMD
+ case 0x8086: // Intel
+ stream << VK_VERSION_MAJOR(driverVersion) << '.'
+ << VK_VERSION_MINOR(driverVersion) << '.'
+ << VK_VERSION_PATCH(driverVersion)
+ << " (" << showbase << hex << driverVersion << ')';
+ break;
+ case 0x10de: // NVIDIA
+ stream << (driverVersion >> 22) << '.'
+ << ((driverVersion >> 14) & 0xff) << '.'
+ << ((driverVersion >> 6) & 0xff) << '.'
+ << (driverVersion & 0x3f)
+ << " (" << showbase << hex << driverVersion << ')';
+ break;
+ default:
+ stream << driverVersion << " (" << showbase << hex << driverVersion << ')';
+ break;
+ }
+
+ stream.flush();
+ return string.toUtf8();
+}
+
+} // namespace KWin
diff --git a/libkwineffects/kwinvulkanutils.h b/libkwineffects/kwinvulkanutils.h
new file mode 100644
index 000000000..34d1b24f6
--- /dev/null
+++ b/libkwineffects/kwinvulkanutils.h
@@ -0,0 +1,3528 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright © 2017-2018 Fredrik Höglund <fredrik@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+
+#ifndef KWINVULKANUTILS_H
+#define KWINVULKANUTILS_H
+
+// kwin
+#include <kwinvulkanutils_export.h>
+#include <kwinvulkanutils_funcs.h>
+
+// Qt
+#include <QtCore/QObject>
+#include <QtGui/QMatrix4x4>
+#include <QtGui/QRegion>
+#include <QtGui/QVector4D>
+
+// STL
+#include <memory>
+#include <functional>
+#include <unordered_map>
+
+// xcb
+#include <xcb/xcb.h>
+
+#include <assert.h>
+
+
+namespace KWin {
+
+/**
+ * Helper function that invokes a vulkan entry point with the signature
+ * vkEntryPoint(..., uint32_t *count, T *data), and returns data as an
+ * std::vector<T>(count)
+ */
+template <typename T, typename Func, typename... Args>
+std::vector<T> resultAsVector(Func function, Args&&... params)
+{
+ uint32_t count = 0;
+ function(params..., &count, nullptr);
+
+ std::vector<T> v(count);
+
+ if (count > 0) {
+ function(params..., &count, v.data());
+
+ if (count < v.size())
+ v.resize(count);
+ }
+
+ return v;
+}
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+template <typename T>
+class VulkanArrayProxy
+{
+public:
+ VulkanArrayProxy(std::nullptr_t) noexcept
+ : m_count(0), m_data(nullptr)
+ {}
+
+ VulkanArrayProxy(const T &value) noexcept
+ : m_count(1), m_data(&value)
+ {}
+
+ VulkanArrayProxy(const std::initializer_list<T> &list) noexcept
+ : m_count(list.size()), m_data(list.begin())
+ {}
+
+ VulkanArrayProxy(const std::vector<T> &vector) noexcept
+ : m_count(vector.size()), m_data(vector.data())
+ {}
+
+ VulkanArrayProxy(const QVector<T> &vector) noexcept
+ : m_count(vector.count()), m_data(vector.constData())
+ {}
+
+ VulkanArrayProxy(const QVarLengthArray<T> &array) noexcept
+ : m_count(array.count()), m_data(array.constData())
+ {}
+
+ template <size_t N>
+ VulkanArrayProxy(const std::array<T, N> &array) noexcept
+ : m_count(array.size()), m_data(array.data())
+ {}
+
+ template <size_t N>
+ VulkanArrayProxy(const T (&array)[N]) noexcept
+ : m_count(N), m_data(array)
+ {}
+
+ const T &front() const noexcept { return m_data[0]; }
+ const T &back() const noexcept { return m_data[m_count - 1]; }
+
+ const T *data() const noexcept { return m_data; }
+ const T *constData() const noexcept { return m_data; }
+
+ bool empty() const noexcept { return m_count == 0; }
+ bool isEmpty() const noexcept { return m_count == 0; }
+
+ const T *begin() const noexcept { return m_data; }
+ const T *cbegin() const noexcept { return m_data; }
+
+ const T *end() const noexcept { return m_data + m_count; }
+ const T *cend() const noexcept { return m_data + m_count; }
+
+ uint32_t size() const noexcept { return m_count; }
+ uint32_t count() const noexcept { return m_count; }
+
+private:
+ const uint32_t m_count;
+ const T * const m_data;
+};
+
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class VulkanExtensionVector : public std::vector<VkExtensionProperties>
+{
+public:
+ VulkanExtensionVector() : std::vector<VkExtensionProperties>() {}
+ VulkanExtensionVector(std::vector<VkExtensionProperties> &&other)
+ : std::vector<VkExtensionProperties>(std::move(other)) {}
+
+ bool contains(const char *name) const {
+ return std::any_of(cbegin(), cend(),
+ [=](const VkExtensionProperties &properties) {
+ return strcmp(properties.extensionName, name) == 0;
+ });
+ }
+
+ bool containsAll(const VulkanArrayProxy<const char *> &extensions) const {
+ for (auto extension : extensions) {
+ if (!contains(extension))
+ return false;
+ }
+ return true;
+ }
+};
+
+
+
+class VulkanLayerVector : public std::vector<VkLayerProperties>
+{
+public:
+ VulkanLayerVector() : std::vector<VkLayerProperties>() {}
+ VulkanLayerVector(std::vector<VkLayerProperties> &&other)
+ : std::vector<VkLayerProperties>(std::move(other)) {}
+
+ bool contains(const char *name) const {
+ return std::any_of(cbegin(), cend(),
+ [=](const VkLayerProperties &properties) {
+ return strcmp(properties.layerName, name) == 0;
+ });
+ }
+
+ bool containsAll(const VulkanArrayProxy<const char *> &layers) const {
+ for (auto layer : layers) {
+ if (!contains(layer))
+ return false;
+ }
+ return true;
+ }
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * The base class for all vulkan objects.
+ */
+class KWINVULKANUTILS_EXPORT VulkanObject
+{
+public:
+ virtual ~VulkanObject() {}
+
+protected:
+ VulkanObject() = default;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanPhysicalDevice
+{
+public:
+ typedef VkPhysicalDevice NativeHandleType;
+
+ VulkanPhysicalDevice() : m_physicalDevice(VK_NULL_HANDLE) {}
+ VulkanPhysicalDevice(VkPhysicalDevice device) : m_physicalDevice(device) {}
+ VulkanPhysicalDevice(const VulkanPhysicalDevice &device) : \
m_physicalDevice(device.m_physicalDevice) {} +
+ VulkanPhysicalDevice &operator = (const VulkanPhysicalDevice &other) {
+ m_physicalDevice = other.m_physicalDevice;
+ return *this;
+ }
+
+ VulkanPhysicalDevice &operator = (VkPhysicalDevice device) {
+ m_physicalDevice = device;
+ return *this;
+ }
+
+ operator VkPhysicalDevice () const { return m_physicalDevice; }
+
+ VkPhysicalDevice handle() const { return m_physicalDevice; }
+
+ bool isValid() const { return m_physicalDevice != VK_NULL_HANDLE; }
+
+ void getFeatures(VkPhysicalDeviceFeatures *pFeatures) {
+ vkGetPhysicalDeviceFeatures(m_physicalDevice, pFeatures);
+ }
+
+ void getFormatProperties(VkFormat format, VkFormatProperties *pFormatProperties) \
{ + vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, \
pFormatProperties); + }
+
+ VkResult getImageFormatProperties(VkFormat format, VkImageType type, \
VkImageTiling tiling, + VkImageUsageFlags usage, \
VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties) { + \
return vkGetPhysicalDeviceImageFormatProperties(m_physicalDevice, format, type, \
tiling, usage, flags, pImageFormatProperties); + }
+
+ void getProperties(VkPhysicalDeviceProperties *pProperties) {
+ vkGetPhysicalDeviceProperties(m_physicalDevice, pProperties);
+ }
+
+ void getQueueFamilyProperties(uint32_t *pQueueFamilyPropertyCount, \
VkQueueFamilyProperties *pQueueFamilyProperties) { + \
vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, pQueueFamilyPropertyCount, \
pQueueFamilyProperties); + }
+
+ std::vector<VkQueueFamilyProperties> getQueueFamilyProperties() {
+ return resultAsVector<VkQueueFamilyProperties>(vkGetPhysicalDeviceQueueFamilyProperties, \
m_physicalDevice); + }
+
+ void getMemoryProperties(VkPhysicalDeviceMemoryProperties *pMemoryProperties) {
+ vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, pMemoryProperties);
+ }
+
+ VkResult createDevice(const VkDeviceCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { + return \
vkCreateDevice(m_physicalDevice, pCreateInfo, pAllocator, pDevice); + }
+
+ VkResult enumerateDeviceExtensionProperties(const char *pLayerName, uint32_t \
*pPropertyCount, VkExtensionProperties *pProperties) { + return \
vkEnumerateDeviceExtensionProperties(m_physicalDevice, pLayerName, pPropertyCount, \
pProperties); + }
+
+ VulkanExtensionVector enumerateDeviceExtensionProperties(const char *pLayerName \
= nullptr) { + return \
resultAsVector<VkExtensionProperties>(vkEnumerateDeviceExtensionProperties, \
m_physicalDevice, pLayerName); + }
+
+ // Deprecated
+ VkResult enumerateDeviceLayerProperties(uint32_t *pPropertyCount, \
VkLayerProperties *pProperties) { + return \
vkEnumerateDeviceLayerProperties(m_physicalDevice, pPropertyCount, pProperties); + \
} +
+ void getSparseImageFormatProperties(VkFormat format, VkImageType type, \
VkSampleCountFlagBits samples, VkImageUsageFlags usage, + \
VkImageTiling tiling, uint32_t *pPropertyCount, VkSparseImageFormatProperties \
*pProperties) { + \
vkGetPhysicalDeviceSparseImageFormatProperties(m_physicalDevice, format, type, \
samples, usage, tiling, pPropertyCount, pProperties); + }
+
+ std::vector<VkSparseImageFormatProperties> \
getSparseImageFormatProperties(VkFormat format, VkImageType type, \
VkSampleCountFlagBits samples, + \
VkImageUsageFlags usage, VkImageTiling tiling) { + return \
resultAsVector<VkSparseImageFormatProperties>(vkGetPhysicalDeviceSparseImageFormatProperties, \
m_physicalDevice, + \
format, type, samples, usage, tiling); + }
+
+ VkResult getSurfaceSupportKHR(uint32_t queueFamilyIndex, VkSurfaceKHR surface, \
VkBool32 *pSupported) { + return \
pfnGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, queueFamilyIndex, surface, \
pSupported); + }
+
+ VkResult getSurfaceCapabilitiesKHR(VkSurfaceKHR surface, \
VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) { + return \
pfnGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, surface, \
pSurfaceCapabilities); + }
+
+ VkResult getSurfaceFormatsKHR(VkSurfaceKHR surface, uint32_t \
*pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats) { + return \
pfnGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, surface, pSurfaceFormatCount, \
pSurfaceFormats); + }
+
+ std::vector<VkSurfaceFormatKHR> getSurfaceFormatsKHR(VkSurfaceKHR surface) {
+ return resultAsVector<VkSurfaceFormatKHR>(pfnGetPhysicalDeviceSurfaceFormatsKHR, \
m_physicalDevice, surface); + }
+
+ VkResult getSurfacePresentModesKHR(VkSurfaceKHR surface, uint32_t \
*pPresentModeCount, VkPresentModeKHR *pPresentModes) { + return \
pfnGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, surface, \
pPresentModeCount, pPresentModes); + }
+
+ std::vector<VkPresentModeKHR> getSurfacePresentModesKHR(VkSurfaceKHR surface) {
+ return resultAsVector<VkPresentModeKHR>(pfnGetPhysicalDeviceSurfacePresentModesKHR, \
m_physicalDevice, surface); + }
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+ VkBool32 getXcbPresentationSupportKHR(uint32_t queueFamilyIndex, \
xcb_connection_t *connection, xcb_visualid_t visual_id) { + return \
pfnGetPhysicalDeviceXcbPresentationSupportKHR(m_physicalDevice, queueFamilyIndex, \
connection, visual_id); + }
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ VkBool32 getWaylandPresentationSupportKHR(uint32_t queueFamilyIndex, struct \
wl_display *display) { + return \
pfnGetPhysicalDeviceWaylandPresentationSupportKHR(m_physicalDevice, queueFamilyIndex, \
display); + }
+#endif
+
+ // VK_KHR_get_physical_device_properties2
+ void getFeatures2KHR(VkPhysicalDeviceFeatures2KHR *pFeatures) {
+ pfnGetPhysicalDeviceFeatures2KHR(m_physicalDevice, pFeatures);
+ }
+
+ void getProperties2KHR(VkPhysicalDeviceProperties2KHR *pProperties) {
+ pfnGetPhysicalDeviceProperties2KHR(m_physicalDevice, pProperties);
+ }
+
+ void getFormatProperties2KHR(VkFormat format, VkFormatProperties2KHR \
*pFormatProperties) { + \
pfnGetPhysicalDeviceFormatProperties2KHR(m_physicalDevice, format, \
pFormatProperties); + }
+
+ VkResult getImageFormatProperties2KHR(const VkPhysicalDeviceImageFormatInfo2KHR \
*pImageFormatInfo, VkImageFormatProperties2KHR *pImageFormatProperties) { + \
return pfnGetPhysicalDeviceImageFormatProperties2KHR(m_physicalDevice, \
pImageFormatInfo, pImageFormatProperties); + }
+
+ void getQueueFamilyProperties2KHR(uint32_t *pQueueFamilyPropertyCount, \
VkQueueFamilyProperties2KHR *pQueueFamilyProperties) { + \
pfnGetPhysicalDeviceQueueFamilyProperties2KHR(m_physicalDevice, \
pQueueFamilyPropertyCount, pQueueFamilyProperties); + }
+
+ void getMemoryProperties2KHR(VkPhysicalDeviceMemoryProperties2KHR* \
pMemoryProperties) { + \
pfnGetPhysicalDeviceMemoryProperties2KHR(m_physicalDevice, pMemoryProperties); + }
+
+ void getSparseImageFormatProperties2KHR(const \
VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, + \
uint32_t *pPropertyCount, VkSparseImageFormatProperties2KHR *pProperties) { + \
pfnGetPhysicalDeviceSparseImageFormatProperties2KHR(m_physicalDevice, pFormatInfo, \
pPropertyCount, pProperties); + }
+
+ std::vector<VkSparseImageFormatProperties2KHR> \
getSparseImageFormatProperties2KHR(const VkPhysicalDeviceSparseImageFormatInfo2KHR \
*pFormatInfo) { + return \
resultAsVector<VkSparseImageFormatProperties2KHR>(pfnGetPhysicalDeviceSparseImageFormatProperties2KHR, \
m_physicalDevice, pFormatInfo); + }
+
+ void getExternalBufferPropertiesKHR(const VkPhysicalDeviceExternalBufferInfoKHR \
*pExternalBufferInfo, VkExternalBufferPropertiesKHR *pExternalBufferProperties) { + \
pfnGetPhysicalDeviceExternalBufferPropertiesKHR(m_physicalDevice, \
pExternalBufferInfo, pExternalBufferProperties); + }
+
+ void getExternalSemaphorePropertiesKHR(const \
VkPhysicalDeviceExternalSemaphoreInfoKHR *pExternalSemaphoreInfo, + \
VkExternalSemaphorePropertiesKHR *pExternalSemaphoreProperties) { + \
pfnGetPhysicalDeviceExternalSemaphorePropertiesKHR(m_physicalDevice, \
pExternalSemaphoreInfo, pExternalSemaphoreProperties); + }
+
+private:
+ VkPhysicalDevice m_physicalDevice;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanInstance
+{
+public:
+ typedef VkInstance NativeHandleType;
+
+ VulkanInstance() : m_instance(VK_NULL_HANDLE) {}
+
+ VulkanInstance(const VkApplicationInfo &applicationInfo,
+ const VulkanArrayProxy<const char *> &enabledLayers = {},
+ const VulkanArrayProxy<const char *> &enabledExtensions = {})
+ : m_instance(VK_NULL_HANDLE)
+ {
+ const VkInstanceCreateInfo createInfo {
+ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .pApplicationInfo = &applicationInfo,
+ .enabledLayerCount = enabledLayers.count(),
+ .ppEnabledLayerNames = enabledLayers.data(),
+ .enabledExtensionCount = enabledExtensions.size(),
+ .ppEnabledExtensionNames = enabledExtensions.data(),
+ };
+
+ vkCreateInstance(&createInfo, nullptr, &m_instance);
+ }
+
+ VulkanInstance(const VulkanInstance &other) = delete;
+
+ VulkanInstance(VulkanInstance &&other)
+ : m_instance(other.m_instance)
+ {
+ other.m_instance = VK_NULL_HANDLE;
+ }
+
+ ~VulkanInstance() {
+ if (m_instance)
+ vkDestroyInstance(m_instance, nullptr);
+ }
+
+ static VulkanExtensionVector supportedExtensions() {
+ return resultAsVector<VkExtensionProperties>(vkEnumerateInstanceExtensionProperties, \
nullptr); + }
+
+ static VulkanLayerVector supportedLayers() {
+ return resultAsVector<VkLayerProperties>(vkEnumerateInstanceLayerProperties);
+ }
+
+ VulkanInstance &operator = (const VulkanInstance &other) = delete;
+
+ VulkanInstance &operator = (VulkanInstance &&other) {
+ if (m_instance)
+ vkDestroyInstance(m_instance, nullptr);
+
+ m_instance = other.m_instance;
+ other.m_instance = VK_NULL_HANDLE;
+ return *this;
+ }
+
+ operator VkInstance () const { return m_instance; }
+ VkInstance handle() const { return m_instance; }
+
+ bool isValid() const { return m_instance != VK_NULL_HANDLE; }
+
+ std::vector<VulkanPhysicalDevice> enumeratePhysicalDevices() const {
+ static_assert(sizeof(VulkanPhysicalDevice) == sizeof(VkPhysicalDevice));
+
+ uint32_t count = 0;
+ vkEnumeratePhysicalDevices(m_instance, &count, nullptr);
+
+ std::vector<VulkanPhysicalDevice> devices(count);
+ vkEnumeratePhysicalDevices(m_instance, &count, \
reinterpret_cast<VkPhysicalDevice *>(devices.data())); +
+ return devices;
+ }
+
+ PFN_vkVoidFunction getProcAddress(const char *name) const {
+ return vkGetInstanceProcAddr(m_instance, name);
+ }
+
+ void destroySurfaceKHR(VkSurfaceKHR surface, const VkAllocationCallbacks \
*pAllocator = nullptr) { + pfnDestroySurfaceKHR(m_instance, surface, \
pAllocator); + }
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+ VkResult createXcbSurfaceKHR(const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkSurfaceKHR *pSurface) {
+ return pfnCreateXcbSurfaceKHR(m_instance, pCreateInfo, pAllocator, \
pSurface); + }
+
+ VkResult createXcbSurfaceKHR(const VkXcbSurfaceCreateInfoKHR &createInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkSurfaceKHR *pSurface) {
+ return pfnCreateXcbSurfaceKHR(m_instance, &createInfo, pAllocator, \
pSurface); + }
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ VkResult createWaylandSurfaceKHR(const VkWaylandSurfaceCreateInfoKHR \
*pCreateInfo, + const VkAllocationCallbacks \
*pAllocator, + VkSurfaceKHR *pSurface) {
+ return pfnCreateWaylandSurfaceKHR(m_instance, pCreateInfo, pAllocator, \
pSurface); + }
+
+ VkResult createWaylandSurfaceKHR(const VkWaylandSurfaceCreateInfoKHR \
&createInfo, + const VkAllocationCallbacks \
*pAllocator, + VkSurfaceKHR *pSurface) {
+ return pfnCreateWaylandSurfaceKHR(m_instance, &createInfo, pAllocator, \
pSurface); + }
+#endif
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+ VkResult createAndroidSurfaceKHR(const VkAndroidSurfaceCreateInfoKHR \
*pCreateInfo, + const VkAllocationCallbacks \
*pAllocator, + VkSurfaceKHR* pSurface) {
+ return pfnCreateAndroidSurfaceKHR(m_instance, pCreateInfo, pAllocator, \
pSurface); + }
+
+ VkResult createAndroidSurfaceKHR(const VkAndroidSurfaceCreateInfoKHR \
&createInfo, + const VkAllocationCallbacks \
*pAllocator, + VkSurfaceKHR* pSurface) {
+ return pfnCreateAndroidSurfaceKHR(m_instance, &createInfo, pAllocator, \
pSurface); + }
+#endif
+
+ VkResult createDebugReportCallbackEXT(const VkDebugReportCallbackCreateInfoEXT \
*pCreateInfo, + const VkAllocationCallbacks \
*pAllocator, + VkDebugReportCallbackEXT \
*pCallback) { + return pfnCreateDebugReportCallbackEXT(m_instance, \
pCreateInfo, pAllocator, pCallback); + }
+
+ VkResult createDebugReportCallbackEXT(const VkDebugReportCallbackCreateInfoEXT \
&createInfo, + const VkAllocationCallbacks \
*pAllocator, + VkDebugReportCallbackEXT \
*pCallback) { + return pfnCreateDebugReportCallbackEXT(m_instance, \
&createInfo, pAllocator, pCallback); + }
+
+ void destroyDebugReportCallbackEXT(VkDebugReportCallbackEXT callback, const \
VkAllocationCallbacks *pAllocator) { + \
pfnDestroyDebugReportCallbackEXT(m_instance, callback, pAllocator); + }
+
+ void debugReportMessageEXT(VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char *pLayerPrefix,
+ const char *pMessage) {
+ pfnDebugReportMessageEXT(m_instance, flags, objectType, object, location, \
messageCode, pLayerPrefix, pMessage); + }
+
+private:
+ VkInstance m_instance;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class VulkanDebugReportCallback
+{
+public:
+ typedef VkDebugReportCallbackEXT NativeHandleType;
+
+ VulkanDebugReportCallback()
+ : m_instance(VK_NULL_HANDLE),
+ m_callback(VK_NULL_HANDLE)
+ {
+ }
+
+ VulkanDebugReportCallback(VulkanInstance &instance, VkDebugReportFlagsEXT flags, \
PFN_vkDebugReportCallbackEXT pfnCallback, void *pUserData = nullptr) + : \
m_instance(instance), + m_callback(VK_NULL_HANDLE)
+ {
+ const VkDebugReportCallbackCreateInfoEXT createInfo = {
+ .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
+ .pNext = nullptr,
+ .flags = flags,
+ .pfnCallback = pfnCallback,
+ .pUserData = pUserData
+ };
+
+ instance.createDebugReportCallbackEXT(&createInfo, nullptr, &m_callback);
+ }
+
+ VulkanDebugReportCallback(VulkanInstance &instance, const \
VkDebugReportCallbackCreateInfoEXT *pCreateInfo) + : m_instance(instance),
+ m_callback(VK_NULL_HANDLE)
+ {
+ instance.createDebugReportCallbackEXT(pCreateInfo, nullptr, &m_callback);
+ }
+
+ VulkanDebugReportCallback(VulkanInstance &instance, const \
VkDebugReportCallbackCreateInfoEXT &createInfo) + : m_instance(instance),
+ m_callback(VK_NULL_HANDLE)
+ {
+ instance.createDebugReportCallbackEXT(&createInfo, nullptr, &m_callback);
+ }
+
+ VulkanDebugReportCallback(const VulkanDebugReportCallback &other) = delete;
+
+ VulkanDebugReportCallback(VulkanDebugReportCallback &&other)
+ : m_instance(other.m_instance),
+ m_callback(other.m_callback)
+ {
+ other.m_instance = VK_NULL_HANDLE;
+ other.m_callback = VK_NULL_HANDLE;
+ }
+
+ ~VulkanDebugReportCallback() {
+ if (m_callback)
+ pfnDestroyDebugReportCallbackEXT(m_instance, m_callback, nullptr);
+ }
+
+ VkDebugReportCallbackEXT handle() const { return m_callback; }
+
+ operator VkDebugReportCallbackEXT () const { return m_callback; }
+
+ VulkanDebugReportCallback &operator = (const VulkanDebugReportCallback &other) = \
delete; +
+ VulkanDebugReportCallback &operator = (VulkanDebugReportCallback &&other)
+ {
+ if (m_callback)
+ pfnDestroyDebugReportCallbackEXT(m_instance, m_callback, nullptr);
+
+ m_instance = other.m_instance;
+ m_callback = other.m_callback;
+
+ other.m_instance = VK_NULL_HANDLE;
+ other.m_callback = VK_NULL_HANDLE;
+ return *this;
+ }
+
+private:
+ VkInstance m_instance;
+ VkDebugReportCallbackEXT m_callback;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class VulkanQueue;
+
+
+/**
+ * Represents a logical device.
+ */
+class KWINVULKANUTILS_EXPORT VulkanDevice
+{
+public:
+ typedef VkDevice NativeHandleType;
+
+ VulkanDevice()
+ : m_physicalDevice(VK_NULL_HANDLE),
+ m_device(VK_NULL_HANDLE)
+ {
+ }
+
+ VulkanDevice(VulkanPhysicalDevice physicalDevice, const VkDeviceCreateInfo \
&createInfo, const VkAllocationCallbacks *pAllocator = nullptr) + : \
m_physicalDevice(physicalDevice), + m_device(VK_NULL_HANDLE)
+ {
+ vkCreateDevice(physicalDevice, &createInfo, pAllocator, &m_device);
+ }
+
+ VulkanDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo \
*pCreateInfo, const VkAllocationCallbacks *pAllocator = nullptr) + : \
m_physicalDevice(physicalDevice), + m_device(VK_NULL_HANDLE)
+ {
+ vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, &m_device);
+ }
+
+ VulkanDevice(const VulkanDevice &other) = delete;
+
+ VulkanDevice(VulkanDevice &&other)
+ : m_physicalDevice(other.m_physicalDevice),
+ m_device(other.m_device)
+ {
+ other.m_physicalDevice = VK_NULL_HANDLE;
+ other.m_device = VK_NULL_HANDLE;
+ }
+
+ ~VulkanDevice() {
+ if (m_device)
+ vkDestroyDevice(m_device, nullptr);
+ }
+
+ operator VkDevice () const { return m_device; }
+
+ VulkanDevice &operator = (const VulkanDevice &other) = delete;
+
+ VulkanDevice &operator = (VulkanDevice &&other) {
+ if (m_device)
+ vkDestroyDevice(m_device, nullptr);
+
+ m_physicalDevice = other.m_physicalDevice;
+ m_device = other.m_device;
+
+ other.m_physicalDevice = VK_NULL_HANDLE;
+ other.m_device = VK_NULL_HANDLE;
+
+ return *this;
+ }
+
+ bool isValid() const { return m_device != VK_NULL_HANDLE; }
+
+ VulkanPhysicalDevice physicalDevice() const { return m_physicalDevice; }
+ VkDevice handle() const { return m_device; }
+
+ PFN_vkVoidFunction getProcAddress(const char *pName) {
+ return vkGetDeviceProcAddr(m_device, pName);
+ }
+
+ void getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) {
+ vkGetDeviceQueue(m_device, queueFamilyIndex, queueIndex, pQueue);
+ }
+
+ VulkanQueue getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex);
+
+ void waitIdle() {
+ vkDeviceWaitIdle(m_device);
+ }
+
+ VkResult allocateMemory(const VkMemoryAllocateInfo *pAllocateInfo, const \
VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) { + return \
vkAllocateMemory(m_device, pAllocateInfo, pAllocator, pMemory); + }
+
+ void freeMemory(VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator = \
nullptr) { + vkFreeMemory(m_device, memory, pAllocator);
+ }
+
+ VkResult mapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize \
size, VkMemoryMapFlags flags, void **ppData) { + return vkMapMemory(m_device, \
memory, offset, size, flags, ppData); + }
+
+ void unmapMemory(VkDeviceMemory memory) {
+ vkUnmapMemory(m_device, memory);
+ }
+
+ VkResult flushMappedMemoryRanges(uint32_t memoryRangeCount, const \
VkMappedMemoryRange *pMemoryRanges) { + return \
vkFlushMappedMemoryRanges(m_device, memoryRangeCount, pMemoryRanges); + }
+
+ VkResult flushMappedMemoryRanges(const VulkanArrayProxy<VkMappedMemoryRange> \
&memoryRanges) { + return vkFlushMappedMemoryRanges(m_device, \
memoryRanges.count(), memoryRanges.data()); + }
+
+ VkResult invalidateMappedMemoryRanges(uint32_t memoryRangeCount, const \
VkMappedMemoryRange *pMemoryRanges) { + return \
vkInvalidateMappedMemoryRanges(m_device, memoryRangeCount, pMemoryRanges); + }
+
+ VkResult invalidateMappedMemoryRanges(const \
VulkanArrayProxy<VkMappedMemoryRange> &memoryRanges) { + return \
vkInvalidateMappedMemoryRanges(m_device, memoryRanges.count(), memoryRanges.data()); \
+ } +
+ void getMemoryCommitment(VkDeviceMemory memory, VkDeviceSize \
*pCommittedMemoryInBytes) { + vkGetDeviceMemoryCommitment(m_device, memory, \
pCommittedMemoryInBytes); + }
+
+ VkResult bindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize \
memoryOffset) { + return vkBindBufferMemory(m_device, buffer, memory, \
memoryOffset); + }
+
+ VkResult bindImageMemory(VkImage image, VkDeviceMemory memory, VkDeviceSize \
memoryOffset) { + return vkBindImageMemory(m_device, image, memory, \
memoryOffset); + }
+
+ // VK_KHR_bind_memory2
+ void bindBufferMemory2KHR(uint32_t bindInfoCount, const \
VkBindBufferMemoryInfoKHR* pBindInfos) { + pfnBindBufferMemory2KHR(m_device, \
bindInfoCount, pBindInfos); + }
+
+ void bindBufferMemory2KHR(const VulkanArrayProxy<VkBindBufferMemoryInfoKHR> \
&bindInfos) { + pfnBindBufferMemory2KHR(m_device, bindInfos.count(), \
bindInfos.data()); + }
+
+ void bindImageMemory2KHR(uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* \
pBindInfos) { + pfnBindImageMemory2KHR(m_device, bindInfoCount, pBindInfos);
+ }
+
+ void bindImageMemory2KHR(const VulkanArrayProxy<VkBindImageMemoryInfoKHR> \
&bindInfos) { + pfnBindImageMemory2KHR(m_device, bindInfos.count(), \
bindInfos.data()); + }
+
+ void getBufferMemoryRequirements(VkBuffer buffer, VkMemoryRequirements \
*pMemoryRequirements) { + vkGetBufferMemoryRequirements(m_device, buffer, \
pMemoryRequirements); + }
+
+ void getImageMemoryRequirements(VkImage image, VkMemoryRequirements \
*pMemoryRequirements) { + vkGetImageMemoryRequirements(m_device, image, \
pMemoryRequirements); + }
+
+ void getImageSparseMemoryRequirements(VkImage image, uint32_t \
*pSparseMemoryRequirementCount, + \
VkSparseImageMemoryRequirements *pSparseMemoryRequirements) { + \
vkGetImageSparseMemoryRequirements(m_device, image, pSparseMemoryRequirementCount, \
pSparseMemoryRequirements); + }
+
+ // VK_KHR_get_memory_requirements2
+ void getImageMemoryRequirements2KHR(const VkImageMemoryRequirementsInfo2KHR \
*pInfo, VkMemoryRequirements2KHR *pMemoryRequirements) { + \
pfnGetImageMemoryRequirements2KHR(m_device, pInfo, pMemoryRequirements); + }
+
+ void getImageMemoryRequirements2KHR(const VkImageMemoryRequirementsInfo2KHR \
&info, VkMemoryRequirements2KHR *pMemoryRequirements) { + \
pfnGetImageMemoryRequirements2KHR(m_device, &info, pMemoryRequirements); + }
+
+ void getBufferMemoryRequirements2KHR(const VkBufferMemoryRequirementsInfo2KHR \
*pInfo, VkMemoryRequirements2KHR *pMemoryRequirements) { + \
pfnGetBufferMemoryRequirements2KHR(m_device, pInfo, pMemoryRequirements); + }
+
+ void getBufferMemoryRequirements2KHR(const VkBufferMemoryRequirementsInfo2KHR \
&info, VkMemoryRequirements2KHR *pMemoryRequirements) { + \
pfnGetBufferMemoryRequirements2KHR(m_device, &info, pMemoryRequirements); + }
+
+ void getImageSparseMemoryRequirements2KHR(const \
VkImageSparseMemoryRequirementsInfo2KHR *pInfo, + \
uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2KHR \
*pSparseMemoryRequirements) { + \
pfnGetImageSparseMemoryRequirements2KHR(m_device, pInfo, \
pSparseMemoryRequirementCount, pSparseMemoryRequirements); + }
+
+ void getImageSparseMemoryRequirements2KHR(const \
VkImageSparseMemoryRequirementsInfo2KHR &info, uint32_t \
*pSparseMemoryRequirementCount, + \
VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements) { + \
pfnGetImageSparseMemoryRequirements2KHR(m_device, &info, \
pSparseMemoryRequirementCount, pSparseMemoryRequirements); + }
+
+ VkResult createFence(const VkFenceCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkFence *pFence) { + return \
vkCreateFence(m_device, pCreateInfo, pAllocator, pFence); + }
+
+ void destroyFence(VkFence fence, const VkAllocationCallbacks *pAllocator = \
nullptr) { + vkDestroyFence(m_device, fence, pAllocator);
+ }
+
+ VkResult resetFences(uint32_t fenceCount, const VkFence *pFences) {
+ return vkResetFences(m_device, fenceCount, pFences);
+ }
+
+ VkResult getFenceStatus(VkFence fence) {
+ return vkGetFenceStatus(m_device, fence);
+ }
+
+ VkResult waitForFences(uint32_t fenceCount, const VkFence *pFences, VkBool32 \
waitAll = VK_TRUE, uint64_t timeout = UINT64_MAX) { + return \
vkWaitForFences(m_device, fenceCount, pFences, waitAll, timeout); + }
+
+ VkResult createSemaphore(const VkSemaphoreCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) { + return \
vkCreateSemaphore(m_device, pCreateInfo, pAllocator, pSemaphore); + }
+
+ void destroySemaphore(VkSemaphore semaphore, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroySemaphore(m_device, semaphore, \
pAllocator); + }
+
+ VkResult createEvent(const VkEventCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkEvent *pEvent) { + return \
vkCreateEvent(m_device, pCreateInfo, pAllocator, pEvent); + }
+
+ void destroyEvent(VkEvent event, const VkAllocationCallbacks *pAllocator = \
nullptr) { + vkDestroyEvent(m_device, event, pAllocator);
+ }
+
+ VkResult getEventStatus(VkEvent event) {
+ return vkGetEventStatus(m_device, event);
+ }
+
+ VkResult setEvent(VkEvent event) {
+ return vkSetEvent(m_device, event);
+ }
+
+ VkResult resetEvent(VkEvent event) {
+ return vkResetEvent(m_device, event);
+ }
+
+ VkResult createQueryPool(const VkQueryPoolCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) { + return \
vkCreateQueryPool(m_device, pCreateInfo, pAllocator, pQueryPool); + }
+
+ void destroyQueryPool(VkQueryPool queryPool, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroyQueryPool(m_device, queryPool, \
pAllocator); + }
+
+ VkResult getQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, \
uint32_t queryCount, + size_t dataSize, void *pData, \
VkDeviceSize stride, VkQueryResultFlags flags) { + return \
vkGetQueryPoolResults(m_device, queryPool, firstQuery, queryCount, dataSize, pData, \
stride, flags); + }
+
+ VkResult createBuffer(const VkBufferCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) { + return \
vkCreateBuffer(m_device, pCreateInfo, pAllocator, pBuffer); + }
+
+ void destroyBuffer(VkBuffer buffer, const VkAllocationCallbacks *pAllocator = \
nullptr) { + vkDestroyBuffer(m_device, buffer, pAllocator);
+ }
+
+ VkResult createBufferView(const VkBufferViewCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkBufferView *pView) { + return \
vkCreateBufferView(m_device, pCreateInfo, pAllocator, pView); + }
+
+ void destroyBufferView(VkBufferView bufferView, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroyBufferView(m_device, bufferView, \
pAllocator); + }
+
+ VkResult createImage(const VkImageCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkImage *pImage) { + return \
vkCreateImage(m_device, pCreateInfo, pAllocator, pImage); + }
+
+ void destroyImage(VkImage image, const VkAllocationCallbacks *pAllocator = \
nullptr) { + vkDestroyImage(m_device, image, pAllocator);
+ }
+
+ void getImageSubresourceLayout(VkImage image, const VkImageSubresource \
*pSubresource, VkSubresourceLayout *pLayout) { + \
vkGetImageSubresourceLayout(m_device, image, pSubresource, pLayout); + }
+
+ VkResult createImageView(const VkImageViewCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkImageView *pView) { + return \
vkCreateImageView(m_device, pCreateInfo, pAllocator, pView); + }
+
+ void destroyImageView(VkImageView imageView, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroyImageView(m_device, imageView, \
pAllocator); + }
+
+ VkResult createShaderModule(const VkShaderModuleCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) { + return \
vkCreateShaderModule(m_device, pCreateInfo, pAllocator, pShaderModule); + }
+
+ void destroyShaderModule(VkShaderModule shaderModule, const \
VkAllocationCallbacks *pAllocator = nullptr) { + \
vkDestroyShaderModule(m_device, shaderModule, pAllocator); + }
+
+ VkResult createPipelineCache(const VkPipelineCacheCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) { + return \
vkCreatePipelineCache(m_device, pCreateInfo, pAllocator, pPipelineCache); + }
+
+ VkResult createPipelineCache(const VkPipelineCacheCreateInfo &createInfo, const \
VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) { + return \
vkCreatePipelineCache(m_device, &createInfo, pAllocator, pPipelineCache); + }
+
+ void destroyPipelineCache(VkPipelineCache pipelineCache, const \
VkAllocationCallbacks *pAllocator = nullptr) { + \
vkDestroyPipelineCache(m_device, pipelineCache, pAllocator); + }
+
+ VkResult getPipelineCacheData(VkPipelineCache pipelineCache, size_t *pDataSize, \
void *pData) { + return vkGetPipelineCacheData(m_device, pipelineCache, \
pDataSize, pData); + }
+
+ VkResult mergePipelineCaches(VkPipelineCache dstCache, uint32_t srcCacheCount, \
const VkPipelineCache *pSrcCaches) { + return vkMergePipelineCaches(m_device, \
dstCache, srcCacheCount, pSrcCaches); + }
+
+ VkResult createGraphicsPipelines(VkPipelineCache pipelineCache, uint32_t \
createInfoCount, const VkGraphicsPipelineCreateInfo *pCreateInfos, + \
const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { + return \
vkCreateGraphicsPipelines(m_device, pipelineCache, createInfoCount, pCreateInfos, \
pAllocator, pPipelines); + }
+
+ VkResult createComputePipelines(VkPipelineCache pipelineCache, uint32_t \
createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, + \
const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { + return \
vkCreateComputePipelines(m_device, pipelineCache, createInfoCount, pCreateInfos, \
pAllocator, pPipelines); + }
+
+ void destroyPipeline(VkPipeline pipeline, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroyPipeline(m_device, pipeline, pAllocator);
+ }
+
+ VkResult createPipelineLayout(const VkPipelineLayoutCreateInfo *pCreateInfo, \
const VkAllocationCallbacks *pAllocator, + \
VkPipelineLayout *pPipelineLayout) { + return vkCreatePipelineLayout(m_device, \
pCreateInfo, pAllocator, pPipelineLayout); + }
+
+ VkResult createPipelineLayout(const VkPipelineLayoutCreateInfo &createInfo, \
const VkAllocationCallbacks *pAllocator, + \
VkPipelineLayout *pPipelineLayout) { + return vkCreatePipelineLayout(m_device, \
&createInfo, pAllocator, pPipelineLayout); + }
+
+ void destroyPipelineLayout(VkPipelineLayout pipelineLayout, const \
VkAllocationCallbacks *pAllocator = nullptr) { + \
vkDestroyPipelineLayout(m_device, pipelineLayout, pAllocator); + }
+
+ VkResult createSampler(const VkSamplerCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkSampler *pSampler) { + return \
vkCreateSampler(m_device, pCreateInfo, pAllocator, pSampler); + }
+
+ void destroySampler(VkSampler sampler, const VkAllocationCallbacks *pAllocator = \
nullptr) { + vkDestroySampler(m_device, sampler, pAllocator);
+ }
+
+ VkResult createDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo \
*pCreateInfo, const VkAllocationCallbacks *pAllocator, + \
VkDescriptorSetLayout *pSetLayout) { + return \
vkCreateDescriptorSetLayout(m_device, pCreateInfo, pAllocator, pSetLayout); + }
+
+ VkResult createDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo \
&createInfo, const VkAllocationCallbacks *pAllocator, + \
VkDescriptorSetLayout *pSetLayout) { + return \
vkCreateDescriptorSetLayout(m_device, &createInfo, pAllocator, pSetLayout); + }
+
+ void destroyDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout, const \
VkAllocationCallbacks *pAllocator = nullptr) { + \
vkDestroyDescriptorSetLayout(m_device, descriptorSetLayout, pAllocator); + }
+
+ VkResult createDescriptorPool(const VkDescriptorPoolCreateInfo *pCreateInfo, \
const VkAllocationCallbacks *pAllocator, + \
VkDescriptorPool *pDescriptorPool) { + return vkCreateDescriptorPool(m_device, \
pCreateInfo, pAllocator, pDescriptorPool); + }
+
+ void destroyDescriptorPool(VkDescriptorPool descriptorPool, const \
VkAllocationCallbacks *pAllocator = nullptr) { + \
vkDestroyDescriptorPool(m_device, descriptorPool, pAllocator); + }
+
+ VkResult resetDescriptorPool(VkDescriptorPool descriptorPool, \
VkDescriptorPoolResetFlags flags) { + return vkResetDescriptorPool(m_device, \
descriptorPool, flags); + }
+
+ VkResult allocateDescriptorSets(const VkDescriptorSetAllocateInfo \
*pAllocateInfo, VkDescriptorSet *pDescriptorSets) { + return \
vkAllocateDescriptorSets(m_device, pAllocateInfo, pDescriptorSets); + }
+
+ VkResult freeDescriptorSets(VkDescriptorPool descriptorPool, uint32_t \
descriptorSetCount, const VkDescriptorSet *pDescriptorSets) { + return \
vkFreeDescriptorSets(m_device, descriptorPool, descriptorSetCount, pDescriptorSets); \
+ } +
+ void updateDescriptorSets(uint32_t descriptorWriteCount, const \
VkWriteDescriptorSet *pDescriptorWrites, + uint32_t \
descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) { + \
vkUpdateDescriptorSets(m_device, descriptorWriteCount, pDescriptorWrites, \
descriptorCopyCount, pDescriptorCopies); + }
+
+ VkResult createFramebuffer(const VkFramebufferCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) { + return \
vkCreateFramebuffer(m_device, pCreateInfo, pAllocator, pFramebuffer); + }
+
+ void destroyFramebuffer(VkFramebuffer framebuffer, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroyFramebuffer(m_device, framebuffer, \
pAllocator); + }
+
+ VkResult createRenderPass(const VkRenderPassCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { + return \
vkCreateRenderPass(m_device, pCreateInfo, pAllocator, pRenderPass); + }
+
+ void destroyRenderPass(VkRenderPass renderPass, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroyRenderPass(m_device, renderPass, \
pAllocator); + }
+
+ void getRenderAreaGranularity(VkRenderPass renderPass, VkExtent2D *pGranularity) \
{ + vkGetRenderAreaGranularity(m_device, renderPass, pGranularity);
+ }
+
+ VkResult createCommandPool(const VkCommandPoolCreateInfo *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) { + return \
vkCreateCommandPool(m_device, pCreateInfo, pAllocator, pCommandPool); + }
+
+ void destroyCommandPool(VkCommandPool commandPool, const VkAllocationCallbacks \
*pAllocator = nullptr) { + vkDestroyCommandPool(m_device, commandPool, \
pAllocator); + }
+
+ VkResult resetCommandPool(VkCommandPool commandPool, VkCommandPoolResetFlags \
flags) { + return vkResetCommandPool(m_device, commandPool, flags);
+ }
+
+ VkResult allocateCommandBuffers(const VkCommandBufferAllocateInfo \
*pAllocateInfo, VkCommandBuffer *pCommandBuffers) { + return \
vkAllocateCommandBuffers(m_device, pAllocateInfo, pCommandBuffers); + }
+
+ void freeCommandBuffers(VkCommandPool commandPool, uint32_t commandBufferCount, \
const VkCommandBuffer *pCommandBuffers) { + vkFreeCommandBuffers(m_device, \
commandPool, commandBufferCount, pCommandBuffers); + }
+
+ // VK_KHR_swapchain
+ VkResult createSwapchainKHR(const VkSwapchainCreateInfoKHR *pCreateInfo, const \
VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) { + return \
pfnCreateSwapchainKHR(m_device, pCreateInfo, pAllocator, pSwapchain); + }
+
+ void destroySwapchainKHR(VkSwapchainKHR swapchain, const VkAllocationCallbacks \
*pAllocator = nullptr) { + pfnDestroySwapchainKHR(m_device, swapchain, \
pAllocator); + }
+
+ VkResult getSwapchainImagesKHR(VkSwapchainKHR swapchain, uint32_t \
*pSwapchainImageCount, VkImage *pSwapchainImages) { + return \
pfnGetSwapchainImagesKHR(m_device, swapchain, pSwapchainImageCount, \
pSwapchainImages); + }
+
+ VkResult acquireNextImageKHR(VkSwapchainKHR swapchain, uint64_t timeout, \
VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) { + return \
pfnAcquireNextImageKHR(m_device, swapchain, timeout, semaphore, fence, pImageIndex); \
+ } +
+ // VK_KHR_maintenance1
+ void trimCommandPoolKHR(VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR \
flags) { + pfnTrimCommandPoolKHR(m_device, commandPool, flags);
+ }
+
+ // VK_KHR_descriptor_update_template
+ VkResult createDescriptorUpdateTemplateKHR(const \
VkDescriptorUpdateTemplateCreateInfoKHR *pCreateInfo, + \
const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplateKHR \
*pDescriptorUpdateTemplate) { + return \
pfnCreateDescriptorUpdateTemplateKHR(m_device, pCreateInfo, pAllocator, \
pDescriptorUpdateTemplate); + }
+
+ void destroyDescriptorUpdateTemplateKHR(VkDescriptorUpdateTemplateKHR \
descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator = nullptr) { + \
pfnDestroyDescriptorUpdateTemplateKHR(m_device, descriptorUpdateTemplate, \
pAllocator); + }
+
+ void updateDescriptorSetWithTemplateKHR(VkDescriptorSet descriptorSet, \
VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void *pData) { + \
pfnUpdateDescriptorSetWithTemplateKHR(m_device, descriptorSet, \
descriptorUpdateTemplate, pData); + }
+
+ // VK_KHR_external_memory_fd
+ VkResult getMemoryFdKHR(const VkMemoryGetFdInfoKHR *pGetFdInfo, int *pFd) {
+ return pfnGetMemoryFdKHR(m_device, pGetFdInfo, pFd);
+ }
+
+ VkResult getMemoryFdKHR(const VkMemoryGetFdInfoKHR &getFdInfo, int *pFd) {
+ return pfnGetMemoryFdKHR(m_device, &getFdInfo, pFd);
+ }
+
+ VkResult getMemoryFdPropertiesKHR(VkExternalMemoryHandleTypeFlagBitsKHR \
handleType, int fd, VkMemoryFdPropertiesKHR *pMemoryFdProperties) { + return \
pfnGetMemoryFdPropertiesKHR(m_device, handleType, fd, pMemoryFdProperties); + }
+
+ // VK_KHR_external_semaphore_fd
+ VkResult importSemaphoreFdKHR(const VkImportSemaphoreFdInfoKHR \
*pImportSemaphoreFdInfo) { + return pfnImportSemaphoreFdKHR(m_device, \
pImportSemaphoreFdInfo); + }
+
+ VkResult getSemaphoreFdKHR(const VkSemaphoreGetFdInfoKHR *pGetFdInfo, int *pFd) \
{ + return pfnGetSemaphoreFdKHR(m_device, pGetFdInfo, pFd);
+ }
+
+ VkResult getSemaphoreFdKHR(const VkSemaphoreGetFdInfoKHR &getFdInfo, int *pFd) {
+ return pfnGetSemaphoreFdKHR(m_device, &getFdInfo, pFd);
+ }
+
+private:
+ VulkanPhysicalDevice m_physicalDevice;
+ VkDevice m_device;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * Represents a queue in a logical device.
+ *
+ * Note that this class does not inherit from VulkanObject, and does not have
+ * a destructor. Queues are owned by the device, and calling vkGetDeviceQueue
+ * with the same parameters multiple times returns the same queue. That means
+ * that copying VulkanQueue objects is also safe.
+ */
+class KWINVULKANUTILS_EXPORT VulkanQueue
+{
+public:
+ typedef VkQueue NativeHandleType;
+
+ VulkanQueue()
+ : m_device(nullptr),
+ m_queue(VK_NULL_HANDLE),
+ m_familyIndex(0)
+ {
+ }
+
+ VulkanQueue(VulkanDevice *device, uint32_t queueFamilyIndex, uint32_t \
queueIndex) + : m_device(device),
+ m_queue(VK_NULL_HANDLE),
+ m_familyIndex(queueFamilyIndex),
+ m_index(queueIndex)
+ {
+ device->getQueue(queueFamilyIndex, queueIndex, &m_queue);
+ }
+
+ VulkanDevice *device() const { return m_device; }
+ uint32_t familyIndex() const { return m_familyIndex; }
+ uint32_t index() const { return m_index; }
+ bool isValid() const { return m_queue != VK_NULL_HANDLE; }
+
+ VkResult submit(uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence \
fence = VK_NULL_HANDLE) { + return vkQueueSubmit(m_queue, submitCount, \
pSubmits, fence); + }
+
+ VkResult submit(const VulkanArrayProxy<VkSubmitInfo> &submitInfo, VkFence fence \
= VK_NULL_HANDLE) { + return vkQueueSubmit(m_queue, submitInfo.count(), \
submitInfo.data(), fence); + }
+
+ VkResult waitIdle() {
+ return vkQueueWaitIdle(m_queue);
+ }
+
+ VkResult bindSparse(uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, \
VkFence fence) { + return vkQueueBindSparse(m_queue, bindInfoCount, pBindInfo, \
fence); + }
+
+ VkResult presentKHR(const VkPresentInfoKHR *pPresentInfo) {
+ return pfnQueuePresentKHR(m_queue, pPresentInfo);
+ }
+
+ VkResult presentKHR(const VkPresentInfoKHR &presentInfo) {
+ return pfnQueuePresentKHR(m_queue, &presentInfo);
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkQueue m_queue;
+ uint32_t m_familyIndex;
+ uint32_t m_index;
+};
+
+inline VulkanQueue VulkanDevice::getQueue(uint32_t queueFamilyIndex, uint32_t \
queueIndex) { + return VulkanQueue(this, queueFamilyIndex, queueIndex);
+}
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanSurface : public VulkanObject
+{
+public:
+ typedef VkSurfaceKHR NativeHandleType;
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+ VulkanSurface(VulkanInstance *instance, xcb_connection_t *connection, \
xcb_window_t window) + : m_instance(instance), m_surface(VK_NULL_HANDLE)
+ {
+ const VkXcbSurfaceCreateInfoKHR createInfo = {
+ .sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
+ .pNext = nullptr,
+ .flags = 0,
+ .connection = connection,
+ .window = window
+ };
+ instance->createXcbSurfaceKHR(&createInfo, nullptr, &m_surface);
+ }
+
+ VulkanSurface(VulkanInstance *instance, const VkXcbSurfaceCreateInfoKHR \
&createInfo) + : m_instance(instance), m_surface(VK_NULL_HANDLE)
+ {
+ instance->createXcbSurfaceKHR(&createInfo, nullptr, &m_surface);
+ }
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ VulkanSurface(VulkanInstance *instance, wl_display *display, wl_surface \
*surface) + : m_instance(instance), m_surface(VK_NULL_HANDLE)
+ {
+ const VkWaylandSurfaceCreateInfoKHR createInfo = {
+ .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
+ .pNext = nullptr,
+ .flags = 0,
+ .display = display,
+ .surface = surface
+ };
+
+ instance->createWaylandSurfaceKHR(&createInfo, nullptr, &m_surface);
+ }
+
+ VulkanSurface(VulkanInstance *instance, const VkWaylandSurfaceCreateInfoKHR \
&createInfo) + : m_instance(instance), m_surface(VK_NULL_HANDLE)
+ {
+ instance->createWaylandSurfaceKHR(&createInfo, nullptr, &m_surface);
+ }
+#endif
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+ VulkanSurface(VulkanInstance *instance, ANativeWindow *window)
+ : m_instance(instance), m_surface(VK_NULL_HANDLE)
+ {
+ const VkAndroidSurfaceCreateInfoKHR createInfo = {
+ .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
+ .pNext = nullptr,
+ .flags = 0,
+ .window = window
+ };
+
+ instance->createAndroidSurfaceKHR(&createInfo, nullptr, &m_surface);
+ }
+
+ VulkanSurface(VulkanInstance *instance, const VkAndroidSurfaceCreateInfoKHR \
&createInfo) + : m_instance(instance), m_surface(VK_NULL_HANDLE)
+ {
+ instance->createAndroidSurfaceKHR(&createInfo, nullptr, &m_surface);
+ }
+#endif
+
+ VulkanSurface(const VulkanSurface &) = delete;
+
+ VulkanSurface(VulkanSurface &&other)
+ {
+ m_instance = other.m_instance;
+ m_surface = other.m_surface;
+
+ other.m_instance = nullptr;
+ other.m_surface = VK_NULL_HANDLE;
+ }
+
+ ~VulkanSurface() override
+ {
+ if (m_surface)
+ m_instance->destroySurfaceKHR(m_surface, nullptr);
+ }
+
+ bool isValid() const { return m_surface != VK_NULL_HANDLE; }
+
+ VkSurfaceKHR handle() const { return m_surface; }
+
+ operator VkSurfaceKHR() const { return m_surface; }
+
+ VulkanSurface &operator = (const VulkanSurface &other) = delete;
+
+ VulkanSurface &operator = (VulkanSurface &&other)
+ {
+ m_instance = other.m_instance;
+ m_surface = other.m_surface;
+
+ other.m_instance = nullptr;
+ other.m_surface = VK_NULL_HANDLE;
+ return *this;
+ }
+
+private:
+ VulkanInstance *m_instance;
+ VkSurfaceKHR m_surface;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanImage : public VulkanObject
+{
+public:
+ typedef VkImage NativeHandleType;
+
+ VulkanImage(VulkanDevice *device, const VkImageCreateInfo &createInfo)
+ : VulkanObject(),
+ m_device(device),
+ m_image(VK_NULL_HANDLE),
+ m_type(createInfo.imageType),
+ m_format(createInfo.format),
+ m_usage(createInfo.usage),
+ m_extent(createInfo.extent),
+ m_mipLevels(createInfo.mipLevels)
+ {
+ device->createImage(&createInfo, nullptr, &m_image);
+ }
+
+ VulkanImage(const VulkanImage &) = delete;
+
+ VulkanImage(VulkanImage &&other)
+ : VulkanObject(),
+ m_device(other.m_device),
+ m_image(other.m_image),
+ m_type(other.m_type),
+ m_format(other.m_format),
+ m_usage(other.m_usage),
+ m_extent(other.m_extent),
+ m_mipLevels(other.m_mipLevels)
+ {
+ other.m_device = nullptr;
+ other.m_image = VK_NULL_HANDLE;
+ other.m_type = VK_IMAGE_TYPE_1D;
+ other.m_format = VK_FORMAT_UNDEFINED;
+ other.m_usage = 0;
+ other.m_extent = { 0, 0, 0 };
+ other.m_mipLevels = 0;
+ }
+
+ ~VulkanImage() override {
+ if (m_image)
+ m_device->destroyImage(m_image);
+ }
+
+ VulkanImage &operator = (const VulkanImage &) = delete;
+
+ VulkanImage &operator = (VulkanImage &&other) {
+ if (m_image)
+ m_device->destroyImage(m_image);
+
+ m_device = other.m_device;
+ m_image = other.m_image;
+ m_type = other.m_type;
+ m_format = other.m_format;
+ m_usage = other.m_usage;
+ m_extent = other.m_extent;
+ m_mipLevels = other.m_mipLevels;
+
+ other.m_device = nullptr;
+ other.m_image = VK_NULL_HANDLE;
+ other.m_type = VK_IMAGE_TYPE_1D;
+ other.m_format = VK_FORMAT_UNDEFINED;
+ other.m_usage = 0;
+ other.m_extent = { 0, 0, 0 };
+ other.m_mipLevels = 0;
+
+ return *this;
+ }
+
+ operator VkImage () const { return m_image; }
+
+ VkImage handle() const { return m_image; }
+
+ VulkanDevice *device() const { return m_device; }
+ VkImageType type() const { return m_type; }
+ VkFormat format() const { return m_format; }
+ VkImageUsageFlags usage() const { return m_usage; }
+ uint32_t width(int level = 0) const { return m_extent.width >> level; }
+ uint32_t height(int level = 0) const { return m_extent.height >> level; }
+ uint32_t depth(int level = 0) const { return m_extent.depth >> level; }
+ uint32_t mipLevelCount() const { return m_mipLevels; }
+ const VkExtent3D &extent() const { return m_extent; }
+ const QSize size(int level = 0) const { return QSize(width(level), \
height(level)); } + const QRect rect(int level = 0) const { return QRect(0, 0, \
width(level), height(level)); } +
+ VkSubresourceLayout getSubresourceLayout(const VkImageSubresource &subresource) \
{ + VkSubresourceLayout layout;
+ m_device->getImageSubresourceLayout(m_image, &subresource, &layout);
+ return layout;
+ }
+
+ bool isValid() const { return m_image != VK_NULL_HANDLE; }
+
+private:
+ VulkanDevice *m_device;
+ VkImage m_image;
+ VkImageType m_type;
+ VkFormat m_format;
+ VkImageUsageFlags m_usage;
+ VkExtent3D m_extent;
+ uint32_t m_mipLevels;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * VulkanStagingImage extents VulkanImage with a setData() and a data() method,
+ * allowing a pointer to the image data to be stored in the image object.
+ */
+class VulkanStagingImage : public VulkanImage
+{
+public:
+ typedef VkImage NativeHandleType;
+
+ VulkanStagingImage(VulkanDevice *device, const VkImageCreateInfo &createInfo)
+ : VulkanImage(device, createInfo)
+ {
+ }
+
+ VulkanStagingImage(const VulkanStagingImage &other) = delete;
+
+ VulkanStagingImage(VulkanStagingImage &&other)
+ : VulkanImage(std::forward<VulkanStagingImage>(other)),
+ m_data(other.m_data)
+ {
+ other.m_data = nullptr;
+ }
+
+ VulkanStagingImage &operator = (const VulkanStagingImage &other) = delete;
+
+ VulkanStagingImage &operator = (VulkanStagingImage &&other) {
+ VulkanImage::operator = (std::forward<VulkanStagingImage>(other));
+ m_data = other.m_data;
+ other.m_data = nullptr;
+ return *this;
+ }
+
+ void setData(uint8_t *data) { m_data = data; }
+ uint8_t *data() const { return m_data; }
+
+private:
+ uint8_t *m_data = nullptr;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanImageView : public VulkanObject
+{
+public:
+ typedef VkImageView NativeHandleType;
+
+ VulkanImageView(VulkanDevice *device, const VkImageViewCreateInfo &createInfo)
+ : VulkanObject(),
+ m_device(device),
+ m_imageView(VK_NULL_HANDLE),
+ m_type(createInfo.viewType),
+ m_format(createInfo.format)
+ {
+ device->createImageView(&createInfo, nullptr, &m_imageView);
+ }
+
+ VulkanImageView(const VulkanImageView &) = delete;
+
+ VulkanImageView(VulkanImageView &&other)
+ : VulkanObject(),
+ m_device(other.m_device),
+ m_imageView(other.m_imageView),
+ m_type(other.m_type),
+ m_format(other.m_format)
+ {
+ other.m_device = nullptr;
+ other.m_imageView = VK_NULL_HANDLE;
+ other.m_type = VK_IMAGE_VIEW_TYPE_1D;
+ other.m_format = VK_FORMAT_UNDEFINED;
+ }
+
+ ~VulkanImageView() override {
+ if (m_imageView)
+ m_device->destroyImageView(m_imageView);
+ }
+
+ VulkanImageView &operator = (const VulkanImageView &) = delete;
+
+ VulkanImageView &operator = (VulkanImageView &&other) {
+ if (m_imageView)
+ m_device->destroyImageView(m_imageView);
+
+ m_device = other.m_device;
+ m_imageView = other.m_imageView;
+ m_type = other.m_type;
+ m_format = other.m_format;
+
+ other.m_device = nullptr;
+ other.m_imageView = VK_NULL_HANDLE;
+ other.m_type = VK_IMAGE_VIEW_TYPE_1D;
+ other.m_format = VK_FORMAT_UNDEFINED;
+
+ return *this;
+ }
+
+ operator VkImageView () const { return m_imageView; }
+
+ VkImageView handle() const { return m_imageView; }
+
+ VulkanDevice *device() const { return m_device; }
+ VkImageViewType type() const { return m_type; }
+ VkFormat format() const { return m_format; }
+
+ bool isValid() const { return m_imageView != VK_NULL_HANDLE; }
+
+private:
+ VulkanDevice *m_device;
+ VkImageView m_imageView;
+ VkImageViewType m_type;
+ VkFormat m_format;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanFramebuffer : public VulkanObject
+{
+public:
+ typedef VkFramebuffer NativeHandleType;
+
+ VulkanFramebuffer()
+ : VulkanObject(),
+ m_device(nullptr),
+ m_framebuffer(VK_NULL_HANDLE),
+ m_width(0),
+ m_height(0),
+ m_layers(0)
+ {
+ }
+
+ VulkanFramebuffer(VulkanDevice *device, const VkFramebufferCreateInfo \
&createInfo) + : VulkanObject(),
+ m_device(device),
+ m_framebuffer(VK_NULL_HANDLE),
+ m_width(createInfo.width),
+ m_height(createInfo.height),
+ m_layers(createInfo.layers)
+ {
+ device->createFramebuffer(&createInfo, nullptr, &m_framebuffer);
+ }
+
+ VulkanFramebuffer(const VulkanFramebuffer &) = delete;
+
+ VulkanFramebuffer(VulkanFramebuffer &&other)
+ : VulkanObject(),
+ m_device(other.m_device),
+ m_framebuffer(other.m_framebuffer),
+ m_width(other.m_width),
+ m_height(other.m_height),
+ m_layers(other.m_layers)
+ {
+ other.m_device = nullptr;
+ other.m_framebuffer = VK_NULL_HANDLE;
+ other.m_width = 0;
+ other.m_height = 0;
+ other.m_layers = 0;
+ }
+
+ ~VulkanFramebuffer() override {
+ if (m_framebuffer)
+ m_device->destroyFramebuffer(m_framebuffer);
+ }
+
+ VulkanFramebuffer &operator = (const VulkanFramebuffer &) = delete;
+
+ VulkanFramebuffer &operator = (VulkanFramebuffer &&other) {
+ if (m_framebuffer)
+ m_device->destroyFramebuffer(m_framebuffer);
+
+ m_device = other.m_device;
+ m_framebuffer = other.m_framebuffer;
+ m_width = other.m_width;
+ m_height = other.m_height;
+ m_layers = other.m_layers;
+
+ other.m_device = nullptr;
+ other.m_framebuffer = VK_NULL_HANDLE;
+ other.m_width = 0;
+ other.m_height = 0;
+ other.m_layers = 0;
+
+ return *this;
+ }
+
+ operator VkFramebuffer () const { return m_framebuffer; }
+
+ VkFramebuffer handle() const { return m_framebuffer; }
+
+ bool isValid() const { return m_framebuffer != VK_NULL_HANDLE; }
+
+ uint32_t width() const { return m_width; }
+ uint32_t height() const { return m_height; }
+ uint32_t layers() const { return m_layers; }
+
+private:
+ VulkanDevice *m_device;
+ VkFramebuffer m_framebuffer;
+ uint32_t m_width;
+ uint32_t m_height;
+ uint32_t m_layers;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanBuffer : public VulkanObject
+{
+public:
+ typedef VkBuffer NativeHandleType;
+
+ VulkanBuffer(VulkanDevice *device, const VkBufferCreateInfo &createInfo)
+ : VulkanObject(),
+ m_device(device),
+ m_buffer(VK_NULL_HANDLE),
+ m_size(createInfo.size),
+ m_usage(createInfo.usage)
+ {
+ device->createBuffer(&createInfo, nullptr, &m_buffer);
+ }
+
+ VulkanBuffer(const VulkanBuffer &) = delete;
+
+ VulkanBuffer(VulkanBuffer &&other)
+ : VulkanObject(),
+ m_device(other.m_device),
+ m_buffer(other.m_buffer),
+ m_size(other.m_size),
+ m_usage(other.m_usage)
+ {
+ other.m_device = nullptr;
+ other.m_buffer = VK_NULL_HANDLE;
+ other.m_size = 0;
+ other.m_usage = 0;
+ }
+
+ ~VulkanBuffer() override {
+ if (m_buffer)
+ m_device->destroyBuffer(m_buffer);
+ }
+
+ VulkanBuffer &operator = (const VulkanBuffer &) = delete;
+
+ VulkanBuffer &operator = (VulkanBuffer &&other) {
+ if (m_buffer)
+ m_device->destroyBuffer(m_buffer);
+
+ m_device = other.m_device;
+ m_buffer = other.m_buffer;
+ m_size = other.m_size;
+ m_usage = other.m_usage;
+
+ other.m_device = nullptr;
+ other.m_buffer = VK_NULL_HANDLE;
+ other.m_size = 0;
+ other.m_usage = 0;
+
+ return *this;
+ }
+
+ operator VkBuffer () const { return m_buffer; }
+
+ VkBuffer handle() const { return m_buffer; }
+
+ bool isValid() const { return m_buffer != VK_NULL_HANDLE; }
+ VkDeviceSize size() const { return m_size; }
+ VkBufferUsageFlags usage() const { return m_usage; }
+
+private:
+ VulkanDevice *m_device;
+ VkBuffer m_buffer;
+ VkDeviceSize m_size;
+ VkBufferUsageFlags m_usage;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanBufferView : public VulkanObject
+{
+public:
+ typedef VkBufferView NativeHandleType;
+
+ VulkanBufferView()
+ : m_device(nullptr),
+ m_bufferView(VK_NULL_HANDLE),
+ m_format(VK_FORMAT_UNDEFINED),
+ m_offset(0),
+ m_range(0)
+ {
+ }
+
+ VulkanBufferView(VulkanDevice *device, const VkBufferViewCreateInfo &createInfo)
+ : m_device(device),
+ m_bufferView(VK_NULL_HANDLE),
+ m_format(createInfo.format),
+ m_offset(createInfo.offset),
+ m_range(createInfo.range)
+ {
+ device->createBufferView(&createInfo, nullptr, &m_bufferView);
+ }
+
+ VulkanBufferView(VulkanBufferView &&other)
+ : m_device(other.m_device),
+ m_bufferView(other.m_bufferView),
+ m_format(other.m_format),
+ m_offset(other.m_offset),
+ m_range(other.m_range)
+ {
+ other.m_device = nullptr;
+ other.m_bufferView = VK_NULL_HANDLE;
+ other.m_format = VK_FORMAT_UNDEFINED;
+ other.m_offset = 0;
+ other.m_range = 0;
+ }
+
+ VulkanBufferView(const VulkanBufferView &other) = delete;
+
+ ~VulkanBufferView() {
+ if (m_bufferView)
+ m_device->destroyBufferView(m_bufferView);
+ }
+
+ bool isValid() const { return m_bufferView != VK_NULL_HANDLE; }
+
+ VkBufferView handle() const { return m_bufferView; }
+ operator VkBufferView () const { return m_bufferView; }
+
+ VkFormat format() const { return m_format; }
+ VkDeviceSize offset() const { return m_offset; }
+ VkDeviceSize range() const { return m_range; }
+
+ VulkanBufferView &operator = (const VulkanBufferView &other) = delete;
+
+ VulkanBufferView &operator = (VulkanBufferView &&other) {
+ if (m_bufferView)
+ m_device->destroyBufferView(m_bufferView);
+
+ m_device = other.m_device;
+ m_bufferView = other.m_bufferView;
+ m_format = other.m_format;
+ m_offset = other.m_offset;
+ m_range = other.m_range;
+
+ other.m_device = nullptr;
+ other.m_bufferView = VK_NULL_HANDLE;
+ other.m_format = VK_FORMAT_UNDEFINED;
+ other.m_offset = 0;
+ other.m_range = 0;
+ return *this;
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkBufferView m_bufferView;
+ VkFormat m_format;
+ VkDeviceSize m_offset;
+ VkDeviceSize m_range;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanSampler : public VulkanObject
+{
+public:
+ typedef VkSampler NativeHandleType;
+
+ VulkanSampler()
+ : m_device(nullptr),
+ m_sampler(VK_NULL_HANDLE)
+ {
+ }
+
+ VulkanSampler(VulkanDevice *device, const VkSamplerCreateInfo &createInfo)
+ : m_device(device),
+ m_sampler(VK_NULL_HANDLE)
+ {
+ device->createSampler(&createInfo, nullptr, &m_sampler);
+ }
+
+ VulkanSampler(VulkanSampler &&other)
+ : m_device(other.m_device),
+ m_sampler(other.m_sampler)
+ {
+ other.m_device = nullptr;
+ other.m_sampler = VK_NULL_HANDLE;
+ }
+
+ VulkanSampler(const VulkanSampler &other) = delete;
+
+ ~VulkanSampler() {
+ if (m_sampler)
+ m_device->destroySampler(m_sampler);
+ }
+
+ bool isValid() const { return m_sampler != VK_NULL_HANDLE; }
+
+ VkSampler handle() const { return m_sampler; }
+ operator VkSampler () const { return m_sampler; }
+
+ VulkanSampler &operator = (const VulkanSampler &other) = delete;
+
+ VulkanSampler &operator = (VulkanSampler &&other) {
+ if (m_sampler)
+ m_device->destroySampler(m_sampler);
+
+ m_device = other.m_device;
+ m_sampler = other.m_sampler;
+
+ other.m_device = nullptr;
+ other.m_sampler = VK_NULL_HANDLE;
+ return *this;
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkSampler m_sampler;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanRenderPass : public VulkanObject
+{
+public:
+ typedef VkRenderPass NativeHandleType;
+
+ VulkanRenderPass()
+ : m_device(nullptr),
+ m_renderPass(VK_NULL_HANDLE)
+ {
+ }
+
+ VulkanRenderPass(VulkanDevice *device, const VkRenderPassCreateInfo &createInfo)
+ : m_device(device),
+ m_renderPass(VK_NULL_HANDLE)
+ {
+ device->createRenderPass(&createInfo, nullptr, &m_renderPass);
+ }
+
+ VulkanRenderPass(VulkanDevice *device,
+ const VulkanArrayProxy<VkAttachmentDescription> attachments,
+ const VulkanArrayProxy<VkSubpassDescription> subpasses,
+ const VulkanArrayProxy<VkSubpassDependency> dependencies = {})
+ : m_device(device),
+ m_renderPass(VK_NULL_HANDLE)
+ {
+ const VkRenderPassCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .attachmentCount = attachments.count(),
+ .pAttachments = attachments.data(),
+ .subpassCount = subpasses.count(),
+ .pSubpasses = subpasses.data(),
+ .dependencyCount = dependencies.count(),
+ .pDependencies = dependencies.data(),
+ };
+
+ device->createRenderPass(&createInfo, nullptr, &m_renderPass);
+ }
+
+ VulkanRenderPass(VulkanRenderPass &&other)
+ : m_device(other.m_device),
+ m_renderPass(other.m_renderPass)
+ {
+ other.m_device = VK_NULL_HANDLE;
+ other.m_renderPass = VK_NULL_HANDLE;
+ }
+
+ VulkanRenderPass(const VulkanRenderPass &other) = delete;
+
+ ~VulkanRenderPass() {
+ if (m_renderPass)
+ m_device->destroyRenderPass(m_renderPass);
+ }
+
+ bool isValid() const { return m_renderPass != VK_NULL_HANDLE; }
+
+ VkRenderPass handle() const { return m_renderPass; }
+ operator VkRenderPass () const { return m_renderPass; }
+
+ VulkanRenderPass &operator = (const VulkanRenderPass &other) = delete;
+
+ VulkanRenderPass &operator = (VulkanRenderPass &&other) {
+ if (m_renderPass)
+ m_device->destroyRenderPass(m_renderPass);
+
+ m_device = other.m_device;
+ m_renderPass = other.m_renderPass;
+
+ other.m_device = VK_NULL_HANDLE;
+ other.m_renderPass = VK_NULL_HANDLE;
+ return *this;
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkRenderPass m_renderPass;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanCommandPool : public VulkanObject
+{
+public:
+ typedef VkCommandPool NativeHandleType;
+
+ VulkanCommandPool()
+ : m_device(nullptr),
+ m_commandPool(VK_NULL_HANDLE),
+ m_createFlags(0),
+ m_queueFamilyIndex(0)
+ {
+ }
+
+ VulkanCommandPool(VulkanDevice *device, const VkCommandPoolCreateInfo \
&createInfo) + : m_device(device),
+ m_commandPool(VK_NULL_HANDLE),
+ m_createFlags(createInfo.flags),
+ m_queueFamilyIndex(createInfo.queueFamilyIndex)
+ {
+ device->createCommandPool(&createInfo, nullptr, &m_commandPool);
+ }
+
+ VulkanCommandPool(VulkanDevice *device, VkCommandPoolCreateFlags flags, uint32_t \
queueFamilyIndex) + : m_device(device),
+ m_commandPool(VK_NULL_HANDLE),
+ m_createFlags(flags),
+ m_queueFamilyIndex(queueFamilyIndex)
+ {
+ const VkCommandPoolCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = flags,
+ .queueFamilyIndex = queueFamilyIndex
+ };
+
+ device->createCommandPool(&createInfo, nullptr, &m_commandPool);
+ }
+
+ VulkanCommandPool(VulkanCommandPool &&other)
+ : m_device(other.m_device),
+ m_commandPool(other.m_commandPool),
+ m_queueFamilyIndex(other.m_queueFamilyIndex)
+ {
+ other.m_device = nullptr;
+ other.m_commandPool = VK_NULL_HANDLE;
+ other.m_queueFamilyIndex = 0;
+ }
+
+ VulkanCommandPool(const VulkanCommandPool &other) = delete;
+
+ ~VulkanCommandPool() {
+ if (m_commandPool)
+ m_device->destroyCommandPool(m_commandPool);
+ }
+
+ /**
+ * Recycles all of the resources from all of the command buffers allocated
+ * from the command pool back to the command pool. All command buffers that
+ * have been allocated from the command pool are put in the initial state.
+ */
+ void reset(VkCommandPoolResetFlags flags = 0) {
+ m_device->resetCommandPool(m_commandPool, flags);
+ }
+
+ /**
+ * Recycles unused memory back to the system.
+ *
+ * This function requires VK_KHR_maintenance1.
+ */
+ void trim(VkCommandPoolTrimFlagsKHR flags = 0) {
+ m_device->trimCommandPoolKHR(m_commandPool, flags);
+ }
+
+ bool isValid() const { return m_commandPool != VK_NULL_HANDLE; }
+ bool commandBuffersResettable() const { return m_createFlags & \
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; } + uint32_t queueFamilyIndex() \
const { return m_queueFamilyIndex; } +
+ VkCommandPool handle() const { return m_commandPool; }
+ operator VkCommandPool () const { return m_commandPool; }
+
+ VulkanCommandPool &operator = (const VulkanCommandPool &other) = delete;
+
+ VulkanCommandPool &operator = (VulkanCommandPool &&other) {
+ if (m_commandPool)
+ m_device->destroyCommandPool(m_commandPool);
+
+ m_device = other.m_device;
+ m_commandPool = other.m_commandPool;
+ m_queueFamilyIndex = other.m_queueFamilyIndex;
+
+ other.m_device = nullptr;
+ other.m_commandPool = VK_NULL_HANDLE;
+ other.m_queueFamilyIndex = 0;
+ return *this;
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkCommandPool m_commandPool;
+ VkCommandPoolCreateFlags m_createFlags;
+ uint32_t m_queueFamilyIndex;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanCommandBuffer : public VulkanObject
+{
+public:
+ typedef VkCommandBuffer NativeHandleType;
+
+ VulkanCommandBuffer()
+ : m_device(nullptr),
+ m_commandPool(VK_NULL_HANDLE),
+ m_commandBuffer(VK_NULL_HANDLE),
+ m_autoDelete(false),
+ m_active(false),
+ m_renderPassActive(false)
+ {
+ }
+
+ VulkanCommandBuffer(VulkanDevice *device, VkCommandPool commandPool, \
VkCommandBufferLevel level) + : m_device(device),
+ m_commandPool(commandPool),
+ m_commandBuffer(VK_NULL_HANDLE),
+ m_autoDelete(true),
+ m_active(false),
+ m_renderPassActive(false)
+ {
+ const VkCommandBufferAllocateInfo allocateInfo = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .pNext = nullptr,
+ .commandPool = commandPool,
+ .level = level,
+ .commandBufferCount = 1
+ };
+
+ device->allocateCommandBuffers(&allocateInfo, &m_commandBuffer);
+ }
+
+ VulkanCommandBuffer(const VulkanCommandBuffer &) = delete;
+
+ VulkanCommandBuffer(VulkanCommandBuffer &&other)
+ : m_device(other.m_device),
+ m_commandPool(other.m_commandPool),
+ m_commandBuffer(other.m_commandBuffer),
+ m_autoDelete(other.m_autoDelete),
+ m_active(other.m_active),
+ m_renderPassActive(other.m_renderPassActive)
+ {
+ other.m_device = nullptr;
+ other.m_commandPool = VK_NULL_HANDLE;
+ other.m_commandBuffer = VK_NULL_HANDLE;
+ other.m_autoDelete = false;
+ other.m_active = false;
+ other.m_renderPassActive = false;
+ }
+
+ ~VulkanCommandBuffer() {
+ if (m_autoDelete && m_commandBuffer)
+ free();
+ }
+
+ VulkanCommandBuffer &operator = (VulkanCommandBuffer &&other) {
+ if (m_autoDelete && m_commandBuffer)
+ free();
+
+ m_device = other.m_device;
+ m_commandPool = other.m_commandPool;
+ m_commandBuffer = other.m_commandBuffer;
+ m_autoDelete = other.m_autoDelete;
+ m_active = other.m_active;
+ m_renderPassActive = other.m_renderPassActive;
+
+ other.m_device = nullptr;
+ other.m_commandPool = VK_NULL_HANDLE;
+ other.m_commandBuffer = VK_NULL_HANDLE;
+ other.m_autoDelete = false;
+ other.m_active = false;
+ other.m_renderPassActive = false;
+
+ return *this;
+ }
+
+ /**
+ * Returns true if the command buffer is valid; and false otherwise.
+ */
+ bool isValid() const { return m_commandBuffer != VK_NULL_HANDLE; }
+
+ /**
+ * Returns true if the command buffer is in the recording state; and false \
otherwise. + */
+ bool isActive() const { return m_active; }
+
+ /**
+ * Returns true if a render pass instance is being recorded; and false \
otherwise. + */
+ bool isRenderPassActive() const { return m_renderPassActive; }
+
+ /**
+ * Sets whether the command buffer is automatically freed when the
+ * VulkanCommandBuffer object is destroyed.
+ *
+ * Setting this property to false allows all command buffers allocated
+ * from a command pool to be freed at the same time.
+ *
+ * The default value is true.
+ */
+ void setAutoDelete(bool enable) { m_autoDelete = enable; }
+
+ /**
+ * Returns true if the command buffer will be freed when the destructor is \
invoked; and false otherwise. + */
+ bool autoDelete() const { return m_autoDelete; }
+
+ /**
+ * Resets the command buffer, allowing it be recorded again.
+ */
+ void reset(VkCommandBufferResetFlags flags = 0) {
+ vkResetCommandBuffer(m_commandBuffer, flags);
+ }
+
+ /**
+ * Releases the command buffer back to the command pool.
+ */
+ void free() {
+ m_device->freeCommandBuffers(m_commandPool, 1, &m_commandBuffer);
+
+ m_device = nullptr;
+ m_commandBuffer = VK_NULL_HANDLE;
+ m_commandPool = VK_NULL_HANDLE;
+ }
+
+ /**
+ * Returns the command buffer handle.
+ */
+ VkCommandBuffer handle() const { return m_commandBuffer; }
+
+ /**
+ * Returns the command buffer handle.
+ */
+ operator VkCommandBuffer () const { return m_commandBuffer; }
+
+ /**
+ * Begins recording the command buffer.
+ *
+ * This function also resets the command buffer.
+ */
+ void begin(VkCommandBufferUsageFlags flags, const VkCommandBufferInheritanceInfo \
*pInheritanceInfo = nullptr) { + const VkCommandBufferBeginInfo beginInfo = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .pNext = nullptr,
+ .flags = flags,
+ .pInheritanceInfo = pInheritanceInfo
+ };
+
+ vkBeginCommandBuffer(m_commandBuffer, &beginInfo);
+ m_active = true;
+ }
+
+ void end() {
+ vkEndCommandBuffer(m_commandBuffer);
+ m_active = false;
+ }
+
+ void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) {
+ vkCmdBindPipeline(m_commandBuffer, pipelineBindPoint, pipeline);
+ }
+
+ void setViewport(uint32_t firstViewport, uint32_t viewportCount, const \
VkViewport *pViewports) { + vkCmdSetViewport(m_commandBuffer, firstViewport, \
viewportCount, pViewports); + }
+
+ void setViewport(uint32_t firstViewport, const VulkanArrayProxy<VkViewport> \
&viewports) { + vkCmdSetViewport(m_commandBuffer, firstViewport, \
viewports.count(), viewports.data()); + }
+
+ void setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D \
*pScissors) { + vkCmdSetScissor(m_commandBuffer, firstScissor, scissorCount, \
pScissors); + }
+
+ void setScissor(uint32_t firstScissor, const VulkanArrayProxy<VkRect2D> \
&scissors) { + vkCmdSetScissor(m_commandBuffer, firstScissor, \
scissors.count(), scissors.data()); + }
+
+ void setLineWidth(float lineWidth) {
+ vkCmdSetLineWidth(m_commandBuffer, lineWidth);
+ }
+
+ void setDepthBias(float depthBiasConstantFactor, float depthBiasClamp, float \
depthBiasSlopeFactor) { + vkCmdSetDepthBias(m_commandBuffer, \
depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor); + }
+
+ void setBlendConstants(const float blendConstants[4]) {
+ vkCmdSetBlendConstants(m_commandBuffer, blendConstants);
+ }
+
+ void setDepthBounds(float minDepthBounds, float maxDepthBounds) {
+ vkCmdSetDepthBounds(m_commandBuffer, minDepthBounds, maxDepthBounds);
+ }
+
+ void setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compareMask) {
+ vkCmdSetStencilCompareMask(m_commandBuffer, faceMask, compareMask);
+ }
+
+ void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMask) {
+ vkCmdSetStencilWriteMask(m_commandBuffer, faceMask, writeMask);
+ }
+
+ void setStencilReference(VkStencilFaceFlags faceMask, uint32_t reference) {
+ vkCmdSetStencilReference(m_commandBuffer, faceMask, reference);
+ }
+
+ void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout \
layout, + uint32_t firstSet, uint32_t descriptorSetCount, \
const VkDescriptorSet *pDescriptorSets, + uint32_t \
dynamicOffsetCount, const uint32_t *pDynamicOffsets) { + \
vkCmdBindDescriptorSets(m_commandBuffer, pipelineBindPoint, layout, firstSet, + \
descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); + }
+
+ void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout \
layout, + uint32_t firstSet, const \
VulkanArrayProxy<VkDescriptorSet> &descriptorSets, + const \
VulkanArrayProxy<uint32_t> &dynamicOffsets = {}) { + \
vkCmdBindDescriptorSets(m_commandBuffer, pipelineBindPoint, layout, firstSet, + \
descriptorSets.count(), descriptorSets.data(), + \
dynamicOffsets.count(), dynamicOffsets.data()); + }
+
+ void bindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType \
indexType) { + vkCmdBindIndexBuffer(m_commandBuffer, buffer, offset, \
indexType); + }
+
+ void bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, const \
VkBuffer *pBuffers, const VkDeviceSize *pOffsets) { + \
vkCmdBindVertexBuffers(m_commandBuffer, firstBinding, bindingCount, pBuffers, \
pOffsets); + }
+
+ void bindVertexBuffers(uint32_t firstBinding, const VulkanArrayProxy<VkBuffer> \
&buffers, const VulkanArrayProxy<VkDeviceSize> &offsets) { + \
assert(buffers.count() == offsets.count()); + \
vkCmdBindVertexBuffers(m_commandBuffer, firstBinding, buffers.count(), \
buffers.data(), offsets.data()); + }
+
+ void draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, \
uint32_t firstInstance) { + vkCmdDraw(m_commandBuffer, vertexCount, \
instanceCount, firstVertex, firstInstance); + }
+
+ void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t \
firstIndex, int32_t vertexOffset, uint32_t firstInstance) { + \
vkCmdDrawIndexed(m_commandBuffer, indexCount, instanceCount, firstIndex, \
vertexOffset, firstInstance); + }
+
+ void drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, \
uint32_t stride) { + vkCmdDrawIndirect(m_commandBuffer, buffer, offset, \
drawCount, stride); + }
+
+ void drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t \
drawCount, uint32_t stride) { + vkCmdDrawIndexedIndirect(m_commandBuffer, \
buffer, offset, drawCount, stride); + }
+
+ void dispatch(uint32_t x, uint32_t y, uint32_t z) {
+ vkCmdDispatch(m_commandBuffer, x, y, z);
+ }
+
+ void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) {
+ vkCmdDispatchIndirect(m_commandBuffer, buffer, offset);
+ }
+
+ void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, \
const VkBufferCopy *pRegions) { + vkCmdCopyBuffer(m_commandBuffer, srcBuffer, \
dstBuffer, regionCount, pRegions); + }
+
+ void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, const \
VulkanArrayProxy<VkBufferCopy> ®ions) { + vkCmdCopyBuffer(m_commandBuffer, \
srcBuffer, dstBuffer, regions.count(), regions.data()); + }
+
+ void copyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, \
VkImageLayout dstImageLayout, + uint32_t regionCount, const \
VkImageCopy *pRegions) { + vkCmdCopyImage(m_commandBuffer, srcImage, \
srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); + }
+
+ void blitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, \
VkImageLayout dstImageLayout, + uint32_t regionCount, const \
VkImageBlit *pRegions, VkFilter filter) { + vkCmdBlitImage(m_commandBuffer, \
srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter); + \
} +
+ void copyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLayout \
dstImageLayout, + uint32_t regionCount, const \
VkBufferImageCopy *pRegions) { + vkCmdCopyBufferToImage(m_commandBuffer, \
srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); + }
+
+ void copyImageToBuffer(VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer \
dstBuffer, + uint32_t regionCount, const VkBufferImageCopy \
*pRegions) { + vkCmdCopyImageToBuffer(m_commandBuffer, srcImage, \
srcImageLayout, dstBuffer, regionCount, pRegions); + }
+
+ void updateBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize \
dataSize, const void *pData) { + vkCmdUpdateBuffer(m_commandBuffer, dstBuffer, \
dstOffset, dataSize, pData); + }
+
+ void fillBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, \
uint32_t data) { + vkCmdFillBuffer(m_commandBuffer, dstBuffer, dstOffset, \
size, data); + }
+
+ void clearColorImage(VkImage image, VkImageLayout imageLayout, const \
VkClearColorValue *pColor, + uint32_t rangeCount, const \
VkImageSubresourceRange *pRanges) { + vkCmdClearColorImage(m_commandBuffer, \
image, imageLayout, pColor, rangeCount, pRanges); + }
+
+ void clearDepthStencilImage(VkImage image, VkImageLayout imageLayout, const \
VkClearDepthStencilValue *pDepthStencil, + uint32_t \
rangeCount, const VkImageSubresourceRange *pRanges) { + \
vkCmdClearDepthStencilImage(m_commandBuffer, image, imageLayout, pDepthStencil, \
rangeCount, pRanges); + }
+
+ void clearAttachments(uint32_t attachmentCount, const VkClearAttachment \
*pAttachments, uint32_t rectCount, const VkClearRect *pRects) { + \
vkCmdClearAttachments(m_commandBuffer, attachmentCount, pAttachments, rectCount, \
pRects); + }
+
+ void resolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage \
dstImage, VkImageLayout dstImageLayout, + uint32_t regionCount, \
const VkImageResolve *pRegions) { + vkCmdResolveImage(m_commandBuffer, \
srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); + }
+
+ void setEvent(VkEvent event, VkPipelineStageFlags stageMask) {
+ vkCmdSetEvent(m_commandBuffer, event, stageMask);
+ }
+
+ void resetEvent(VkEvent event, VkPipelineStageFlags stageMask) {
+ vkCmdResetEvent(m_commandBuffer, event, stageMask);
+ }
+
+ void waitEvents(uint32_t eventCount, const VkEvent *pEvents,
+ VkPipelineStageFlags srcStageMask, VkPipelineStageFlags \
dstStageMask, + uint32_t memoryBarrierCount, const VkMemoryBarrier \
*pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, const \
VkBufferMemoryBarrier *pBufferMemoryBarriers, + uint32_t \
imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { + \
vkCmdWaitEvents(m_commandBuffer, eventCount, pEvents, + \
srcStageMask, dstStageMask, + memoryBarrierCount, \
pMemoryBarriers, + bufferMemoryBarrierCount, \
pBufferMemoryBarriers, + imageMemoryBarrierCount, \
pImageMemoryBarriers); + }
+
+ void pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags \
dstStageMask, VkDependencyFlags dependencyFlags, + uint32_t \
memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, + \
uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier \
*pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, \
const VkImageMemoryBarrier *pImageMemoryBarriers) { + \
vkCmdPipelineBarrier(m_commandBuffer, srcStageMask, dstStageMask, dependencyFlags, + \
memoryBarrierCount, pMemoryBarriers, + \
bufferMemoryBarrierCount, pBufferMemoryBarriers, + \
imageMemoryBarrierCount, pImageMemoryBarriers); + }
+
+ void pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags \
dstStageMask, VkDependencyFlags dependencyFlags, + const \
VulkanArrayProxy<VkMemoryBarrier> &memoryBarriers, + const \
VulkanArrayProxy<VkBufferMemoryBarrier> &bufferMemoryBarriers, + \
const VulkanArrayProxy<VkImageMemoryBarrier> &imageMemoryBarriers) { + \
vkCmdPipelineBarrier(m_commandBuffer, srcStageMask, dstStageMask, dependencyFlags, + \
memoryBarriers.count(), memoryBarriers.data(), + \
bufferMemoryBarriers.count(), bufferMemoryBarriers.data(), + \
imageMemoryBarriers.count(), imageMemoryBarriers.data()); + }
+
+ void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags \
flags) { + vkCmdBeginQuery(m_commandBuffer, queryPool, query, flags);
+ }
+
+ void endQuery(VkQueryPool queryPool, uint32_t query) {
+ vkCmdEndQuery(m_commandBuffer, queryPool, query);
+ }
+
+ void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t \
queryCount) { + vkCmdResetQueryPool(m_commandBuffer, queryPool, firstQuery, \
queryCount); + }
+
+ void writeTimestamp(VkPipelineStageFlagBits pipelineStage, VkQueryPool \
queryPool, uint32_t query) { + vkCmdWriteTimestamp(m_commandBuffer, \
pipelineStage, queryPool, query); + }
+
+ void copyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t \
queryCount, + VkBuffer dstBuffer, VkDeviceSize \
dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { + \
vkCmdCopyQueryPoolResults(m_commandBuffer, queryPool, firstQuery, queryCount, \
dstBuffer, dstOffset, stride, flags); + }
+
+ void pushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, \
uint32_t offset, uint32_t size, const void *pValues) { + \
vkCmdPushConstants(m_commandBuffer, layout, stageFlags, offset, size, pValues); + \
} +
+ void pushDescriptorSetKHR(VkPipelineBindPoint pipelineBindPoint, \
VkPipelineLayout layout, uint32_t set, + uint32_t \
descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites) { + \
pfnCmdPushDescriptorSetKHR(m_commandBuffer, pipelineBindPoint, layout, set, + \
descriptorWriteCount, pDescriptorWrites); + }
+
+ void pushDescriptorSetKHR(VkPipelineBindPoint pipelineBindPoint, \
VkPipelineLayout layout, uint32_t set, + const \
VulkanArrayProxy<VkWriteDescriptorSet> &descriptorWrites) { + \
pfnCmdPushDescriptorSetKHR(m_commandBuffer, pipelineBindPoint, layout, set, + \
descriptorWrites.count(), descriptorWrites.data()); + }
+
+ void pushDescriptorSetWithTemplateKHR(VkDescriptorUpdateTemplateKHR \
descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void *pData) { \
+ pfnCmdPushDescriptorSetWithTemplateKHR(m_commandBuffer, \
descriptorUpdateTemplate, layout, set, pData); + }
+
+ void beginRenderPass(const VkRenderPassBeginInfo *pRenderPassBegin, \
VkSubpassContents contents) { + vkCmdBeginRenderPass(m_commandBuffer, \
pRenderPassBegin, contents); + m_renderPassActive = true;
+ }
+
+ void beginRenderPass(const VkRenderPassBeginInfo &renderPassBegin, \
VkSubpassContents contents) { + vkCmdBeginRenderPass(m_commandBuffer, \
&renderPassBegin, contents); + m_renderPassActive = true;
+ }
+
+ void nextSubpass(VkSubpassContents contents) {
+ vkCmdNextSubpass(m_commandBuffer, contents);
+ }
+
+ void endRenderPass() {
+ vkCmdEndRenderPass(m_commandBuffer);
+ m_renderPassActive = false;
+ }
+
+ void executeCommands(uint32_t commandBufferCount, const VkCommandBuffer \
*pCommandBuffers) { + vkCmdExecuteCommands(m_commandBuffer, \
commandBufferCount, pCommandBuffers); + }
+
+ // VK_EXT_discard_rectangles
+ void setDiscardRectangleEXT(uint32_t firstDiscardRectangle, uint32_t \
discardRectangleCount, const VkRect2D *pDiscardRectangles) { + \
vkCmdSetDiscardRectangleEXT(m_commandBuffer, firstDiscardRectangle, \
discardRectangleCount, pDiscardRectangles); + }
+
+ void setDiscardRectangleEXT(uint32_t firstDiscardRectangle, const \
VulkanArrayProxy<VkRect2D> &discardRectangles) { + \
vkCmdSetDiscardRectangleEXT(m_commandBuffer, firstDiscardRectangle, \
discardRectangles.count(), discardRectangles.data()); + }
+
+private:
+ VulkanDevice *m_device;
+ VkCommandPool m_commandPool;
+ VkCommandBuffer m_commandBuffer;
+ bool m_autoDelete:1;
+ bool m_active:1;
+ bool m_renderPassActive:1;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanDeviceMemory : public VulkanObject
+{
+public:
+ typedef VkDeviceMemory NativeHandleType;
+
+ struct CreateInfo {
+ VulkanDevice *device;
+ VkDeviceMemory memory;
+ VkDeviceSize size;
+ VkMemoryPropertyFlags flags;
+ VkExternalMemoryHandleTypeFlagsKHR exportableHandleTypes;
+ bool dedicated;
+ bool imported;
+ };
+
+ VulkanDeviceMemory(const CreateInfo &info)
+ : VulkanObject(),
+ m_device(info.device),
+ m_memory(info.memory),
+ m_size(info.size),
+ m_flags(info.flags),
+ m_exportableHandleTypes(info.exportableHandleTypes),
+ m_dedicated(info.dedicated),
+ m_imported(info.imported),
+ m_mapped(false)
+ {
+ }
+
+ VulkanDeviceMemory(const VulkanDeviceMemory &) = delete;
+
+ VulkanDeviceMemory(VulkanDeviceMemory &&other)
+ : VulkanObject(),
+ m_device(other.m_device),
+ m_memory(other.m_memory),
+ m_size(other.m_size),
+ m_flags(other.m_flags),
+ m_exportableHandleTypes(other.m_exportableHandleTypes),
+ m_dedicated(other.m_dedicated),
+ m_imported(other.m_imported),
+ m_mapped(other.m_mapped)
+
+ {
+ other.m_device = nullptr;
+ other.m_memory = VK_NULL_HANDLE;
+ other.m_size = 0;
+ other.m_flags = 0;
+ other.m_exportableHandleTypes = 0;
+ other.m_dedicated = false;
+ other.m_imported = false;
+ other.m_mapped = false;
+ }
+
+ ~VulkanDeviceMemory() override {
+ if (m_memory)
+ m_device->freeMemory(m_memory, nullptr);
+ }
+
+ VulkanDeviceMemory &operator = (const VulkanDeviceMemory &) = delete;
+
+ VulkanDeviceMemory &operator = (VulkanDeviceMemory &&other) {
+ if (m_memory)
+ m_device->freeMemory(m_memory, nullptr);
+
+ m_device = other.m_device;
+ m_memory = other.m_memory;
+ m_size = other.m_size;
+ m_flags = other.m_flags;
+ m_exportableHandleTypes = other.m_exportableHandleTypes;
+ m_dedicated = other.m_dedicated;
+ m_imported = other.m_imported;
+ m_mapped = other.m_mapped;
+
+ other.m_device = nullptr;
+ other.m_memory = VK_NULL_HANDLE;
+ other.m_size = 0;
+ other.m_flags = 0;
+ other.m_exportableHandleTypes = 0;
+ other.m_dedicated = false;
+ other.m_imported = false;
+ other.m_mapped = false;
+
+ return *this;
+ }
+
+ VkDeviceMemory handle() const { return m_memory; }
+ operator VkDeviceMemory() const { return m_memory; }
+
+ bool isValid() const { return m_memory != VK_NULL_HANDLE; }
+
+ VkDeviceSize size() const { return m_size; }
+
+ VkMemoryPropertyFlags propertyFlags() const { return m_flags; }
+ VkExternalMemoryHandleTypeFlagsKHR exportableHandleTypes() const { return \
m_exportableHandleTypes; } +
+ bool isDeviceLocal() const { return m_flags & \
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; } + bool isHostCoherent() const { return \
m_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } + bool isHostVisible() const { \
return m_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; } + bool isHostCached() \
const { return m_flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT; } + bool \
isLazilyAllocated() const { return m_flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; \
} + bool isDedicated() const { return m_dedicated; }
+ bool isImported() const { return m_imported; }
+ bool isExportable() const { return m_exportableHandleTypes != 0; }
+ bool isMapped() const { return m_mapped; }
+
+ VkResult getFd(VkExternalMemoryHandleTypeFlagBitsKHR handleType, int *pFd) {
+ const VkMemoryGetFdInfoKHR getFdInfo {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
+ .pNext = nullptr,
+ .memory = m_memory,
+ .handleType = handleType
+ };
+ assert((m_exportableHandleTypes & handleType) != 0);
+ return m_device->getMemoryFdKHR(&getFdInfo, pFd);
+ }
+
+ VkResult map(VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, \
void **ppData) { + VkResult result = m_device->mapMemory(m_memory, offset, \
size, flags, ppData); + if (result == VK_SUCCESS)
+ m_mapped = true;
+ return result;
+ }
+
+ VkResult map(VkMemoryMapFlags flags, void **ppData) {
+ return map(0, m_size, flags, ppData);
+ }
+
+ void unmap() {
+ m_device->unmapMemory(m_memory);
+ m_mapped = false;
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkDeviceMemory m_memory;
+ VkDeviceSize m_size;
+ VkMemoryPropertyFlags m_flags;
+ VkExternalMemoryHandleTypeFlagsKHR m_exportableHandleTypes;
+ bool m_dedicated:1;
+ bool m_imported:1;
+ bool m_mapped:1;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanSemaphore : public VulkanObject
+{
+public:
+ typedef VkSemaphore NativeHandleType;
+
+ VulkanSemaphore()
+ : m_device(nullptr),
+ m_semaphore(VK_NULL_HANDLE)
+ {
+ }
+
+ VulkanSemaphore(VulkanDevice *device)
+ : m_device(device),
+ m_semaphore(VK_NULL_HANDLE)
+ {
+ const VkSemaphoreCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0
+ };
+
+ m_device->createSemaphore(&createInfo, nullptr, &m_semaphore);
+ }
+
+ VulkanSemaphore(VulkanDevice *device, const VkSemaphoreCreateInfo &createInfo)
+ : m_device(device),
+ m_semaphore(VK_NULL_HANDLE)
+ {
+ m_device->createSemaphore(&createInfo, nullptr, &m_semaphore);
+ }
+
+ VulkanSemaphore(const VulkanSemaphore &other) = delete;
+
+ VulkanSemaphore(VulkanSemaphore &&other)
+ : m_device(other.m_device),
+ m_semaphore(other.m_semaphore)
+ {
+ other.m_device = nullptr;
+ other.m_semaphore = VK_NULL_HANDLE;
+ }
+
+ ~VulkanSemaphore() {
+ if (m_semaphore)
+ m_device->destroySemaphore(m_semaphore);
+ }
+
+ VulkanSemaphore &operator = (const VulkanSemaphore &other) = delete;
+
+ VulkanSemaphore &operator = (VulkanSemaphore &&other) {
+ if (m_semaphore)
+ m_device->destroySemaphore(m_semaphore);
+
+ m_device = other.m_device;
+ m_semaphore = other.m_semaphore;
+
+ other.m_device = nullptr;
+ other.m_semaphore = VK_NULL_HANDLE;
+ return *this;
+ }
+
+ operator VkSemaphore() const { return m_semaphore; }
+
+ VkSemaphore handle() const { return m_semaphore; }
+
+private:
+ VulkanDevice *m_device;
+ VkSemaphore m_semaphore;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * A VulkanFence is a synchronization primitive that can be used
+ * to insert a dependency from a queue to the host.
+ */
+class KWINVULKANUTILS_EXPORT VulkanFence : public VulkanObject
+{
+public:
+ typedef VkFence NativeHandleType;
+
+ VulkanFence()
+ : m_device(nullptr),
+ m_fence(VK_NULL_HANDLE)
+ {
+ }
+
+ VulkanFence(VulkanDevice *device, VkFenceCreateFlags flags = 0)
+ : m_device(device)
+ {
+ const VkFenceCreateInfo createInfo = {
+ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = flags
+ };
+
+ m_device->createFence(&createInfo, nullptr, &m_fence);
+ }
+
+ VulkanFence(VulkanDevice *device, const VkFenceCreateInfo &createInfo)
+ : m_device(device)
+ {
+ m_device->createFence(&createInfo, nullptr, &m_fence);
+ }
+
+ VulkanFence(const VulkanFence &) = delete;
+
+ VulkanFence(VulkanFence &&other)
+ : m_device(other.m_device),
+ m_fence(other.m_fence)
+ {
+ other.m_device = nullptr;
+ other.m_fence = VK_NULL_HANDLE;
+ }
+
+ ~VulkanFence() override {
+ if (m_fence)
+ m_device->destroyFence(m_fence);
+ }
+
+ VulkanFence &operator = (const VulkanFence &) = delete;
+
+ VulkanFence &operator = (VulkanFence &&other) {
+ if (m_fence)
+ m_device->destroyFence(m_fence);
+
+ m_device = other.m_device;
+ m_fence = other.m_fence;
+
+ other.m_device = nullptr;
+ other.m_fence = VK_NULL_HANDLE;
+ return *this;
+ }
+
+ operator VkFence () const { return m_fence; }
+
+ VkResult status() const {
+ return m_device->getFenceStatus(m_fence);
+ }
+
+ bool isSignalled() const {
+ return status() == VK_SUCCESS;
+ }
+
+ void reset() {
+ m_device->resetFences(1, &m_fence);
+ }
+
+ void wait(uint64_t timeout = UINT64_MAX) {
+ m_device->waitForFences(1, &m_fence, VK_TRUE, timeout);
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkFence m_fence;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * A VulkanShaderModule contains code for a shader.
+ */
+class KWINVULKANUTILS_EXPORT VulkanShaderModule : public VulkanObject
+{
+public:
+ typedef VkShaderModule NativeHandleType;
+
+ VulkanShaderModule()
+ : VulkanObject(),
+ m_device(nullptr),
+ m_shaderModule(VK_NULL_HANDLE)
+ {
+ }
+
+ VulkanShaderModule(VulkanDevice *device, const QString &fileName);
+
+ VulkanShaderModule(const VulkanShaderModule &) = delete;
+
+ VulkanShaderModule(VulkanShaderModule &&other)
+ : VulkanObject(),
+ m_device(other.m_device),
+ m_shaderModule(other.m_shaderModule)
+ {
+ other.m_device = nullptr;
+ other.m_shaderModule = VK_NULL_HANDLE;
+ }
+
+ ~VulkanShaderModule() override {
+ if (m_shaderModule)
+ m_device->destroyShaderModule(m_shaderModule, nullptr);
+ }
+
+ VulkanShaderModule &operator = (const VulkanShaderModule &) = delete;
+
+ VulkanShaderModule &operator = (VulkanShaderModule &&other) {
+ if (m_shaderModule)
+ m_device->destroyShaderModule(m_shaderModule, nullptr);
+
+ m_device = other.m_device;
+ m_shaderModule = other.m_shaderModule;
+
+ other.m_device = nullptr;
+ other.m_shaderModule = VK_NULL_HANDLE;
+
+ return *this;
+ }
+
+ bool isValid() const { return m_shaderModule != VK_NULL_HANDLE; }
+
+ VkShaderModule handle() const { return m_shaderModule; }
+ operator VkShaderModule () const { return m_shaderModule; }
+
+private:
+ VulkanDevice *m_device;
+ VkShaderModule m_shaderModule;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * VulkanClippedDrawHelper is used to invoked a draw command in a command buffer \
once + * for each scissor rect in a region.
+ */
+class VulkanClippedDrawHelper
+{
+public:
+ VulkanClippedDrawHelper(VulkanCommandBuffer *cmd, const QRegion ®ion)
+ : cmd(cmd),
+ region(region)
+ {
+ }
+
+ template <typename Func>
+ void forEachRect(Func f) {
+ for (const QRect &r : region) {
+ const VkRect2D scissor = {
+ .offset = { (int32_t) r.x(), (int32_t) r.y() },
+ .extent = { (uint32_t) r.width(), (uint32_t) r.height() }
+ };
+
+ cmd->setScissor(0, 1, &scissor);
+ f();
+ }
+ }
+
+ void draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, \
uint32_t firstInstance) { + forEachRect(std::bind(&VulkanCommandBuffer::draw, \
cmd, vertexCount, instanceCount, firstVertex, firstInstance)); + }
+
+ void drawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t \
firstIndex, int32_t vertexOffset, uint32_t firstInstance) { + \
forEachRect(std::bind(&VulkanCommandBuffer::drawIndexed, cmd, indexCount, \
instanceCount, firstIndex, vertexOffset, firstInstance)); + }
+
+ void drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, \
uint32_t stride) { + forEachRect(std::bind(&VulkanCommandBuffer::drawIndirect, \
cmd, buffer, offset, drawCount, stride)); + }
+
+ void drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t \
drawCount, uint32_t stride) { + \
forEachRect(std::bind(&VulkanCommandBuffer::drawIndexedIndirect, cmd, buffer, offset, \
drawCount, stride)); + }
+
+private:
+ VulkanCommandBuffer *cmd;
+ const QRegion ®ion;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class VulkanBufferRange
+{
+public:
+ VulkanBufferRange()
+ : m_buffer(nullptr),
+ m_offset(0),
+ m_range(0),
+ m_data(nullptr)
+ {
+ }
+
+ VulkanBufferRange(std::shared_ptr<VulkanBuffer> buffer, VkDeviceSize offset, \
VkDeviceSize range, void *data = nullptr) + : m_buffer(buffer),
+ m_offset(offset),
+ m_range(range),
+ m_data(data)
+ {
+ }
+
+ std::shared_ptr<VulkanBuffer> buffer() const { return m_buffer; }
+ VkBuffer handle() const { return m_buffer->handle(); }
+ VkDeviceSize offset() const { return m_offset; }
+ VkDeviceSize range() const { return m_range; }
+ void *data() const { return m_data; }
+
+private:
+ std::shared_ptr<VulkanBuffer> m_buffer;
+ VkDeviceSize m_offset;
+ VkDeviceSize m_range;
+ void *m_data;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanDeviceMemoryAllocator
+{
+public:
+ VulkanDeviceMemoryAllocator(VulkanDevice *device, const std::vector<const char \
*> &enabledDeviceExtensions); + virtual ~VulkanDeviceMemoryAllocator();
+
+ VulkanDevice *device() const { return m_device; }
+
+ /**
+ * Returns the index of the first memory type in memoryTypeBits that has all the \
property flags in mask set. + */
+ int findMemoryType(uint32_t memoryTypeBits, VkMemoryPropertyFlags mask) const;
+
+ /**
+ * Allocates size bytes of device memory.
+ *
+ * The memory will be allocated from the first memory type in memoryTypeBits \
that has + * all the flags in optimal set, or if that fails, the first memory \
type that has + * all the flags in required set.
+ *
+ * The memory will be allocated as non-dedicated and non-exportable.
+ */
+ std::shared_ptr<VulkanDeviceMemory> allocateMemory(VkDeviceSize size,
+ uint32_t memoryTypeBits,
+ VkMemoryPropertyFlags \
optimal, + \
VkMemoryPropertyFlags required); +
+ /**
+ * Allocates memory for the given buffer, and binds the buffer to the memory \
object. + *
+ * The memory will be allocated from the first supported memory type that has
+ * all the flags in optimal set, or if that fails, the first memory type that \
has + * all the flags in required set.
+ *
+ * The memory will be allocated as dedicated if the implementation indicates \
that + * dedicated memory is preferred or required for the given buffer.
+ *
+ * The memory will be allocated as non-exportable.
+ */
+ std::shared_ptr<VulkanDeviceMemory> allocateMemory(std::shared_ptr<VulkanBuffer> \
&buffer, + \
VkMemoryPropertyFlags optimal, + \
VkMemoryPropertyFlags required); +
+ /**
+ * Allocates memory for the given image, and binds the image to the memory \
object. + *
+ * The memory will be allocated from the first supported memory type that has
+ * all the flags in optimal set, or if that fails, the first memory type that \
has + * all the flags in required set.
+ *
+ * The memory will be allocated as dedicated if the implementation indicates \
that + * dedicated memory is preferred or required for the given image.
+ *
+ * The memory will be allocated as non-exportable.
+ */
+ std::shared_ptr<VulkanDeviceMemory> allocateMemory(std::shared_ptr<VulkanImage> \
&image, + VkMemoryPropertyFlags \
optimal, + \
VkMemoryPropertyFlags required); +
+ /**
+ * Returns the memory properties for the physical device.
+ */
+ const VkPhysicalDeviceMemoryProperties &memoryProperties() const { return \
m_memoryProperties; } +
+protected:
+ /**
+ * @internal
+ */
+ std::shared_ptr<VulkanDeviceMemory> allocateMemoryInternal(VkDeviceSize size, \
uint32_t memoryTypeBits, + \
VkMemoryPropertyFlags optimal, + \
VkMemoryPropertyFlags required, + \
const void *pAllocateInfoNext); +
+private:
+ VulkanDevice *m_device;
+ VkPhysicalDeviceMemoryProperties m_memoryProperties;
+ bool m_haveExternalMemory = false;
+ bool m_haveExternalMemoryFd = false;
+ bool m_haveDedicatedAllocation = false;
+ bool m_haveGetMemoryRequirements2 = false;
+ bool m_haveBindMemory2 = false;
+ bool m_haveExternalMemoryDmaBuf = false;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanCircularAllocatorBase
+{
+public:
+ VulkanCircularAllocatorBase(const VulkanCircularAllocatorBase &) = delete;
+
+ virtual ~VulkanCircularAllocatorBase();
+
+ /**
+ * Inserts any non-coherent mapped memory ranges that need to be flushed into \
the vector pointed to by \a it. + *
+ * The memory ranges returned by this method must be flushed prior to submitting
+ * command buffers that access data written to those ranges.
+ */
+ void getNonCoherentAllocatedRanges(std::back_insert_iterator<std::vector<VkMappedMemoryRange>> \
it); +
+ /**
+ * Creates and returns a frame boundary object.
+ *
+ * This object should be associated with the fence passed to vkQueueSubmit() \
when submitting + * command buffers that access memory allocated from the ring \
buffer. + *
+ * The FrameBoundary object holds a strong reference to the buffer, preventing \
it from being + * deleted while it is busy, along with the busy offset within the \
ring buffer. + * When the FrameBoundary object is destroyed, its destructor moves \
the tail pointer in the + * internal buffer, allowing the allocated memory ranges \
to be reused. + */
+ std::shared_ptr<VulkanObject> createFrameBoundary();
+
+ VulkanCircularAllocatorBase &operator = (const VulkanCircularAllocatorBase &) = \
delete; +
+protected:
+ class CircularBuffer;
+
+ VulkanCircularAllocatorBase(VulkanDevice *device, uint32_t nonCoherentAtomSize);
+
+protected:
+ VulkanDevice *m_device;
+ std::shared_ptr<CircularBuffer> m_circularBuffer;
+ std::vector<std::shared_ptr<CircularBuffer>> m_orphanedBuffers;
+ VkDeviceSize m_nonCoherentAtomSize = 1;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * VulkanUploadManager is used for streaming vertices, uniforms and image data.
+ */
+class KWINVULKANUTILS_EXPORT VulkanUploadManager : public \
VulkanCircularAllocatorBase +{
+public:
+ /**
+ * initialSize must be a power of two.
+ */
+ VulkanUploadManager(VulkanDevice *device,
+ VulkanDeviceMemoryAllocator *allocator,
+ size_t initialSize,
+ VkBufferUsageFlags bufferUsage,
+ VkMemoryPropertyFlags optimalFlags,
+ const VkPhysicalDeviceLimits &limits);
+
+ VulkanUploadManager(const VulkanUploadManager &) = delete;
+
+ /**
+ * Destroys the upload manager.
+ */
+ ~VulkanUploadManager() override;
+
+ /**
+ * Returns the buffer usage flags.
+ */
+ VkBufferUsageFlags usage() const { return m_bufferUsage; }
+
+ /**
+ * Returns the minimum texel buffer offset alignment.
+ */
+ VkDeviceSize minTexelBufferOffsetAlignment() const { return \
m_minTexelBufferOffsetAlignment; } +
+ /**
+ * Returns the minimum uniform buffer offset alignment.
+ */
+ VkDeviceSize minUniformBufferOffsetAlignment() const { return \
m_minUniformBufferOffsetAlignment; } +
+ /**
+ * Returns the minimum storage buffer offset alignment.
+ */
+ VkDeviceSize minStorageBufferOffsetAlignment() const { return \
m_minStorageBufferOffsetAlignment; } +
+ /**
+ * Allocates size bytes of data from the upload buffer.
+ */
+ VulkanBufferRange allocate(size_t size, uint32_t alignment = 4);
+
+ /**
+ * Uploads size bytes of data into the upload buffer.
+ */
+ VulkanBufferRange upload(const void *data, size_t size, uint32_t alignment = 4) \
{ + auto range = allocate(size, alignment);
+ memcpy(range.data(), data, size);
+ return range;
+ }
+
+ /**
+ * Uploads size bytes of data into the upload buffer, aligning the allocation
+ * to the minimum texel buffer offset alignment.
+ */
+ VulkanBufferRange uploadTexelData(const void *data, size_t size) {
+ return upload(data, size, m_minTexelBufferOffsetAlignment);
+ }
+
+ /**
+ * Uploads size bytes of data into the upload buffer, aligning the allocation
+ * to the minimum uniform buffer offset alignment.
+ */
+ VulkanBufferRange uploadUniformData(const void *data, size_t size) {
+ return upload(data, size, m_minUniformBufferOffsetAlignment);
+ }
+
+ /**
+ * Uploads size bytes of data into the upload buffer, aligning the allocation
+ * to the minimum storage buffer offset alignment.
+ */
+ VulkanBufferRange uploadStorageData(const void *data, size_t size) {
+ return upload(data, size, m_minStorageBufferOffsetAlignment);
+ }
+
+ /**
+ * Emplaces an object of type T in the upload buffer.
+ */
+ template <typename T, typename... Args>
+ VulkanBufferRange emplace(Args&&... args) {
+ auto range = allocate(sizeof(T), 4);
+ new(range.data()) T(std::forward<Args>(args)...);
+ return range;
+ }
+
+ /**
+ * Emplaces an object of type T in the upload buffer, aligning the allocation
+ * to the minimum uniform buffer offset alignment.
+ */
+ template <typename T, typename... Args>
+ VulkanBufferRange emplaceUniform(Args&&... args) {
+ auto range = allocate(sizeof(T), m_minUniformBufferOffsetAlignment);
+ new(range.data()) T(std::forward<Args>(args)...);
+ return range;
+ }
+
+ VulkanUploadManager &operator = (const VulkanUploadManager &) = delete;
+
+private:
+ void reallocate(size_t minimumSize);
+
+private:
+ VulkanDeviceMemoryAllocator *m_allocator;
+ size_t m_initialSize;
+ VkBufferUsageFlags m_bufferUsage;
+ VkMemoryPropertyFlags m_optimalMemoryFlags;
+ VkDeviceSize m_minTexelBufferOffsetAlignment = 4;
+ VkDeviceSize m_minUniformBufferOffsetAlignment = 4;
+ VkDeviceSize m_minStorageBufferOffsetAlignment = 4;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+/**
+ * VulkanStagingImageAllocator allocates and binds images to memory allocated from a \
ring buffer. + */
+class KWINVULKANUTILS_EXPORT VulkanStagingImageAllocator : public \
VulkanCircularAllocatorBase +{
+public:
+ VulkanStagingImageAllocator(VulkanDevice *device,
+ VulkanDeviceMemoryAllocator *allocator,
+ size_t initialSize,
+ VkMemoryPropertyFlags optimalMemoryFlags,
+ const VkPhysicalDeviceLimits &limits);
+
+ ~VulkanStagingImageAllocator() override;
+
+ /**
+ * Creates an image, and binds to memory allocated from the internal ring \
buffer. + *
+ * All images created by this method must use the same tiling mode,
+ * and must not be sparse or exportable.
+ */
+ std::shared_ptr<VulkanStagingImage> createImage(const VkImageCreateInfo \
&createInfo); +
+private:
+ void reallocate(size_t minimumSize, uint32_t memoryPropertyMask);
+
+private:
+ VulkanDeviceMemoryAllocator *m_allocator;
+ size_t m_initialSize;
+ VkMemoryPropertyFlags m_optimalMemoryFlags;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanPipelineCache
+{
+public:
+ typedef VkPipelineCache NativeHandleType;
+
+ VulkanPipelineCache() : m_device(VK_NULL_HANDLE), m_cache(VK_NULL_HANDLE) {}
+
+ VulkanPipelineCache(VulkanDevice *device, size_t initialDataSize = 0, const void \
*pInitialData = nullptr) + : m_device(device),
+ m_cache(VK_NULL_HANDLE)
+ {
+ device->createPipelineCache({
+ .sType = \
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, + \
.pNext = nullptr, + .flags = 0,
+ .initialDataSize = initialDataSize,
+ .pInitialData = pInitialData
+ }, nullptr, &m_cache);
+ }
+
+ VulkanPipelineCache(VulkanPipelineCache &&other)
+ : m_device(other.m_device),
+ m_cache(other.m_cache)
+ {
+ other.m_device = VK_NULL_HANDLE;
+ other.m_cache = VK_NULL_HANDLE;
+ }
+
+ VulkanPipelineCache(const VulkanPipelineCache &other) = delete;
+
+ ~VulkanPipelineCache() {
+ if (m_cache)
+ m_device->destroyPipelineCache(m_cache);
+ }
+
+ VkPipelineCache handle() const { return m_cache; }
+ operator VkPipelineCache () const { return m_cache; }
+
+ bool isValid() const { return m_cache != VK_NULL_HANDLE; }
+
+ std::vector<uint8_t> data() {
+ size_t size = 0;
+ m_device->getPipelineCacheData(m_cache, &size, nullptr);
+
+ std::vector<uint8_t> data(size);
+ m_device->getPipelineCacheData(m_cache, &size, data.data());
+ return data;
+ }
+
+ VulkanPipelineCache &operator = (const VulkanPipelineCache &other) = delete;
+
+ VulkanPipelineCache &operator = (VulkanPipelineCache &&other) {
+ if (m_cache)
+ m_device->destroyPipelineCache(m_cache);
+
+ m_device = other.m_device;
+ m_cache = other.m_cache;
+
+ other.m_device = nullptr;
+ other.m_cache = VK_NULL_HANDLE;
+ return *this;
+ }
+
+private:
+ VulkanDevice *m_device;
+ VkPipelineCache m_cache;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+class KWINVULKANUTILS_EXPORT VulkanPipelineManager
+{
+public:
+ /**
+ * The material rendered by the pipeline.
+ */
+ enum Material {
+ FlatColor = 0,
+ Texture = 1,
+ TwoTextures = 2,
+ DecorationStagingImages = 3,
+ MaterialCount = 4,
+ };
+
+ /**
+ * The traits of the pipeline, such as filters applied to the material,
+ * how fragments are rasterized, etc.
+ */
+ enum Trait {
+ NoTraits = 0,
+ PreMultipliedAlphaBlend = (1 << 0),
+ Modulate = (1 << 1),
+ Desaturate = (1 << 2),
+ CrossFade = (1 << 3),
+ };
+
+ Q_DECLARE_FLAGS(Traits, Trait);
+
+ /**
+ * The type of descriptors that will be used with the pipeline.
+ */
+ enum DescriptorType {
+ DescriptorSet = 0,
+ PushDescriptors = 1
+ };
+
+ /**
+ * The types of render passes the pipeline will be compatible with.
+ *
+ * All render passes have one subpass, and one framebuffer attachment.
+ * They differ only in the format of the attachment.
+ */
+ enum RenderPassType {
+ SwapchainRenderPass = 0, /// Render pass that targets images with the swap \
chain format + OffscreenRenderPass, /// Render pass that targets \
VK_FORMAT_R8G8B8A8_UNORM images + RenderPassTypeCount
+ };
+
+ /**
+ * The topology of the primitives rendered by the pipeline.
+ */
+ enum Topology {
+ PointList = VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
+ LineList = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
+ LineStrip = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
+ TriangleList = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ TriangleStrip = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ TriangleFan = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
+ };
+
+ class ColorUniformData {
+ public:
+ ColorUniformData(const QMatrix4x4 &matrix, const QVector4D &color) {
+ memcpy(m_matrix, matrix.constData(), 64);
+ memcpy(m_color, &color, 16);
+ }
+
+ private:
+ float m_matrix[16];
+ float m_color[4];
+ };
+
+ class TextureUniformData {
+ public:
+ TextureUniformData(const QMatrix4x4 &matrix, float opacity, float \
brightness, float saturation, float crossFadeProgress) { + const float rgb \
= brightness * opacity; + const float a = opacity;
+ memcpy(m_matrix, matrix.constData(), 64);
+ m_modulation[0] = rgb;
+ m_modulation[1] = rgb;
+ m_modulation[2] = rgb;
+ m_modulation[3] = a;
+ m_saturation = saturation;
+ m_crossFadeProgress = crossFadeProgress;
+ m_pad[0] = 0.0f;
+ m_pad[1] = 0.0f;
+ }
+
+ private:
+ float m_matrix[16];
+ float m_modulation[4];
+ float m_saturation;
+ float m_crossFadeProgress;
+ float m_pad[2];
+ };
+
+ /**
+ * Creates a new VulkanPipelineManager.
+ *
+ * @param device The logical device
+ * @param swapchainRenderPass Render pass for swap chain compatible pipelines
+ * @param offscreenRenderPass Render pass for offscreen compatible pipelines
+ * @param nearestSampler Nearest-neighbor sampler to be used as an \
immutable sampler + * @param linearSampler Linear sampler to be used as an \
immutable sampler + * @param havePushDescriptors Indicates whether \
VK_KHR_push_descriptor is supported by the device + */
+ VulkanPipelineManager(VulkanDevice *device, VulkanPipelineCache *cache,
+ VkSampler nearestSampler, VkSampler linearSampler,
+ VkRenderPass swapchainRenderPass, VkRenderPass \
offscreenRenderPass, + bool havePushDescriptors);
+
+ /**
+ * Destroys the VulkanPipelineManager.
+ */
+ ~VulkanPipelineManager();
+
+ /**
+ * Returns true if the VulkanPipelineManager is valid, and false otherwise.
+ */
+ bool isValid() const { return m_valid; }
+
+ /**
+ * Returns a pipeline and a pipeline layout matching the given material, triats, \
descriptor type and topology. + */
+ std::tuple<VkPipeline, VkPipelineLayout> pipeline(Material material,
+ Traits traits,
+ DescriptorType descriptorType,
+ Topology topology,
+ RenderPassType \
renderPassType); +
+ VkDescriptorSetLayout descriptorSetLayout(Material material) const { return \
m_descriptorSetLayout[material]; } + VkDescriptorSetLayout \
pushDescriptorSetLayout(Material material) const { return \
m_pushDescriptorSetLayout[material]; } +
+private:
+ bool createDescriptorSetLayouts();
+ bool createPipelineLayouts();
+ bool createDescriptorUpdateTemplates();
+ VkPipeline createPipeline(Material material, Traits traits, DescriptorType \
descriptorType, Topology topology, VkRenderPass renderPass); +
+private:
+ VulkanDevice *m_device;
+ VulkanPipelineCache *m_pipelineCache;
+ VkDescriptorSetLayout m_descriptorSetLayout[MaterialCount];
+ VkDescriptorSetLayout m_pushDescriptorSetLayout[MaterialCount];
+ VkPipelineLayout m_pipelineLayout[MaterialCount];
+ VkPipelineLayout m_pushDescriptorPipelineLayout[MaterialCount];
+ std::unordered_map<uint32_t, VkPipeline> m_pipelines;
+ VkRenderPass m_renderPasses[RenderPassTypeCount];
+ VulkanShaderModule m_colorVertexShader;
+ VulkanShaderModule m_textureVertexShader;
+ VulkanShaderModule m_crossFadeVertexShader;
+ VulkanShaderModule m_updateDecorationVertexShader;
+ VulkanShaderModule m_colorFragmentShader;
+ VulkanShaderModule m_textureFragmentShader;
+ VulkanShaderModule m_modulateFragmentShader;
+ VulkanShaderModule m_desaturateFragmentShader;
+ VulkanShaderModule m_crossFadeFragmentShader;
+ VulkanShaderModule m_updateDecorationFragmentShader;
+ VkSampler m_nearestSampler = VK_NULL_HANDLE;
+ VkSampler m_linearSampler = VK_NULL_HANDLE;
+ uint32_t m_maxDiscardRectangles = 0;
+ bool m_havePushDescriptors = false;
+ bool m_valid = false;
+};
+
+
+
+// -----------------------------------------------------------------------
+
+
+
+KWINVULKANUTILS_EXPORT QByteArray enumToString(VkFormat format);
+KWINVULKANUTILS_EXPORT QByteArray enumToString(VkResult result);
+KWINVULKANUTILS_EXPORT QByteArray enumToString(VkPresentModeKHR mode);
+KWINVULKANUTILS_EXPORT QByteArray enumToString(VkPhysicalDeviceType \
physicalDeviceType); +
+KWINVULKANUTILS_EXPORT QByteArray vendorName(uint32_t vendorID);
+KWINVULKANUTILS_EXPORT QByteArray driverVersionString(uint32_t vendorID, uint32_t \
driverVersion); +
+} // namespace KWin
+
+#endif // KWINVULKANUTILS_H
diff --git a/libkwineffects/kwinvulkanutils_funcs.cpp \
b/libkwineffects/kwinvulkanutils_funcs.cpp new file mode 100644
index 000000000..dfd78c95e
--- /dev/null
+++ b/libkwineffects/kwinvulkanutils_funcs.cpp
@@ -0,0 +1,200 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright © 2017-2018 Fredrik Höglund <fredrik@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+
+#include "kwinvulkanutils_funcs.h"
+
+#define RESOLVE(name) \
+ pfn ##name = (PFN_vk ##name) vkGetInstanceProcAddr(instance, "vk" #name)
+
+namespace KWin
+{
+
+// VK_KHR_surface
+PFN_vkDestroySurfaceKHR pfnDestroySurfaceKHR;
+PFN_vkGetPhysicalDeviceSurfaceSupportKHR pfnGetPhysicalDeviceSurfaceSupportKHR;
+PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR \
pfnGetPhysicalDeviceSurfaceCapabilitiesKHR; +PFN_vkGetPhysicalDeviceSurfaceFormatsKHR \
pfnGetPhysicalDeviceSurfaceFormatsKHR; +PFN_vkGetPhysicalDeviceSurfacePresentModesKHR \
pfnGetPhysicalDeviceSurfacePresentModesKHR; +
+#ifdef VK_USE_PLATFORM_XCB_KHR
+// VK_KHR_xcb_surface
+PFN_vkCreateXcbSurfaceKHR pfnCreateXcbSurfaceKHR;
+PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR \
pfnGetPhysicalDeviceXcbPresentationSupportKHR; +#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+// VK_KHR_wayland_surface
+PFN_vkCreateWaylandSurfaceKHR pfnCreateWaylandSurfaceKHR;
+PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR \
pfnGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+// VK_KHR_android_surface
+PFN_vkCreateAndroidSurfaceKHR pfnCreateAndroidSurfaceKHR;
+#endif
+
+// VK_KHR_swapchain
+PFN_vkCreateSwapchainKHR pfnCreateSwapchainKHR;
+PFN_vkDestroySwapchainKHR pfnDestroySwapchainKHR;
+PFN_vkGetSwapchainImagesKHR pfnGetSwapchainImagesKHR;
+PFN_vkAcquireNextImageKHR pfnAcquireNextImageKHR;
+PFN_vkQueuePresentKHR pfnQueuePresentKHR;
+
+// VK_KHR_maintenance1
+PFN_vkTrimCommandPoolKHR pfnTrimCommandPoolKHR;
+
+// VK_KHR_push_descriptor
+PFN_vkCmdPushDescriptorSetKHR pfnCmdPushDescriptorSetKHR;
+
+// VK_KHR_descriptor_update_template
+PFN_vkCreateDescriptorUpdateTemplateKHR pfnCreateDescriptorUpdateTemplateKHR;
+PFN_vkDestroyDescriptorUpdateTemplateKHR pfnDestroyDescriptorUpdateTemplateKHR;
+PFN_vkUpdateDescriptorSetWithTemplateKHR pfnUpdateDescriptorSetWithTemplateKHR;
+PFN_vkCmdPushDescriptorSetWithTemplateKHR pfnCmdPushDescriptorSetWithTemplateKHR;
+
+// VK_EXT_debug_report
+PFN_vkCreateDebugReportCallbackEXT pfnCreateDebugReportCallbackEXT;
+PFN_vkDestroyDebugReportCallbackEXT pfnDestroyDebugReportCallbackEXT;
+PFN_vkDebugReportMessageEXT pfnDebugReportMessageEXT;
+
+// VK_KHR_get_physical_device_properties2
+PFN_vkGetPhysicalDeviceFeatures2KHR \
pfnGetPhysicalDeviceFeatures2KHR; +PFN_vkGetPhysicalDeviceProperties2KHR \
pfnGetPhysicalDeviceProperties2KHR; +PFN_vkGetPhysicalDeviceFormatProperties2KHR \
pfnGetPhysicalDeviceFormatProperties2KHR; \
+PFN_vkGetPhysicalDeviceImageFormatProperties2KHR \
pfnGetPhysicalDeviceImageFormatProperties2KHR; \
+PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR \
pfnGetPhysicalDeviceQueueFamilyProperties2KHR; \
+PFN_vkGetPhysicalDeviceMemoryProperties2KHR \
pfnGetPhysicalDeviceMemoryProperties2KHR; \
+PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR \
pfnGetPhysicalDeviceSparseImageFormatProperties2KHR; +
+// VK_KHR_external_memory_capabilities
+PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR \
pfnGetPhysicalDeviceExternalBufferPropertiesKHR; +
+// VK_KHR_external_memory_fd
+PFN_vkGetMemoryFdKHR pfnGetMemoryFdKHR;
+PFN_vkGetMemoryFdPropertiesKHR pfnGetMemoryFdPropertiesKHR;
+
+// VK_KHR_external_semaphore_capabilities
+PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR \
pfnGetPhysicalDeviceExternalSemaphorePropertiesKHR; +
+// VK_KHR_external_semaphore_fd
+PFN_vkImportSemaphoreFdKHR pfnImportSemaphoreFdKHR;
+PFN_vkGetSemaphoreFdKHR pfnGetSemaphoreFdKHR;
+
+// VK_KHR_get_memory_requirements2
+PFN_vkGetImageMemoryRequirements2KHR pfnGetImageMemoryRequirements2KHR;
+PFN_vkGetBufferMemoryRequirements2KHR pfnGetBufferMemoryRequirements2KHR;
+PFN_vkGetImageSparseMemoryRequirements2KHR pfnGetImageSparseMemoryRequirements2KHR;
+
+// VK_EXT_discard_rectangles
+PFN_vkCmdSetDiscardRectangleEXT pfnCmdSetDiscardRectangleEXT;
+
+// VK_KHR_bind_memory2
+PFN_vkBindBufferMemory2KHR pfnBindBufferMemory2KHR;
+PFN_vkBindImageMemory2KHR pfnBindImageMemory2KHR;
+
+
+void resolveFunctions(VkInstance instance)
+{
+ // VK_KHR_surface
+ RESOLVE (DestroySurfaceKHR);
+ RESOLVE (GetPhysicalDeviceSurfaceSupportKHR);
+ RESOLVE (GetPhysicalDeviceSurfaceCapabilitiesKHR);
+ RESOLVE (GetPhysicalDeviceSurfaceFormatsKHR);
+ RESOLVE (GetPhysicalDeviceSurfacePresentModesKHR);
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+ // VK_KHR_xcb_surface
+ RESOLVE (CreateXcbSurfaceKHR);
+ RESOLVE (GetPhysicalDeviceXcbPresentationSupportKHR);
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ // VK_KHR_wayland_surface
+ RESOLVE (CreateWaylandSurfaceKHR);
+ RESOLVE (GetPhysicalDeviceWaylandPresentationSupportKHR);
+#endif
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+ // VK_KHR_android_surface
+ RESOLVE (CreateAndroidSurfaceKHR);
+#endif
+
+ // VK_KHR_swapchain
+ RESOLVE (CreateSwapchainKHR);
+ RESOLVE (DestroySwapchainKHR);
+ RESOLVE (GetSwapchainImagesKHR);
+ RESOLVE (AcquireNextImageKHR);
+ RESOLVE (QueuePresentKHR);
+
+ // VK_KHR_maintenance1
+ RESOLVE (TrimCommandPoolKHR);
+
+ // VK_KHR_push_descriptor
+ RESOLVE (CmdPushDescriptorSetKHR);
+
+ // VK_KHR_descriptor_update_template
+ RESOLVE (CreateDescriptorUpdateTemplateKHR);
+ RESOLVE (DestroyDescriptorUpdateTemplateKHR);
+ RESOLVE (UpdateDescriptorSetWithTemplateKHR);
+ RESOLVE (CmdPushDescriptorSetWithTemplateKHR);
+
+ // VK_EXT_debug_report
+ RESOLVE (CreateDebugReportCallbackEXT);
+ RESOLVE (CreateDebugReportCallbackEXT);
+ RESOLVE (DestroyDebugReportCallbackEXT);
+ RESOLVE (DebugReportMessageEXT);
+
+ // VK_KHR_get_physical_device_properties2
+ RESOLVE (GetPhysicalDeviceFeatures2KHR);
+ RESOLVE (GetPhysicalDeviceProperties2KHR);
+ RESOLVE (GetPhysicalDeviceFormatProperties2KHR);
+ RESOLVE (GetPhysicalDeviceImageFormatProperties2KHR);
+ RESOLVE (GetPhysicalDeviceQueueFamilyProperties2KHR);
+ RESOLVE (GetPhysicalDeviceMemoryProperties2KHR);
+ RESOLVE (GetPhysicalDeviceSparseImageFormatProperties2KHR);
+
+ // VK_KHR_external_memory_capabilities
+ RESOLVE (GetPhysicalDeviceExternalBufferPropertiesKHR);
+
+ // VK_KHR_external_memory_fd
+ RESOLVE (GetMemoryFdKHR);
+ RESOLVE (GetMemoryFdPropertiesKHR);
+
+ // VK_KHR_external_semaphore_capabilities
+ RESOLVE (GetPhysicalDeviceExternalSemaphorePropertiesKHR);
+
+ // VK_KHR_external_semaphore_fd
+ RESOLVE (ImportSemaphoreFdKHR);
+ RESOLVE (GetSemaphoreFdKHR);
+
+ // VK_KHR_get_memory_requirements2
+ RESOLVE (GetImageMemoryRequirements2KHR);
+ RESOLVE (GetBufferMemoryRequirements2KHR);
+ RESOLVE (GetImageSparseMemoryRequirements2KHR);
+
+ // VK_EXT_discard_rectangles
+ RESOLVE (CmdSetDiscardRectangleEXT);
+
+ // VK_KHR_bind_memory2
+ RESOLVE (BindBufferMemory2KHR);
+ RESOLVE (BindImageMemory2KHR);
+}
+
+} // namespace KWin
diff --git a/libkwineffects/kwinvulkanutils_funcs.h \
b/libkwineffects/kwinvulkanutils_funcs.h new file mode 100644
index 000000000..595fca7c7
--- /dev/null
+++ b/libkwineffects/kwinvulkanutils_funcs.h
@@ -0,0 +1,123 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright © 2017-2018 Fredrik Höglund <fredrik@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+
+#ifndef KWINVULKANUTILS_FUNCS_H
+#define KWINVULKANUTILS_FUNCS_H
+
+#include <kwinvulkanutils_export.h>
+
+#define VK_USE_PLATFORM_XCB_KHR
+#define VK_USE_PLATFORM_WAYLAND_KHR
+#include <vulkan/vulkan.h>
+
+namespace KWin
+{
+
+class VulkanExtensionPropertyList;
+
+// VK_KHR_surface
+extern KWINVULKANUTILS_EXPORT PFN_vkDestroySurfaceKHR \
pfnDestroySurfaceKHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceSurfaceSupportKHR pfnGetPhysicalDeviceSurfaceSupportKHR; \
+extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR \
pfnGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR pfnGetPhysicalDeviceSurfaceFormatsKHR; \
+extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceSurfacePresentModesKHR \
pfnGetPhysicalDeviceSurfacePresentModesKHR; +
+#ifdef VK_USE_PLATFORM_XCB_KHR
+// VK_KHR_xcb_surface
+extern KWINVULKANUTILS_EXPORT PFN_vkCreateXcbSurfaceKHR \
pfnCreateXcbSurfaceKHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR \
pfnGetPhysicalDeviceXcbPresentationSupportKHR; +#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+// VK_KHR_wayland_surface
+extern KWINVULKANUTILS_EXPORT PFN_vkCreateWaylandSurfaceKHR \
pfnCreateWaylandSurfaceKHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR \
pfnGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+// VK_KHR_android_surface
+extern KWINVULKANUTILS_EXPORT PFN_vkCreateAndroidSurfaceKHR \
pfnCreateAndroidSurfaceKHR; +#endif
+
+// VK_KHR_swapchain
+extern KWINVULKANUTILS_EXPORT PFN_vkCreateSwapchainKHR pfnCreateSwapchainKHR;
+extern KWINVULKANUTILS_EXPORT PFN_vkDestroySwapchainKHR pfnDestroySwapchainKHR;
+extern KWINVULKANUTILS_EXPORT PFN_vkGetSwapchainImagesKHR pfnGetSwapchainImagesKHR;
+extern KWINVULKANUTILS_EXPORT PFN_vkAcquireNextImageKHR pfnAcquireNextImageKHR;
+extern KWINVULKANUTILS_EXPORT PFN_vkQueuePresentKHR pfnQueuePresentKHR;
+
+// VK_KHR_maintenance1
+extern KWINVULKANUTILS_EXPORT PFN_vkTrimCommandPoolKHR pfnTrimCommandPoolKHR;
+
+// VK_KHR_push_descriptor
+extern KWINVULKANUTILS_EXPORT PFN_vkCmdPushDescriptorSetKHR \
pfnCmdPushDescriptorSetKHR; +
+// VK_KHR_descriptor_update_template
+extern KWINVULKANUTILS_EXPORT PFN_vkCreateDescriptorUpdateTemplateKHR \
pfnCreateDescriptorUpdateTemplateKHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkDestroyDescriptorUpdateTemplateKHR pfnDestroyDescriptorUpdateTemplateKHR; \
+extern KWINVULKANUTILS_EXPORT PFN_vkUpdateDescriptorSetWithTemplateKHR \
pfnUpdateDescriptorSetWithTemplateKHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkCmdPushDescriptorSetWithTemplateKHR pfnCmdPushDescriptorSetWithTemplateKHR; +
+// VK_EXT_debug_report
+extern KWINVULKANUTILS_EXPORT PFN_vkCreateDebugReportCallbackEXT \
pfnCreateDebugReportCallbackEXT; +extern KWINVULKANUTILS_EXPORT \
PFN_vkDestroyDebugReportCallbackEXT pfnDestroyDebugReportCallbackEXT; +extern \
KWINVULKANUTILS_EXPORT PFN_vkDebugReportMessageEXT pfnDebugReportMessageEXT; \
+ +// VK_KHR_get_physical_device_properties2
+extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceFeatures2KHR \
pfnGetPhysicalDeviceFeatures2KHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceProperties2KHR \
pfnGetPhysicalDeviceProperties2KHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceFormatProperties2KHR \
pfnGetPhysicalDeviceFormatProperties2KHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceImageFormatProperties2KHR \
pfnGetPhysicalDeviceImageFormatProperties2KHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR \
pfnGetPhysicalDeviceQueueFamilyProperties2KHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceMemoryProperties2KHR \
pfnGetPhysicalDeviceMemoryProperties2KHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR \
pfnGetPhysicalDeviceSparseImageFormatProperties2KHR; +
+// VK_KHR_external_memory_capabilities
+extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR \
pfnGetPhysicalDeviceExternalBufferPropertiesKHR; +
+// VK_KHR_external_memory_fd
+extern KWINVULKANUTILS_EXPORT PFN_vkGetMemoryFdKHR pfnGetMemoryFdKHR;
+extern KWINVULKANUTILS_EXPORT PFN_vkGetMemoryFdPropertiesKHR \
pfnGetMemoryFdPropertiesKHR; +
+// VK_KHR_external_semaphore_capabilities
+extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR \
pfnGetPhysicalDeviceExternalSemaphorePropertiesKHR; +
+// VK_KHR_external_semaphore_fd
+extern KWINVULKANUTILS_EXPORT PFN_vkImportSemaphoreFdKHR pfnImportSemaphoreFdKHR;
+extern KWINVULKANUTILS_EXPORT PFN_vkGetSemaphoreFdKHR pfnGetSemaphoreFdKHR;
+
+// VK_KHR_get_memory_requirements2
+extern KWINVULKANUTILS_EXPORT PFN_vkGetImageMemoryRequirements2KHR \
pfnGetImageMemoryRequirements2KHR; +extern KWINVULKANUTILS_EXPORT \
PFN_vkGetBufferMemoryRequirements2KHR pfnGetBufferMemoryRequirements2KHR; \
+extern KWINVULKANUTILS_EXPORT PFN_vkGetImageSparseMemoryRequirements2KHR \
pfnGetImageSparseMemoryRequirements2KHR; +
+// VK_EXT_discard_rectangles
+extern KWINVULKANUTILS_EXPORT PFN_vkCmdSetDiscardRectangleEXT \
pfnCmdSetDiscardRectangleEXT; +
+// VK_KHR_bind_memory2
+extern KWINVULKANUTILS_EXPORT PFN_vkBindBufferMemory2KHR pfnBindBufferMemory2KHR;
+extern KWINVULKANUTILS_EXPORT PFN_vkBindImageMemory2KHR pfnBindImageMemory2KHR;
+
+void KWINVULKANUTILS_EXPORT resolveFunctions(VkInstance instance);
+
+} // namespace KWin
+
+#endif // KWINVULKANUTILS_FUNCS_H
+
diff --git a/libkwineffects/logging.cpp b/libkwineffects/logging.cpp
index 6b2c61e9d..906ec52e8 100644
--- a/libkwineffects/logging.cpp
+++ b/libkwineffects/logging.cpp
@@ -21,3 +21,4 @@ along with this program. If not, see \
<http://www.gnu.org/licenses/>. Q_LOGGING_CATEGORY(LIBKWINEFFECTS, "libkwineffects", \
QtCriticalMsg) Q_LOGGING_CATEGORY(LIBKWINGLUTILS, "libkwinglutils", QtCriticalMsg)
Q_LOGGING_CATEGORY(LIBKWINXRENDERUTILS, "libkwinxrenderutils", QtCriticalMsg)
+Q_LOGGING_CATEGORY(LIBKWINVULKANUTILS, "libkwinvulkanutils", QtCriticalMsg)
diff --git a/libkwineffects/logging_p.h b/libkwineffects/logging_p.h
index 394d3d535..0ab084671 100644
--- a/libkwineffects/logging_p.h
+++ b/libkwineffects/logging_p.h
@@ -26,5 +26,6 @@ along with this program. If not, see \
<http://www.gnu.org/licenses/>. Q_DECLARE_LOGGING_CATEGORY(LIBKWINEFFECTS)
Q_DECLARE_LOGGING_CATEGORY(LIBKWINGLUTILS)
Q_DECLARE_LOGGING_CATEGORY(LIBKWINXRENDERUTILS)
+Q_DECLARE_LOGGING_CATEGORY(LIBKWINVULKANUTILS)
#endif
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic