From kde-commits Fri Feb 16 17:01:48 2018 From: =?utf-8?q?Fredrik_H=C3=B6glund?= Date: Fri, 16 Feb 2018 17:01:48 +0000 To: kde-commits Subject: [kwin/fredrik/vulkan] libkwineffects: Add libkwinvulkanutils Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=151880053608147 Git commit a39b24ec410ab7f066b159d0cf6d2f42329495ff by Fredrik H=C3=B6glund. 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_NA= ME ${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 EXPOR= T_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::C= onfigCore KF5::CoreAddons KF5::WindowSystem Vulkan::Vulkan) + install(TARGETS kwinvulkanutils EXPORT kdeworkspaceLibraryTargets ${IN= STALL_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/kwinvulkan= utils.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 =C2=A9 2017-2018 Fredrik H=C3=B6glund + +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 . +*********************************************************************/ + +#include "kwinvulkanutils.h" + +#include "kwineffects.h" +#include "../utils.h" +#include "logging_p.h" + +#include +#include + + +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 =3D static_cast(pNext); + if (header->sType =3D=3D sType) + return pNext; + + pNext =3D header->pNext; + } + + return nullptr; +} + + +// Returns the VkStructureType enumerator corresponding to T +template constexpr VkStructureType getStructureType() { retur= n VK_STRUCTURE_TYPE_MAX_ENUM; } + +template <> constexpr VkStructureType getStructureType() { return VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_K= HR; } +template <> constexpr VkStructureType getStructureType() { return VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; } +template <> constexpr VkStructureType getStructureType() { return VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR= ; } + + +// Finds the first struct of type T in the pNext chain given by pNext +template +const T *findNext(const void *pNext) +{ + const VkStructureType sType =3D getStructureType(); + static_assert(sType !=3D VK_STRUCTURE_TYPE_MAX_ENUM); + return static_cast(findNextImpl(pNext, sType)); +} + + + +// ------------------------------------------------------------------ + + + +VulkanDeviceMemoryAllocator::VulkanDeviceMemoryAllocator(VulkanDevice *dev= ice, const std::vector &enabledDeviceExtensions) + : m_device(device) +{ + VulkanPhysicalDevice gpu =3D device->physicalDevice(); + gpu.getMemoryProperties(&m_memoryProperties); + + auto extensionEnabled =3D [&](const char *extension) -> bool { + return std::find_if(enabledDeviceExtensions.cbegin(), enabledDevic= eExtensions.cend(), + [=3D](const char *entry) { return strcmp(exten= sion, entry) =3D=3D 0; }) !=3D enabledDeviceExtensions.cend(); + }; + + m_haveExternalMemory =3D extensionEnabled(VK_KHR_EXTERNAL_MEMO= RY_EXTENSION_NAME); + m_haveExternalMemoryFd =3D extensionEnabled(VK_KHR_EXTERNAL_MEMO= RY_FD_EXTENSION_NAME); + m_haveDedicatedAllocation =3D extensionEnabled(VK_KHR_DEDICATED_ALL= OCATION_EXTENSION_NAME); + m_haveGetMemoryRequirements2 =3D extensionEnabled(VK_KHR_GET_MEMORY_RE= QUIREMENTS_2_EXTENSION_NAME); + m_haveBindMemory2 =3D extensionEnabled(VK_KHR_BIND_MEMORY_2= _EXTENSION_NAME); + m_haveExternalMemoryDmaBuf =3D extensionEnabled(VK_EXT_EXTERNAL_MEMO= RY_DMA_BUF_EXTENSION_NAME); +} + + +VulkanDeviceMemoryAllocator::~VulkanDeviceMemoryAllocator() +{ +} + + +int VulkanDeviceMemoryAllocator::findMemoryType(uint32_t memoryTypeBits, V= kMemoryPropertyFlags mask) const +{ + for (unsigned int i =3D 0; i < m_memoryProperties.memoryTypeCount; i++= ) { + if (memoryTypeBits & (1 << i) && + (m_memoryProperties.memoryTypes[i].propertyFlags & mask) =3D= =3D mask) { + return i; + } + } + + return -1; +} + + +std::shared_ptr VulkanDeviceMemoryAllocator::allocateM= emory(VkDeviceSize size, + = uint32_t memoryTypeBits, + = VkMemoryPropertyFlags optimal, + = VkMemoryPropertyFlags required) +{ + return allocateMemoryInternal(size, memoryTypeBits, optimal, required,= nullptr); +} + + +std::shared_ptr VulkanDeviceMemoryAllocator::allocateM= emory(std::shared_ptr &image, + = VkMemoryPropertyFlags optimal, VkMemoryPropertyFlags required) +{ + // Out + VkMemoryDedicatedRequirementsKHR dedicatedRequirements =3D { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR, + .pNext =3D nullptr, + .prefersDedicatedAllocation =3D VK_FALSE, + .requiresDedicatedAllocation =3D VK_FALSE + }; + + VkMemoryRequirements2KHR memoryRequirements2 =3D { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR, + .pNext =3D &dedicatedRequirements, + .memoryRequirements =3D {} + }; + + if (m_haveGetMemoryRequirements2 && m_haveDedicatedAllocation) { + m_device->getImageMemoryRequirements2KHR(VkImageMemoryRequirements= Info2KHR { + .sType =3D VK_STRUCT= URE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR, + .pNext =3D nullptr, + .image =3D image->ha= ndle() + }, &memoryRequirements2); + } else { + m_device->getImageMemoryRequirements(image->handle(), &memoryRequi= rements2.memoryRequirements); + } + + const VkMemoryRequirements &memoryRequirements =3D memoryRequirements2= .memoryRequirements; + + const VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + .pNext =3D nullptr, + .image =3D image->handle(), + .buffer =3D VK_NULL_HANDLE + }; + + const void *pAllocateInfoNext =3D nullptr; + + if (dedicatedRequirements.prefersDedicatedAllocation || dedicatedRequi= rements.requiresDedicatedAllocation) + pAllocateInfoNext =3D &dedicatedAllocateInfo; + + auto memory =3D allocateMemoryInternal(memoryRequirements.size, memory= Requirements.memoryTypeBits, + optimal, required, pAllocateInfoN= ext); + + if (memory) { + m_device->bindImageMemory(image->handle(), memory->handle(), 0); + } + + return memory; +} + + +std::shared_ptr VulkanDeviceMemoryAllocator::allocateM= emory(std::shared_ptr &buffer, + = VkMemoryPropertyFlags optimal, VkMemoryPropertyFlags required) +{ + // Out + VkMemoryDedicatedRequirementsKHR dedicatedRequirements =3D { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR, + .pNext =3D nullptr, + .prefersDedicatedAllocation =3D VK_FALSE, + .requiresDedicatedAllocation =3D VK_FALSE + }; + + VkMemoryRequirements2KHR memoryRequirements2 =3D { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR, + .pNext =3D &dedicatedRequirements, + .memoryRequirements =3D {} + }; + + if (m_haveGetMemoryRequirements2 && m_haveDedicatedAllocation) { + m_device->getBufferMemoryRequirements2KHR(VkBufferMemoryRequiremen= tsInfo2KHR { + .sType =3D VK_STRUCT= URE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR, + .pNext =3D nullptr, + .buffer =3D buffer->= handle() + }, &memoryRequirements2); + } else { + m_device->getBufferMemoryRequirements(buffer->handle(), &memoryReq= uirements2.memoryRequirements); + } + + const VkMemoryRequirements &memoryRequirements =3D memoryRequirements2= .memoryRequirements; + + const VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + .pNext =3D nullptr, + .image =3D VK_NULL_HANDLE, + .buffer =3D buffer->handle() + }; + + const void *pAllocateInfoNext =3D nullptr; + + if (dedicatedRequirements.prefersDedicatedAllocation || dedicatedRequi= rements.requiresDedicatedAllocation) + pAllocateInfoNext =3D &dedicatedAllocateInfo; + + auto memory =3D allocateMemoryInternal(memoryRequirements.size, memory= Requirements.memoryTypeBits, + optimal, required, pAllocateInfoN= ext); + + if (memory) { + m_device->bindBufferMemory(buffer->handle(), memory->handle(), 0); + } + + return memory; +} + + +std::shared_ptr VulkanDeviceMemoryAllocator::allocateM= emoryInternal(VkDeviceSize size, + = uint32_t memoryTypeBits, + = VkMemoryPropertyFlags optimal, + = VkMemoryPropertyFlags required, + = const void *pAllocateInfoNext) +{ + VkDeviceMemory memory =3D VK_NULL_HANDLE; + int index =3D -1; + + const auto *dedicatedRequirements =3D findNext(pAllocateInfoNext); + const auto *importMemoryFdInfo =3D findNext(pAllocateInfoNext); + const auto *exportMemoryAllocateInfo =3D findNext(pAllocateInfoNext); + + while (memory =3D=3D VK_NULL_HANDLE) { + index =3D findMemoryType(memoryTypeBits, optimal); + + if (index =3D=3D -1) + index =3D findMemoryType(memoryTypeBits, required); + + if (index =3D=3D -1) + break; + + const VkMemoryAllocateInfo allocateInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext =3D pAllocateInfoNext, + .allocationSize =3D size, + .memoryTypeIndex =3D (uint32_t) index + }; + + VkResult result =3D m_device->allocateMemory(&allocateInfo, nullpt= r, &memory); + if (result !=3D VK_SUCCESS) { + if (result =3D=3D VK_ERROR_OUT_OF_DEVICE_MEMORY) { + // Clear the memory type bit and try again + memoryTypeBits &=3D ~(1 << index); + continue; + } + break; + } + } + + if (memory =3D=3D VK_NULL_HANDLE) { + qCCritical(LIBKWINVULKANUTILS) << "Failed to allocate" << size << = "bytes of device memory"; + return std::shared_ptr(); + } + + return std::make_shared(VulkanDeviceMemory::Create= Info { + .device =3D m_device, + .memory =3D memory, + .size =3D size, + .flags =3D m_memoryPro= perties.memoryTypes[index].propertyFlags, + .exportableHandleTypes= =3D exportMemoryAllocateInfo ? + exportMemoryAl= locateInfo->handleTypes : 0, + .dedicated =3D dedicat= edRequirements !=3D nullptr, + .imported =3D importMe= moryFdInfo !=3D 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 =3D file.readAll(); + + const VkShaderModuleCreateInfo createInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .codeSize =3D (size_t) code.size(), + .pCode =3D (uint32_t *) code.constData() + }; + + if (m_device->createShaderModule(&createInfo, nullptr, &m_shaderModule= ) !=3D VK_SUCCESS) { + qCCritical(LIBKWINVULKANUTILS) << "Failed to create shader module = for" << fileName; + } +} + + + +// -------------------------------------------------------------------- + + + +VulkanPipelineManager::VulkanPipelineManager(VulkanDevice *device, VulkanP= ipelineCache *cache, + VkSampler nearestSampler, VkS= ampler linearSampler, + VkRenderPass swapchainRenderP= ass, VkRenderPass offscreenRenderPass, + bool havePushDescriptors) + : m_device(device), + m_pipelineCache(cache), + m_nearestSampler(nearestSampler), + m_linearSampler(linearSampler), + m_havePushDescriptors(havePushDescriptors) +{ + m_renderPasses[SwapchainRenderPass] =3D swapchainRenderPass; + m_renderPasses[OffscreenRenderPass] =3D offscreenRenderPass; + + for (int i =3D 0; i < MaterialCount; i++) { + m_descriptorSetLayout[i] =3D VK_NULL_HANDLE; + m_pipelineLayout[i] =3D VK_NULL_HANDLE; + m_pushDescriptorSetLayout[i] =3D VK_NULL_HANDLE; + m_pushDescriptorPipelineLayout[i] =3D VK_NULL_HANDLE; + } + + const struct { + QString fileName; + VulkanShaderModule &module; + } modules[] =3D { + { 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 =3D true; + + for (auto &entry : modules) { + entry.module =3D VulkanShaderModule(m_device, entry.fileName); + m_valid =3D m_valid && entry.module.isValid(); + } + + m_valid =3D m_valid && createDescriptorSetLayouts(); + m_valid =3D m_valid && createPipelineLayouts(); +} + + +VulkanPipelineManager::~VulkanPipelineManager() +{ + for (const std::pair &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 =3D true; + + struct CreateInfo { + VkDescriptorSetLayoutCreateFlags flags; + std::initializer_list bindings; + }; + + auto create =3D [&](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 =3D m_device->createDescriptorSetLayout({ + .sType =3D VK_STR= UCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext =3D nullpt= r, + .flags =3D info.f= lags, + .bindingCount =3D= (uint32_t) info.bindings.size(), + .pBindings =3D in= fo.bindings.begin() + }, nullptr, &layout); + + if (result !=3D VK_SUCCESS) { + qCCritical(LIBKWINVULKANUTILS) << "Failed to create a descript= or set layout"; + valid =3D false; + } + + return layout; + }; + + + // layout (set =3D N, binding =3D 0) uniform UBO { + // mat4 matrix; + // vec4 color; + // } + m_descriptorSetLayout[FlatColor] =3D + create({ + .flags =3D 0, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_UNIF= ORM_BUFFER_DYNAMIC, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_VERTEX_BIT = | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers =3D nullptr + } + } + }); + + m_pushDescriptorSetLayout[FlatColor] =3D + create({ + .flags =3D VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DES= CRIPTOR_BIT_KHR, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_UNIF= ORM_BUFFER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_VERTEX_BIT = | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers =3D nullptr + } + } + }); + + + // layout (set =3D N, binding =3D 0) uniform sampler2D texture; + // layout (set =3D N, binding =3D 1) uniform UBO { + // mat4 matrix; + // ... + // } + m_descriptorSetLayout[Texture] =3D + create({ + .flags =3D 0, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_COMB= INED_IMAGE_SAMPLER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 1, + .descriptorType =3D VK_DESCRIPTOR_TYPE_UNIF= ORM_BUFFER_DYNAMIC, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_VERTEX_BIT = | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers =3D nullptr + } + } + }); + + m_pushDescriptorSetLayout[Texture] =3D + create({ + .flags =3D VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DES= CRIPTOR_BIT_KHR, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_COMB= INED_IMAGE_SAMPLER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 1, + .descriptorType =3D VK_DESCRIPTOR_TYPE_UNIF= ORM_BUFFER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_VERTEX_BIT = | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers =3D nullptr + } + } + }); + + // layout (set =3D N, binding =3D 0) uniform texture2D textures[2]; + // layout (set =3D N, binding =3D 1) uniform sampler sampler { + // layout (set =3D N, binding =3D 2) uniform UBO { + // mat4 matrix; + // ... + // } + m_descriptorSetLayout[TwoTextures] =3D + create({ + .flags =3D 0, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LED_IMAGE, + .descriptorCount =3D 2, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 1, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 2, + .descriptorType =3D VK_DESCRIPTOR_TYPE_UNIF= ORM_BUFFER_DYNAMIC, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_VERTEX_BIT = | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers =3D nullptr + } + } + }); + + + m_pushDescriptorSetLayout[TwoTextures] =3D + create({ + .flags =3D VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DES= CRIPTOR_BIT_KHR, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LED_IMAGE, + .descriptorCount =3D 2, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 1, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 2, + .descriptorType =3D VK_DESCRIPTOR_TYPE_UNIF= ORM_BUFFER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_VERTEX_BIT = | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers =3D nullptr + } + } + }); + + // layout (set =3D N, binding =3D 0) uniform texture2D textures[4]; + // layout (set =3D N, binding =3D 1) uniform sampler sampler { + m_descriptorSetLayout[DecorationStagingImages] =3D + create({ + .flags =3D 0, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LED_IMAGE, + .descriptorCount =3D 4, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 1, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D &m_nearestSampler + } + } + }); + + m_pushDescriptorSetLayout[DecorationStagingImages] =3D + create({ + .flags =3D VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DES= CRIPTOR_BIT_KHR, + .bindings =3D { + { + .binding =3D 0, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LED_IMAGE, + .descriptorCount =3D 4, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D nullptr + }, + { + .binding =3D 1, + .descriptorType =3D VK_DESCRIPTOR_TYPE_SAMP= LER, + .descriptorCount =3D 1, + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .pImmutableSamplers =3D &m_nearestSampler + } + } + }); + + return valid; +} + + +bool VulkanPipelineManager::createPipelineLayouts() +{ + bool valid =3D true; + + auto create =3D [&](const std::initializer_list= setLayouts, + const std::initializer_list pus= hConstantRanges =3D {}) { + VkPipelineLayout layout =3D VK_NULL_HANDLE; + VkResult result =3D m_device->createPipelineLayout({ + .sType =3D VK= _STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext =3D nu= llptr, + .flags =3D 0, + .setLayoutCou= nt =3D (uint32_t) setLayouts.size(), + .pSetLayouts = =3D setLayouts.begin(), + .pushConstant= RangeCount =3D (uint32_t) pushConstantRanges.size(), + .pPushConstan= tRanges =3D pushConstantRanges.begin() + }, nullptr, &layo= ut); + if (result !=3D VK_SUCCESS) { + qCCritical(LIBKWINVULKANUTILS) << "Failed to create a pipeline= layout"; + valid =3D false; + } + + return layout; + }; + + for (int i =3D 0; i <=3D TwoTextures; i++) { + m_pipelineLayout[i] =3D create({m_descriptorSetLayout[i]}); + + if (m_havePushDescriptors) + m_pushDescriptorPipelineLayout[i] =3D create({m_pushDescriptor= SetLayout[i]}); + else + m_pushDescriptorPipelineLayout[i] =3D VK_NULL_HANDLE; + } + + m_pipelineLayout[DecorationStagingImages] =3D + create({ + m_descriptorSetLayout[DecorationStagingImages] + }, + { + { + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BIT, + .offset =3D 0, + .size =3D sizeof(uint32_t) + } + }); + + if (m_havePushDescriptors) { + m_pushDescriptorPipelineLayout[DecorationStagingImages] =3D + create({ + m_pushDescriptorSetLayout[DecorationStagingImag= es] + }, + { + { + .stageFlags =3D VK_SHADER_STAGE_FRAGMENT_BI= T, + .offset =3D 0, + .size =3D sizeof(uint32_t) + } + }); + } else { + m_pushDescriptorPipelineLayout[DecorationStagingImages] =3D VK_NUL= L_HANDLE; + } + + return valid; +} + + +VkPipeline VulkanPipelineManager::createPipeline(Material material, Traits= traits, DescriptorType descriptorType, Topology topology, VkRenderPass ren= derPass) +{ + // Viewport state + // -------------- + static const VkViewport viewport =3D { + .x =3D 0.0f, + .y =3D 0.0f, + .width =3D 1.0f, + .height =3D 1.0f, + .minDepth =3D 0.0f, + .maxDepth =3D 1.0f + }; + + static const VkRect2D scissor =3D { + .offset =3D { 0, 0 }, + .extent =3D { 1, 1 } + }; + + const VkPipelineViewportStateCreateInfo viewportState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .viewportCount =3D 1, + .pViewports =3D &viewport, + .scissorCount =3D 1, + .pScissors =3D &scissor + }; + + + // Rasterization state + // ------------------- + static const VkPipelineRasterizationStateCreateInfo rasterizationState= { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_I= NFO, + .pNext =3D nullptr, + .flags =3D 0, + .depthClampEnable =3D VK_FALSE, + .rasterizerDiscardEnable =3D VK_FALSE, + .polygonMode =3D VK_POLYGON_MODE_FILL, + .cullMode =3D VK_CULL_MODE_NONE, + .frontFace =3D VK_FRONT_FACE_COUNTER_CLOCKWISE, + .depthBiasEnable =3D VK_FALSE, + .depthBiasConstantFactor =3D 0.0f, + .depthBiasClamp =3D 0.0f, + .depthBiasSlopeFactor =3D 0.0f, + .lineWidth =3D 1.0f + }; + + + // Multisample state + // ----------------- + static const VkPipelineMultisampleStateCreateInfo multisampleState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INF= O, + .pNext =3D nullptr, + .flags =3D 0, + .rasterizationSamples =3D VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable =3D VK_FALSE, + .minSampleShading =3D 1.0f, + .pSampleMask =3D nullptr, + .alphaToCoverageEnable =3D VK_FALSE, + .alphaToOneEnable =3D VK_FALSE + }; + + + // Dynamic states + //--------------- + static const VkDynamicState dynamicStates[] { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + + const VkPipelineDynamicStateCreateInfo dynamicState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .dynamicStateCount =3D ARRAY_SIZE(dynamicStates), + .pDynamicStates =3D dynamicStates + }; + + + // Depth-stencil state + // ------------------- + static const VkPipelineDepthStencilStateCreateInfo depthStencilState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_I= NFO, + .pNext =3D nullptr, + .flags =3D 0, + .depthTestEnable =3D VK_FALSE, + .depthWriteEnable =3D VK_FALSE, + .depthCompareOp =3D VK_COMPARE_OP_LESS, + .depthBoundsTestEnable =3D VK_FALSE, + .stencilTestEnable =3D VK_FALSE, + .front =3D { + .failOp =3D VK_STENCIL_OP_KEEP, + .passOp =3D VK_STENCIL_OP_KEEP, + .depthFailOp =3D VK_STENCIL_OP_KEEP, + .compareOp =3D VK_COMPARE_OP_NEVER, + .compareMask =3D 0, + .writeMask =3D 0, + .reference =3D 0 + }, + .back =3D { + .failOp =3D VK_STENCIL_OP_KEEP, + .passOp =3D VK_STENCIL_OP_KEEP, + .depthFailOp =3D VK_STENCIL_OP_KEEP, + .compareOp =3D VK_COMPARE_OP_NEVER, + .compareMask =3D 0, + .writeMask =3D 0, + .reference =3D 0 + }, + .minDepthBounds =3D 0.0f, + .maxDepthBounds =3D 1.0f + }; + + + // Color blend attachment states + // ----------------------------- + static const VkPipelineColorBlendAttachmentState preMultipliedBlendAtt= achment { + .blendEnable =3D VK_TRUE, + .srcColorBlendFactor =3D VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor =3D VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp =3D VK_BLEND_OP_ADD, + .srcAlphaBlendFactor =3D VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor =3D VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp =3D VK_BLEND_OP_ADD, + .colorWriteMask =3D 0xf + }; + + static const VkPipelineColorBlendAttachmentState opaqueBlendAttachment= { + .blendEnable =3D VK_TRUE, + .srcColorBlendFactor =3D VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor =3D VK_BLEND_FACTOR_ZERO, + .colorBlendOp =3D VK_BLEND_OP_ADD, + .srcAlphaBlendFactor =3D VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor =3D VK_BLEND_FACTOR_ZERO, + .alphaBlendOp =3D VK_BLEND_OP_ADD, + .colorWriteMask =3D 0xf + }; + + + // Color blend states + // ------------------ + const VkPipelineColorBlendStateCreateInfo preMultipliedAlphaBlendState= { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INF= O, + .pNext =3D nullptr, + .flags =3D 0, + .logicOpEnable =3D VK_FALSE, + .logicOp =3D VK_LOGIC_OP_COPY, + .attachmentCount =3D 1, + .pAttachments =3D &preMultipliedBlendAttachment, + .blendConstants =3D { 0.0f, 0.0f, 0.0f, 0.0f } + }; + + const VkPipelineColorBlendStateCreateInfo opaqueBlendState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INF= O, + .pNext =3D nullptr, + .flags =3D 0, + .logicOpEnable =3D VK_FALSE, + .logicOp =3D VK_LOGIC_OP_COPY, + .attachmentCount =3D 1, + .pAttachments =3D &opaqueBlendAttachment, + .blendConstants =3D { 0.0f, 0.0f, 0.0f, 0.0f } + }; + + + + // Input assembly states + // --------------------- + const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =3D { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_= INFO, + .pNext =3D nullptr, + .flags =3D 0, + .topology =3D (VkPrimitiveTopology) topology, + .primitiveRestartEnable =3D VK_FALSE + }; + + + // Color inputs + // ------------ + static const VkVertexInputAttributeDescription colorVertexInputAttribs= [] =3D { + { .location =3D 0, .binding =3D 0, .format =3D VK_FORMAT_R32G32_SF= LOAT, .offset =3D 0 }, + }; + + static const VkVertexInputBindingDescription colorVertexInputBindings[= ] { + { .binding =3D 0, .stride =3D sizeof(QVector2D), .inputRate =3D VK= _VERTEX_INPUT_RATE_VERTEX }, + }; + + const VkPipelineVertexInputStateCreateInfo colorVertexInputState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_IN= FO, + .pNext =3D nullptr, + .flags =3D 0, + .vertexBindingDescriptionCount =3D ARRAY_SIZE(colorVertexInputBind= ings), + .pVertexBindingDescriptions =3D colorVertexInputBindings, + .vertexAttributeDescriptionCount =3D ARRAY_SIZE(colorVertexInputAt= tribs), + .pVertexAttributeDescriptions =3D colorVertexInputAttribs + }; + + + // Texture inputs + // -------------- + static const VkVertexInputAttributeDescription textureVertexInputAttri= bs[] =3D { + { .location =3D 0, .binding =3D 0, .format =3D VK_FORMAT_R32G32_SF= LOAT, .offset =3D offsetof(GLVertex2D, position) }, + { .location =3D 1, .binding =3D 0, .format =3D VK_FORMAT_R32G32_SF= LOAT, .offset =3D offsetof(GLVertex2D, texcoord) }, + }; + + static const VkVertexInputBindingDescription textureVertexInputBinding= s[] { + { .binding =3D 0, .stride =3D sizeof(GLVertex2D), .inputRate =3D V= K_VERTEX_INPUT_RATE_VERTEX }, + }; + + const VkPipelineVertexInputStateCreateInfo textureVertexInputState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_IN= FO, + .pNext =3D nullptr, + .flags =3D 0, + .vertexBindingDescriptionCount =3D ARRAY_SIZE(textureVertexInputBi= ndings), + .pVertexBindingDescriptions =3D textureVertexInputBindings, + .vertexAttributeDescriptionCount =3D ARRAY_SIZE(textureVertexInput= Attribs), + .pVertexAttributeDescriptions =3D textureVertexInputAttribs + }; + + + // Cross-fade inputs + // ----------------- + static const VkVertexInputAttributeDescription crossFadeVertexInputAtt= ribs[] =3D { + { .location =3D 0, .binding =3D 0, .format =3D VK_FORMAT_R32G32_SF= LOAT, .offset =3D offsetof(GLCrossFadeVertex2D, position) }, + { .location =3D 1, .binding =3D 0, .format =3D VK_FORMAT_R32G32_SF= LOAT, .offset =3D offsetof(GLCrossFadeVertex2D, texcoord1) }, + { .location =3D 2, .binding =3D 0, .format =3D VK_FORMAT_R32G32_SF= LOAT, .offset =3D offsetof(GLCrossFadeVertex2D, texcoord2) }, + }; + + static const VkVertexInputBindingDescription crossFadeVertexInputBindi= ngs[] { + { .binding =3D 0, .stride =3D sizeof(GLCrossFadeVertex2D), .inputR= ate =3D VK_VERTEX_INPUT_RATE_VERTEX }, + }; + + const VkPipelineVertexInputStateCreateInfo crossFadeVertexInputState { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_IN= FO, + .pNext =3D nullptr, + .flags =3D 0, + .vertexBindingDescriptionCount =3D ARRAY_SIZE(crossFadeVertexInput= Bindings), + .pVertexBindingDescriptions =3D crossFadeVertexInputBindings, + .vertexAttributeDescriptionCount =3D ARRAY_SIZE(crossFadeVertexInp= utAttribs), + .pVertexAttributeDescriptions =3D crossFadeVertexInputAttribs + }; + + const VkPipelineVertexInputStateCreateInfo *vertexInputState =3D nullp= tr; + const VkPipelineColorBlendStateCreateInfo *blendState =3D nullptr; + VkShaderModule fs =3D VK_NULL_HANDLE; + VkShaderModule vs =3D VK_NULL_HANDLE; + VkPipelineLayout layout; + + if (descriptorType =3D=3D PushDescriptors) + layout =3D m_pushDescriptorPipelineLayout[material]; + else + layout =3D m_pipelineLayout[material]; + + if (traits & PreMultipliedAlphaBlend) + blendState =3D &preMultipliedAlphaBlendState; + else + blendState =3D &opaqueBlendState; + + switch (material) { + case FlatColor: + vertexInputState =3D &colorVertexInputState; + vs =3D m_colorVertexShader; + fs =3D m_colorFragmentShader; + break; + + case Texture: + vertexInputState =3D &textureVertexInputState; + vs =3D m_textureVertexShader; + if (traits & Desaturate) + fs =3D m_desaturateFragmentShader; + else if (traits & Modulate) + fs =3D m_modulateFragmentShader; + else + fs =3D m_textureFragmentShader; + break; + + case TwoTextures: + vertexInputState =3D &crossFadeVertexInputState; + vs =3D m_crossFadeVertexShader; + fs =3D m_crossFadeFragmentShader; + break; + + case DecorationStagingImages: + vertexInputState =3D &textureVertexInputState; + vs =3D m_updateDecorationVertexShader; + fs =3D m_updateDecorationFragmentShader; + break; + + default: + break; + }; + + + // Shader stages + // ------------- + const VkPipelineShaderStageCreateInfo pipelineStages[] { + // Vertex shader + { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .stage =3D VK_SHADER_STAGE_VERTEX_BIT, + .module =3D vs, + .pName =3D "main", + .pSpecializationInfo =3D nullptr + }, + // Fragment shader + { + .sType =3D VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .stage =3D VK_SHADER_STAGE_FRAGMENT_BIT, + .module =3D fs, + .pName =3D "main", + .pSpecializationInfo =3D nullptr + } + }; + + const VkGraphicsPipelineCreateInfo createInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .stageCount =3D ARRAY_SIZE(pipelineStages), + .pStages =3D pipelineStages, + .pVertexInputState =3D vertexInputState, + .pInputAssemblyState =3D &inputAssemblyState, + .pTessellationState =3D nullptr, + .pViewportState =3D &viewportState, + .pRasterizationState =3D &rasterizationState, + .pMultisampleState =3D &multisampleState, + .pDepthStencilState =3D &depthStencilState, + .pColorBlendState =3D blendState, + .pDynamicState =3D &dynamicState, + .layout =3D layout, + .renderPass =3D renderPass, + .subpass =3D 0, + .basePipelineHandle =3D VK_NULL_HANDLE, + .basePipelineIndex =3D 0 + }; + + VkPipeline pipeline; + const VkResult result =3D m_device->createGraphicsPipelines(m_pipeline= Cache->handle(), 1, &createInfo, nullptr, &pipeline); + + if (result !=3D VK_SUCCESS) { + qCCritical(LIBKWINVULKANUTILS) << "vkCreateGraphicsPipelines retur= ned" << enumToString(result); + return VK_NULL_HANDLE; + } + + return pipeline; +} + + +std::tuple VulkanPipelineManager::pipeline(M= aterial material, + T= raits traits, + D= escriptorType descriptorType, + T= opology topology, + R= enderPassType 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 =3D 0; + + key.u.material =3D material; + key.u.traits =3D traits; + key.u.topology =3D topology; + key.u.descriptorType =3D descriptorType; + key.u.renderPassType =3D renderPassType; + + VkPipeline &pipe =3D m_pipelines[key.value]; + + if (pipe =3D=3D VK_NULL_HANDLE) + pipe =3D createPipeline(material, traits, descriptorType, topology= , m_renderPasses[renderPassType]); + + const VkPipelineLayout layout =3D descriptorType =3D=3D PushDescriptor= s ? + m_pushDescriptorPipelineLayout[material] : + m_pipelineLayout[material]; + + return std::tuple(pipe, layout); +} + + + +// -------------------------------------------------------------------- + + + +class VulkanCircularAllocatorBase::CircularBuffer : public std::enable_sha= red_from_this +{ +public: + struct BusyOffset { + BusyOffset(const BusyOffset &) =3D delete; + BusyOffset(BusyOffset &&) =3D default; + ~BusyOffset() { if (m_buffer) m_buffer->m_tail =3D m_offset; } + BusyOffset &operator =3D (const BusyOffset &) =3D delete; + BusyOffset &operator =3D (BusyOffset &&) =3D default; + std::shared_ptr m_buffer; + uint32_t m_offset; + }; + + CircularBuffer(const std::shared_ptr &buffer, const std:= :shared_ptr &memory, uint8_t *data, uint32_t size) + : m_buffer(buffer), m_memory(memory), m_size(size), m_data(data) {} + + CircularBuffer(const std::shared_ptr &memory, uint= 8_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 !=3D m_lastBusyOffset; } + + void getNonCoherentAllocatedRanges(std::back_insert_iterator> &it, VkDeviceSize nonCoherentAtomSize); + BusyOffset busyOffset(); + + std::shared_ptr buffer() const { return m_buffer; } + std::shared_ptr 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 m_buffer; + std::shared_ptr m_memory; + uint32_t m_head =3D 0; + uint32_t m_tail =3D 0; + uint32_t m_size =3D 0; + uint32_t m_nextWrapAroundOffset =3D 0; + uint32_t m_lastBusyOffset =3D 0; + uint32_t m_flushedOffset =3D 0; + uint8_t *m_data =3D nullptr; + + friend class BusyOffset; +}; + + +bool VulkanCircularAllocatorBase::CircularBuffer::allocate(size_t allocati= onSize, 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 =3D align(m_head, alignment); + + // Handle wrap around + uint32_t wrapAroundOffset =3D m_nextWrapAroundOffset; + if (offset + allocationSize > wrapAroundOffset) { + offset =3D wrapAroundOffset; + wrapAroundOffset +=3D m_size; + } + + // Make sure there is enough free space for the allocation + if (m_tail + m_size - offset < allocationSize) + return false; + + m_head =3D offset + allocationSize; + m_nextWrapAroundOffset =3D wrapAroundOffset; + + *pOffset =3D offset & (m_size - 1); + return true; +} + + +void VulkanCircularAllocatorBase::CircularBuffer::getNonCoherentAllocatedR= anges(std::back_insert_iterator> &it, VkDe= viceSize nonCoherentAtomSize) +{ + if (!m_memory || m_memory->isHostCoherent()) + return; + + if (m_flushedOffset =3D=3D m_head) + return; + + uint32_t start =3D m_flushedOffset & ~(nonCoherentAtomSize - 1); // Ro= und down + uint32_t end =3D align(m_head, nonCoherentAtomSize); // Ro= und up + + if ((end - start) >=3D m_buffer->size()) { + *it++ =3D VkMappedMemoryRange { + .sType =3D VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .pNext =3D nullptr, + .memory =3D m_memory->handle(), + .offset =3D 0, + .size =3D VK_WHOLE_SIZE + }; + } else { + const uint32_t mask =3D m_buffer->size() - 1; + start &=3D mask; + end &=3D mask; + + assert(!(m_memory->size() & (nonCoherentAtomSize - 1))); + assert(end <=3D m_memory->size()); + + if (start < end) { + *it++ =3D VkMappedMemoryRange { + .sType =3D VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .pNext =3D nullptr, + .memory =3D m_memory->handle(), + .offset =3D start, + .size =3D end - start + }; + } else { + // We have wrapped around and have dirty ranges at both the be= ginning + // and the end of the buffer + *it++ =3D VkMappedMemoryRange { + .sType =3D VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .pNext =3D nullptr, + .memory =3D m_memory->handle(), + .offset =3D 0, + .size =3D end + }; + + *it++ =3D VkMappedMemoryRange { + .sType =3D VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .pNext =3D nullptr, + .memory =3D m_memory->handle(), + .offset =3D start, + .size =3D m_memory->size() - start + }; + } + } + + m_flushedOffset =3D m_head; +} + + +VulkanCircularAllocatorBase::CircularBuffer::BusyOffset VulkanCircularAllo= catorBase::CircularBuffer::busyOffset() +{ + if (m_lastBusyOffset !=3D m_head) { + m_lastBusyOffset =3D m_head; + return BusyOffset{shared_from_this(), m_head}; + } + + return BusyOffset{nullptr, 0}; +} + + + +// ------------------------------------------------------------------- + + + +VulkanCircularAllocatorBase::VulkanCircularAllocatorBase(VulkanDevice *dev= ice, uint32_t nonCoherentAtomSize) + : m_device(device), + m_nonCoherentAtomSize(nonCoherentAtomSize) +{ +} + + +VulkanCircularAllocatorBase::~VulkanCircularAllocatorBase() +{ +} + + +void VulkanCircularAllocatorBase::getNonCoherentAllocatedRanges(std::back_= insert_iterator> it) +{ + for (auto &buffer : m_orphanedBuffers) + buffer->getNonCoherentAllocatedRanges(it, m_nonCoherentAtomSize); + + if (m_circularBuffer) + m_circularBuffer->getNonCoherentAllocatedRanges(it, m_nonCoherentA= tomSize); +} + + +std::shared_ptr VulkanCircularAllocatorBase::createFrameBoun= dary() +{ + struct FrameBoundary : public VulkanObject + { + FrameBoundary(CircularBuffer::BusyOffset &&offset, std::vector> &&buffers) + : offset(std::move(offset)), buffers(std::move(buffers)) {} + CircularBuffer::BusyOffset offset; + std::vector> buffers; + }; + + std::shared_ptr boundary; + + if (m_circularBuffer) + boundary =3D std::make_shared(m_circularBuffer->bus= yOffset(), std::move(m_orphanedBuffers)); + else + boundary =3D std::make_shared(CircularBuffer::BusyO= ffset{nullptr, 0}, std::move(m_orphanedBuffers)); + + m_orphanedBuffers =3D std::vector>(); + return boundary; +} + + + +// ------------------------------------------------------------------- + + + +VulkanUploadManager::VulkanUploadManager(VulkanDevice *device, + VulkanDeviceMemoryAllocator *allo= cator, + size_t initialSize, + VkBufferUsageFlags bufferUsage, + VkMemoryPropertyFlags optimalFlag= s, + const VkPhysicalDeviceLimits &lim= its) + : VulkanCircularAllocatorBase(device, limits.nonCoherentAtomSize), + m_allocator(allocator), + m_initialSize(initialSize), + m_bufferUsage(bufferUsage), + m_optimalMemoryFlags(optimalFlags), + m_minTexelBufferOffsetAlignment(limits.minTexelBufferOffsetAlignment= ), + m_minUniformBufferOffsetAlignment(limits.minUniformBufferOffsetAlign= ment), + m_minStorageBufferOffsetAlignment(limits.minStorageBufferOffsetAlign= ment) +{ + // The size must be a power-of-two + assert(initialSize =3D=3D (initialSize & -initialSize)); +} + + +VulkanUploadManager::~VulkanUploadManager() +{ +} + + +VulkanBufferRange VulkanUploadManager::allocate(size_t size, uint32_t alig= nment) +{ + uint32_t offset =3D 0; + + if (!m_circularBuffer || !m_circularBuffer->allocate(size, alignment, = &offset)) { + reallocate(size); + + if (!m_circularBuffer || !m_circularBuffer->allocate(size, alignme= nt, &offset)) + return VulkanBufferRange(); + } + + return VulkanBufferRange(m_circularBuffer->buffer(), offset, size, m_c= ircularBuffer->data() + offset); +} + + +void VulkanUploadManager::reallocate(size_t minimumSize) +{ + size_t newSize =3D (m_circularBuffer && m_circularBuffer->size() > 0) = ? m_circularBuffer->size() * 2 : m_initialSize; + while (newSize < minimumSize) + newSize *=3D 2; + + newSize =3D align(newSize, m_nonCoherentAtomSize); + + // The size must be a power-of-two + assert(newSize =3D=3D (newSize & -newSize)); + + if (m_circularBuffer && m_circularBuffer->isBusy()) + m_orphanedBuffers.push_back(m_circularBuffer); + + m_circularBuffer =3D nullptr; + + auto buffer =3D std::make_shared(m_device, + VkBufferCreateInfo { + .sType =3D VK_STRUCTU= RE_TYPE_BUFFER_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .size =3D newSize, + .usage =3D m_bufferUs= age, + .sharingMode =3D VK_S= HARING_MODE_EXCLUSIVE, + .queueFamilyIndexCoun= t =3D 0, + .pQueueFamilyIndices = =3D nullptr + }); + + if (buffer && buffer->isValid()) { + auto memory =3D m_allocator->allocateMemory(buffer, m_optimalMemor= yFlags, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (memory && memory->isValid()) { + uint8_t *data =3D nullptr; + memory->map(0, (void **) &data); + + m_circularBuffer =3D std::make_shared(buffer, = memory, data, newSize); + } + } +} + + + +// ------------------------------------------------------------------- + + + +VulkanStagingImageAllocator::VulkanStagingImageAllocator(VulkanDevice *dev= ice, + VulkanDeviceMemor= yAllocator *allocator, + size_t initialSiz= e, + VkMemoryPropertyF= lags optimalMemoryFlags, + const VkPhysicalD= eviceLimits &limits) + : VulkanCircularAllocatorBase(device, limits.nonCoherentAtomSize), + m_allocator(allocator), + m_initialSize(initialSize), + m_optimalMemoryFlags(optimalMemoryFlags) +{ + // The size must be a power-of-two + assert(initialSize =3D=3D (initialSize & -initialSize)); +} + + +VulkanStagingImageAllocator::~VulkanStagingImageAllocator() +{ +} + + +std::shared_ptr VulkanStagingImageAllocator::createIma= ge(const VkImageCreateInfo &createInfo) +{ + auto image =3D std::make_shared(m_device, createIn= fo); + if (!image->isValid()) + return nullptr; + + VkMemoryRequirements memoryRequirements; + m_device->getImageMemoryRequirements(image->handle(), &memoryRequireme= nts); + + uint32_t offset =3D 0; + if (!m_circularBuffer || !m_circularBuffer->allocate(memoryRequirement= s.size, memoryRequirements.alignment, &offset)) { + reallocate(memoryRequirements.size, memoryRequirements.memoryTypeB= its); + + if (!m_circularBuffer || !m_circularBuffer->allocate(memoryRequire= ments.size, memoryRequirements.alignment, &offset)) + return nullptr; + } + + m_device->bindImageMemory(image->handle(), m_circularBuffer->memoryHan= dle(), offset); + image->setData(m_circularBuffer->data() + offset); + + return image; +} + + +void VulkanStagingImageAllocator::reallocate(size_t minimumSize, uint32_t = memoryTypeBits) +{ + size_t newSize =3D (m_circularBuffer && m_circularBuffer->size() > 0) = ? m_circularBuffer->size() * 2 : m_initialSize; + while (newSize < minimumSize) + newSize *=3D 2; + + newSize =3D align(newSize, m_nonCoherentAtomSize); + + // The size must be a power-of-two + assert(newSize =3D=3D (newSize & -newSize)); + + if (m_circularBuffer && m_circularBuffer->isBusy()) + m_orphanedBuffers.push_back(m_circularBuffer); + + m_circularBuffer =3D nullptr; + + if (auto memory =3D m_allocator->allocateMemory(newSize, memoryTypeBit= s, m_optimalMemoryFlags, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + uint8_t *data =3D nullptr; + memory->map(0, (void **) &data); + + m_circularBuffer =3D std::make_shared(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[] =3D { + "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 >=3D VK_FORMAT_UNDEFINED && + format <=3D VK_FORMAT_ASTC_12x12_SRGB_BLOCK) { + return formats[format]; + } + + static const char * const pvrtc_formats[] =3D { + "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 >=3D VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG && + format <=3D VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG) { + return pvrtc_formats[format - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IM= G]; + } + + static const char * const ycbcr_formats[] =3D { + "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 >=3D VK_FORMAT_G8B8G8R8_422_UNORM_KHR && + format <=3D 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[] =3D { + "VK_PRESENT_MODE_IMMEDIATE_KHR", + "VK_PRESENT_MODE_MAILBOX_KHR", + "VK_PRESENT_MODE_FIFO_KHR", + "VK_PRESENT_MODE_FIFO_RELAXED_KHR" + }; + + if (mode >=3D VK_PRESENT_MODE_IMMEDIATE_KHR && mode <=3D VK_PRESENT_MO= DE_FIFO_RELAXED_KHR) + return modes[mode]; + + return QByteArray::number(mode); +} + + +QByteArray enumToString(VkPhysicalDeviceType physicalDeviceType) +{ + static const char * const types[] =3D { + "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 >=3D VK_PHYSICAL_DEVICE_TYPE_OTHER && + physicalDeviceType <=3D 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 << driverVersio= n << ')'; + break; + } + + stream.flush(); + return string.toUtf8(); +} + +} // namespace KWin diff --git a/libkwineffects/kwinvulkanutils.h b/libkwineffects/kwinvulkanut= ils.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 =C2=A9 2017-2018 Fredrik H=C3=B6glund + +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 . +*********************************************************************/ + +#ifndef KWINVULKANUTILS_H +#define KWINVULKANUTILS_H + +// kwin +#include +#include + +// Qt +#include +#include +#include +#include + +// STL +#include +#include +#include + +// xcb +#include + +#include + + +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(count) + */ +template +std::vector resultAsVector(Func function, Args&&... params) +{ + uint32_t count =3D 0; + function(params..., &count, nullptr); + + std::vector v(count); + + if (count > 0) { + function(params..., &count, v.data()); + + if (count < v.size()) + v.resize(count); + } + + return v; +} + + + +// ----------------------------------------------------------------------- + + + +template +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 &list) noexcept + : m_count(list.size()), m_data(list.begin()) + {} + + VulkanArrayProxy(const std::vector &vector) noexcept + : m_count(vector.size()), m_data(vector.data()) + {} + + VulkanArrayProxy(const QVector &vector) noexcept + : m_count(vector.count()), m_data(vector.constData()) + {} + + VulkanArrayProxy(const QVarLengthArray &array) noexcept + : m_count(array.count()), m_data(array.constData()) + {} + + template + VulkanArrayProxy(const std::array &array) noexcept + : m_count(array.size()), m_data(array.data()) + {} + + template + 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 =3D=3D 0; } + bool isEmpty() const noexcept { return m_count =3D=3D 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 +{ +public: + VulkanExtensionVector() : std::vector() {} + VulkanExtensionVector(std::vector &&other) + : std::vector(std::move(other)) {} + + bool contains(const char *name) const { + return std::any_of(cbegin(), cend(), + [=3D](const VkExtensionProperties &properties) { + return strcmp(properties.extensionName, nam= e) =3D=3D 0; + }); + } + + bool containsAll(const VulkanArrayProxy &extensions) con= st { + for (auto extension : extensions) { + if (!contains(extension)) + return false; + } + return true; + } +}; + + + +class VulkanLayerVector : public std::vector +{ +public: + VulkanLayerVector() : std::vector() {} + VulkanLayerVector(std::vector &&other) + : std::vector(std::move(other)) {} + + bool contains(const char *name) const { + return std::any_of(cbegin(), cend(), + [=3D](const VkLayerProperties &properties) { + return strcmp(properties.layerName, name) = =3D=3D 0; + }); + } + + bool containsAll(const VulkanArrayProxy &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() =3D default; +}; + + + +// ----------------------------------------------------------------------- + + + +class KWINVULKANUTILS_EXPORT VulkanPhysicalDevice +{ +public: + typedef VkPhysicalDevice NativeHandleType; + + VulkanPhysicalDevice() : m_physicalDevice(VK_NULL_HANDLE) {} + VulkanPhysicalDevice(VkPhysicalDevice device) : m_physicalDevice(devic= e) {} + VulkanPhysicalDevice(const VulkanPhysicalDevice &device) : m_physicalD= evice(device.m_physicalDevice) {} + + VulkanPhysicalDevice &operator =3D (const VulkanPhysicalDevice &other)= { + m_physicalDevice =3D other.m_physicalDevice; + return *this; + } + + VulkanPhysicalDevice &operator =3D (VkPhysicalDevice device) { + m_physicalDevice =3D device; + return *this; + } + + operator VkPhysicalDevice () const { return m_physicalDevice; } + + VkPhysicalDevice handle() const { return m_physicalDevice; } + + bool isValid() const { return m_physicalDevice !=3D VK_NULL_HANDLE; } + + void getFeatures(VkPhysicalDeviceFeatures *pFeatures) { + vkGetPhysicalDeviceFeatures(m_physicalDevice, pFeatures); + } + + void getFormatProperties(VkFormat format, VkFormatProperties *pFormatP= roperties) { + vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, pFor= matProperties); + } + + VkResult getImageFormatProperties(VkFormat format, VkImageType type, V= kImageTiling tiling, + VkImageUsageFlags usage, VkImageCrea= teFlags 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, VkQ= ueueFamilyProperties *pQueueFamilyProperties) { + vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, pQueueF= amilyPropertyCount, pQueueFamilyProperties); + } + + std::vector getQueueFamilyProperties() { + return resultAsVector(vkGetPhysicalDevice= QueueFamilyProperties, m_physicalDevice); + } + + void getMemoryProperties(VkPhysicalDeviceMemoryProperties *pMemoryProp= erties) { + vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, pMemoryPrope= rties); + } + + VkResult createDevice(const VkDeviceCreateInfo *pCreateInfo, const VkA= llocationCallbacks *pAllocator, VkDevice *pDevice) { + return vkCreateDevice(m_physicalDevice, pCreateInfo, pAllocator, p= Device); + } + + VkResult enumerateDeviceExtensionProperties(const char *pLayerName, ui= nt32_t *pPropertyCount, VkExtensionProperties *pProperties) { + return vkEnumerateDeviceExtensionProperties(m_physicalDevice, pLay= erName, pPropertyCount, pProperties); + } + + VulkanExtensionVector enumerateDeviceExtensionProperties(const char *p= LayerName =3D nullptr) { + return resultAsVector(vkEnumerateDeviceExte= nsionProperties, m_physicalDevice, pLayerName); + } + + // Deprecated + VkResult enumerateDeviceLayerProperties(uint32_t *pPropertyCount, VkLa= yerProperties *pProperties) { + return vkEnumerateDeviceLayerProperties(m_physicalDevice, pPropert= yCount, pProperties); + } + + void getSparseImageFormatProperties(VkFormat format, VkImageType type,= VkSampleCountFlagBits samples, VkImageUsageFlags usage, + VkImageTiling tiling, uint32_t *pP= ropertyCount, VkSparseImageFormatProperties *pProperties) { + vkGetPhysicalDeviceSparseImageFormatProperties(m_physicalDevice, f= ormat, type, samples, usage, tiling, pPropertyCount, pProperties); + } + + std::vector getSparseImageFormatPropert= ies(VkFormat format, VkImageType type, VkSampleCountFlagBits samples, + = VkImageUsageFlags usage, VkImageTiling tiling) { + return resultAsVector(vkGetPhysical= DeviceSparseImageFormatProperties, m_physicalDevice, + format, type,= samples, usage, tiling); + } + + VkResult getSurfaceSupportKHR(uint32_t queueFamilyIndex, VkSurfaceKHR = surface, VkBool32 *pSupported) { + return pfnGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, que= ueFamilyIndex, surface, pSupported); + } + + VkResult getSurfaceCapabilitiesKHR(VkSurfaceKHR surface, VkSurfaceCapa= bilitiesKHR *pSurfaceCapabilities) { + return pfnGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice= , surface, pSurfaceCapabilities); + } + + VkResult getSurfaceFormatsKHR(VkSurfaceKHR surface, uint32_t *pSurface= FormatCount, VkSurfaceFormatKHR *pSurfaceFormats) { + return pfnGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, sur= face, pSurfaceFormatCount, pSurfaceFormats); + } + + std::vector getSurfaceFormatsKHR(VkSurfaceKHR surf= ace) { + return resultAsVector(pfnGetPhysicalDeviceSurf= aceFormatsKHR, m_physicalDevice, surface); + } + + VkResult getSurfacePresentModesKHR(VkSurfaceKHR surface, uint32_t *pPr= esentModeCount, VkPresentModeKHR *pPresentModes) { + return pfnGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice= , surface, pPresentModeCount, pPresentModes); + } + + std::vector getSurfacePresentModesKHR(VkSurfaceKHR s= urface) { + return resultAsVector(pfnGetPhysicalDeviceSurfac= ePresentModesKHR, m_physicalDevice, surface); + } + +#ifdef VK_USE_PLATFORM_XCB_KHR + VkBool32 getXcbPresentationSupportKHR(uint32_t queueFamilyIndex, xcb_c= onnection_t *connection, xcb_visualid_t visual_id) { + return pfnGetPhysicalDeviceXcbPresentationSupportKHR(m_physicalDev= ice, queueFamilyIndex, connection, visual_id); + } +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + VkBool32 getWaylandPresentationSupportKHR(uint32_t queueFamilyIndex, s= truct wl_display *display) { + return pfnGetPhysicalDeviceWaylandPresentationSupportKHR(m_physica= lDevice, 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 VkPhysicalDeviceImageForma= tInfo2KHR *pImageFormatInfo, VkImageFormatProperties2KHR *pImageFormatPrope= rties) { + return pfnGetPhysicalDeviceImageFormatProperties2KHR(m_physicalDev= ice, pImageFormatInfo, pImageFormatProperties); + } + + void getQueueFamilyProperties2KHR(uint32_t *pQueueFamilyPropertyCount,= VkQueueFamilyProperties2KHR *pQueueFamilyProperties) { + pfnGetPhysicalDeviceQueueFamilyProperties2KHR(m_physicalDevice, pQ= ueueFamilyPropertyCount, pQueueFamilyProperties); + } + + void getMemoryProperties2KHR(VkPhysicalDeviceMemoryProperties2KHR* pMe= moryProperties) { + pfnGetPhysicalDeviceMemoryProperties2KHR(m_physicalDevice, pMemory= Properties); + } + + void getSparseImageFormatProperties2KHR(const VkPhysicalDeviceSparseIm= ageFormatInfo2KHR *pFormatInfo, + uint32_t *pPropertyCount, VkSp= arseImageFormatProperties2KHR *pProperties) { + pfnGetPhysicalDeviceSparseImageFormatProperties2KHR(m_physicalDevi= ce, pFormatInfo, pPropertyCount, pProperties); + } + + std::vector getSparseImageFormatPro= perties2KHR(const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo) { + return resultAsVector(pfnGetPhy= sicalDeviceSparseImageFormatProperties2KHR, m_physicalDevice, pFormatInfo); + } + + void getExternalBufferPropertiesKHR(const VkPhysicalDeviceExternalBuff= erInfoKHR *pExternalBufferInfo, VkExternalBufferPropertiesKHR *pExternalBuf= ferProperties) { + pfnGetPhysicalDeviceExternalBufferPropertiesKHR(m_physicalDevice, = pExternalBufferInfo, pExternalBufferProperties); + } + + void getExternalSemaphorePropertiesKHR(const VkPhysicalDeviceExternalS= emaphoreInfoKHR *pExternalSemaphoreInfo, + VkExternalSemaphorePropertiesKH= R *pExternalSemaphoreProperties) { + pfnGetPhysicalDeviceExternalSemaphorePropertiesKHR(m_physicalDevic= e, 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 &enabledLayers =3D= {}, + const VulkanArrayProxy &enabledExtensions= =3D {}) + : m_instance(VK_NULL_HANDLE) + { + const VkInstanceCreateInfo createInfo { + .sType =3D VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .pApplicationInfo =3D &applicationInfo, + .enabledLayerCount =3D enabledLayers.count(), + .ppEnabledLayerNames =3D enabledLayers.data(), + .enabledExtensionCount =3D enabledExtensions.size(), + .ppEnabledExtensionNames =3D enabledExtensions.data(), + }; + + vkCreateInstance(&createInfo, nullptr, &m_instance); + } + + VulkanInstance(const VulkanInstance &other) =3D delete; + + VulkanInstance(VulkanInstance &&other) + : m_instance(other.m_instance) + { + other.m_instance =3D VK_NULL_HANDLE; + } + + ~VulkanInstance() { + if (m_instance) + vkDestroyInstance(m_instance, nullptr); + } + + static VulkanExtensionVector supportedExtensions() { + return resultAsVector(vkEnumerateInstanceEx= tensionProperties, nullptr); + } + + static VulkanLayerVector supportedLayers() { + return resultAsVector(vkEnumerateInstanceLayerP= roperties); + } + + VulkanInstance &operator =3D (const VulkanInstance &other) =3D delete; + + VulkanInstance &operator =3D (VulkanInstance &&other) { + if (m_instance) + vkDestroyInstance(m_instance, nullptr); + + m_instance =3D other.m_instance; + other.m_instance =3D VK_NULL_HANDLE; + return *this; + } + + operator VkInstance () const { return m_instance; } + VkInstance handle() const { return m_instance; } + + bool isValid() const { return m_instance !=3D VK_NULL_HANDLE; } + + std::vector enumeratePhysicalDevices() const { + static_assert(sizeof(VulkanPhysicalDevice) =3D=3D sizeof(VkPhysica= lDevice)); + + uint32_t count =3D 0; + vkEnumeratePhysicalDevices(m_instance, &count, nullptr); + + std::vector devices(count); + vkEnumeratePhysicalDevices(m_instance, &count, reinterpret_cast(devices.data())); + + return devices; + } + + PFN_vkVoidFunction getProcAddress(const char *name) const { + return vkGetInstanceProcAddr(m_instance, name); + } + + void destroySurfaceKHR(VkSurfaceKHR surface, const VkAllocationCallbac= ks *pAllocator =3D nullptr) { + pfnDestroySurfaceKHR(m_instance, surface, pAllocator); + } + +#ifdef VK_USE_PLATFORM_XCB_KHR + VkResult createXcbSurfaceKHR(const VkXcbSurfaceCreateInfoKHR *pCreateI= nfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) { + return pfnCreateXcbSurfaceKHR(m_instance, pCreateInfo, pAllocator,= pSurface); + } + + VkResult createXcbSurfaceKHR(const VkXcbSurfaceCreateInfoKHR &createIn= fo, + 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 *pAllocat= or, + VkSurfaceKHR *pSurface) { + return pfnCreateWaylandSurfaceKHR(m_instance, pCreateInfo, pAlloca= tor, pSurface); + } + + VkResult createWaylandSurfaceKHR(const VkWaylandSurfaceCreateInfoKHR &= createInfo, + const VkAllocationCallbacks *pAllocat= or, + VkSurfaceKHR *pSurface) { + return pfnCreateWaylandSurfaceKHR(m_instance, &createInfo, pAlloca= tor, pSurface); + } +#endif + +#ifdef VK_USE_PLATFORM_ANDROID_KHR + VkResult createAndroidSurfaceKHR(const VkAndroidSurfaceCreateInfoKHR *= pCreateInfo, + const VkAllocationCallbacks *pAllocat= or, + VkSurfaceKHR* pSurface) { + return pfnCreateAndroidSurfaceKHR(m_instance, pCreateInfo, pAlloca= tor, pSurface); + } + + VkResult createAndroidSurfaceKHR(const VkAndroidSurfaceCreateInfoKHR &= createInfo, + const VkAllocationCallbacks *pAllocat= or, + VkSurfaceKHR* pSurface) { + return pfnCreateAndroidSurfaceKHR(m_instance, &createInfo, pAlloca= tor, pSurface); + } +#endif + + VkResult createDebugReportCallbackEXT(const VkDebugReportCallbackCreat= eInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAl= locator, + VkDebugReportCallbackEXT *pCallb= ack) { + return pfnCreateDebugReportCallbackEXT(m_instance, pCreateInfo, pA= llocator, pCallback); + } + + VkResult createDebugReportCallbackEXT(const VkDebugReportCallbackCreat= eInfoEXT &createInfo, + const VkAllocationCallbacks *pAl= locator, + VkDebugReportCallbackEXT *pCallb= ack) { + return pfnCreateDebugReportCallbackEXT(m_instance, &createInfo, pA= llocator, 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, lo= cation, 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, VkDebugReportFlags= EXT flags, PFN_vkDebugReportCallbackEXT pfnCallback, void *pUserData =3D nu= llptr) + : m_instance(instance), + m_callback(VK_NULL_HANDLE) + { + const VkDebugReportCallbackCreateInfoEXT createInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EX= T, + .pNext =3D nullptr, + .flags =3D flags, + .pfnCallback =3D pfnCallback, + .pUserData =3D pUserData + }; + + instance.createDebugReportCallbackEXT(&createInfo, nullptr, &m_cal= lback); + } + + VulkanDebugReportCallback(VulkanInstance &instance, const VkDebugRepor= tCallbackCreateInfoEXT *pCreateInfo) + : m_instance(instance), + m_callback(VK_NULL_HANDLE) + { + instance.createDebugReportCallbackEXT(pCreateInfo, nullptr, &m_cal= lback); + } + + VulkanDebugReportCallback(VulkanInstance &instance, const VkDebugRepor= tCallbackCreateInfoEXT &createInfo) + : m_instance(instance), + m_callback(VK_NULL_HANDLE) + { + instance.createDebugReportCallbackEXT(&createInfo, nullptr, &m_cal= lback); + } + + VulkanDebugReportCallback(const VulkanDebugReportCallback &other) =3D = delete; + + VulkanDebugReportCallback(VulkanDebugReportCallback &&other) + : m_instance(other.m_instance), + m_callback(other.m_callback) + { + other.m_instance =3D VK_NULL_HANDLE; + other.m_callback =3D VK_NULL_HANDLE; + } + + ~VulkanDebugReportCallback() { + if (m_callback) + pfnDestroyDebugReportCallbackEXT(m_instance, m_callback, nullp= tr); + } + + VkDebugReportCallbackEXT handle() const { return m_callback; } + + operator VkDebugReportCallbackEXT () const { return m_callback; } + + VulkanDebugReportCallback &operator =3D (const VulkanDebugReportCallba= ck &other) =3D delete; + + VulkanDebugReportCallback &operator =3D (VulkanDebugReportCallback &&o= ther) + { + if (m_callback) + pfnDestroyDebugReportCallbackEXT(m_instance, m_callback, nullp= tr); + + m_instance =3D other.m_instance; + m_callback =3D other.m_callback; + + other.m_instance =3D VK_NULL_HANDLE; + other.m_callback =3D 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 VkDeviceCreate= Info &createInfo, const VkAllocationCallbacks *pAllocator =3D nullptr) + : m_physicalDevice(physicalDevice), + m_device(VK_NULL_HANDLE) + { + vkCreateDevice(physicalDevice, &createInfo, pAllocator, &m_device); + } + + VulkanDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo= *pCreateInfo, const VkAllocationCallbacks *pAllocator =3D nullptr) + : m_physicalDevice(physicalDevice), + m_device(VK_NULL_HANDLE) + { + vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, &m_device); + } + + VulkanDevice(const VulkanDevice &other) =3D delete; + + VulkanDevice(VulkanDevice &&other) + : m_physicalDevice(other.m_physicalDevice), + m_device(other.m_device) + { + other.m_physicalDevice =3D VK_NULL_HANDLE; + other.m_device =3D VK_NULL_HANDLE; + } + + ~VulkanDevice() { + if (m_device) + vkDestroyDevice(m_device, nullptr); + } + + operator VkDevice () const { return m_device; } + + VulkanDevice &operator =3D (const VulkanDevice &other) =3D delete; + + VulkanDevice &operator =3D (VulkanDevice &&other) { + if (m_device) + vkDestroyDevice(m_device, nullptr); + + m_physicalDevice =3D other.m_physicalDevice; + m_device =3D other.m_device; + + other.m_physicalDevice =3D VK_NULL_HANDLE; + other.m_device =3D VK_NULL_HANDLE; + + return *this; + } + + bool isValid() const { return m_device !=3D 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, con= st VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) { + return vkAllocateMemory(m_device, pAllocateInfo, pAllocator, pMemo= ry); + } + + void freeMemory(VkDeviceMemory memory, const VkAllocationCallbacks *pA= llocator =3D nullptr) { + vkFreeMemory(m_device, memory, pAllocator); + } + + VkResult mapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDevic= eSize 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 VkMa= ppedMemoryRange *pMemoryRanges) { + return vkFlushMappedMemoryRanges(m_device, memoryRangeCount, pMemo= ryRanges); + } + + VkResult flushMappedMemoryRanges(const VulkanArrayProxy &memoryRanges) { + return vkFlushMappedMemoryRanges(m_device, memoryRanges.count(), m= emoryRanges.data()); + } + + VkResult invalidateMappedMemoryRanges(uint32_t memoryRangeCount, const= VkMappedMemoryRange *pMemoryRanges) { + return vkInvalidateMappedMemoryRanges(m_device, memoryRangeCount, = pMemoryRanges); + } + + VkResult invalidateMappedMemoryRanges(const VulkanArrayProxy &memoryRanges) { + return vkInvalidateMappedMemoryRanges(m_device, memoryRanges.count= (), memoryRanges.data()); + } + + void getMemoryCommitment(VkDeviceMemory memory, VkDeviceSize *pCommitt= edMemoryInBytes) { + vkGetDeviceMemoryCommitment(m_device, memory, pCommittedMemoryInBy= tes); + } + + VkResult bindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDe= viceSize memoryOffset) { + return vkBindBufferMemory(m_device, buffer, memory, memoryOffset); + } + + VkResult bindImageMemory(VkImage image, VkDeviceMemory memory, VkDevic= eSize memoryOffset) { + return vkBindImageMemory(m_device, image, memory, memoryOffset); + } + + // VK_KHR_bind_memory2 + void bindBufferMemory2KHR(uint32_t bindInfoCount, const VkBindBufferMe= moryInfoKHR* pBindInfos) { + pfnBindBufferMemory2KHR(m_device, bindInfoCount, pBindInfos); + } + + void bindBufferMemory2KHR(const VulkanArrayProxy &bindInfos) { + pfnBindBufferMemory2KHR(m_device, bindInfos.count(), bindInfos.dat= a()); + } + + void bindImageMemory2KHR(uint32_t bindInfoCount, const VkBindImageMemo= ryInfoKHR* pBindInfos) { + pfnBindImageMemory2KHR(m_device, bindInfoCount, pBindInfos); + } + + void bindImageMemory2KHR(const VulkanArrayProxy &bindInfos) { + pfnBindImageMemory2KHR(m_device, bindInfos.count(), bindInfos.data= ()); + } + + void getBufferMemoryRequirements(VkBuffer buffer, VkMemoryRequirements= *pMemoryRequirements) { + vkGetBufferMemoryRequirements(m_device, buffer, pMemoryRequirement= s); + } + + void getImageMemoryRequirements(VkImage image, VkMemoryRequirements *p= MemoryRequirements) { + vkGetImageMemoryRequirements(m_device, image, pMemoryRequirements); + } + + void getImageSparseMemoryRequirements(VkImage image, uint32_t *pSparse= MemoryRequirementCount, + VkSparseImageMemoryRequirements = *pSparseMemoryRequirements) { + vkGetImageSparseMemoryRequirements(m_device, image, pSparseMemoryR= equirementCount, pSparseMemoryRequirements); + } + + // VK_KHR_get_memory_requirements2 + void getImageMemoryRequirements2KHR(const VkImageMemoryRequirementsInf= o2KHR *pInfo, VkMemoryRequirements2KHR *pMemoryRequirements) { + pfnGetImageMemoryRequirements2KHR(m_device, pInfo, pMemoryRequirem= ents); + } + + void getImageMemoryRequirements2KHR(const VkImageMemoryRequirementsInf= o2KHR &info, VkMemoryRequirements2KHR *pMemoryRequirements) { + pfnGetImageMemoryRequirements2KHR(m_device, &info, pMemoryRequirem= ents); + } + + void getBufferMemoryRequirements2KHR(const VkBufferMemoryRequirementsI= nfo2KHR *pInfo, VkMemoryRequirements2KHR *pMemoryRequirements) { + pfnGetBufferMemoryRequirements2KHR(m_device, pInfo, pMemoryRequire= ments); + } + + void getBufferMemoryRequirements2KHR(const VkBufferMemoryRequirementsI= nfo2KHR &info, VkMemoryRequirements2KHR *pMemoryRequirements) { + pfnGetBufferMemoryRequirements2KHR(m_device, &info, pMemoryRequire= ments); + } + + void getImageSparseMemoryRequirements2KHR(const VkImageSparseMemoryReq= uirementsInfo2KHR *pInfo, + uint32_t *pSparseMemoryRequir= ementCount, VkSparseImageMemoryRequirements2KHR *pSparseMemoryRequirements)= { + pfnGetImageSparseMemoryRequirements2KHR(m_device, pInfo, pSparseMe= moryRequirementCount, pSparseMemoryRequirements); + } + + void getImageSparseMemoryRequirements2KHR(const VkImageSparseMemoryReq= uirementsInfo2KHR &info, uint32_t *pSparseMemoryRequirementCount, + VkSparseImageMemoryRequireme= nts2KHR *pSparseMemoryRequirements) { + pfnGetImageSparseMemoryRequirements2KHR(m_device, &info, pSparseMe= moryRequirementCount, pSparseMemoryRequirements); + } + + VkResult createFence(const VkFenceCreateInfo *pCreateInfo, const VkAll= ocationCallbacks *pAllocator, VkFence *pFence) { + return vkCreateFence(m_device, pCreateInfo, pAllocator, pFence); + } + + void destroyFence(VkFence fence, const VkAllocationCallbacks *pAllocat= or =3D 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, Vk= Bool32 waitAll =3D VK_TRUE, uint64_t timeout =3D UINT64_MAX) { + return vkWaitForFences(m_device, fenceCount, pFences, waitAll, tim= eout); + } + + VkResult createSemaphore(const VkSemaphoreCreateInfo *pCreateInfo, con= st VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) { + return vkCreateSemaphore(m_device, pCreateInfo, pAllocator, pSemap= hore); + } + + void destroySemaphore(VkSemaphore semaphore, const VkAllocationCallbac= ks *pAllocator =3D nullptr) { + vkDestroySemaphore(m_device, semaphore, pAllocator); + } + + VkResult createEvent(const VkEventCreateInfo *pCreateInfo, const VkAll= ocationCallbacks *pAllocator, VkEvent *pEvent) { + return vkCreateEvent(m_device, pCreateInfo, pAllocator, pEvent); + } + + void destroyEvent(VkEvent event, const VkAllocationCallbacks *pAllocat= or =3D 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, con= st VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) { + return vkCreateQueryPool(m_device, pCreateInfo, pAllocator, pQuery= Pool); + } + + void destroyQueryPool(VkQueryPool queryPool, const VkAllocationCallbac= ks *pAllocator =3D nullptr) { + vkDestroyQueryPool(m_device, queryPool, pAllocator); + } + + VkResult getQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuer= y, uint32_t queryCount, + size_t dataSize, void *pData, VkDeviceSiz= e stride, VkQueryResultFlags flags) { + return vkGetQueryPoolResults(m_device, queryPool, firstQuery, quer= yCount, dataSize, pData, stride, flags); + } + + VkResult createBuffer(const VkBufferCreateInfo *pCreateInfo, const VkA= llocationCallbacks *pAllocator, VkBuffer *pBuffer) { + return vkCreateBuffer(m_device, pCreateInfo, pAllocator, pBuffer); + } + + void destroyBuffer(VkBuffer buffer, const VkAllocationCallbacks *pAllo= cator =3D nullptr) { + vkDestroyBuffer(m_device, buffer, pAllocator); + } + + VkResult createBufferView(const VkBufferViewCreateInfo *pCreateInfo, c= onst VkAllocationCallbacks *pAllocator, VkBufferView *pView) { + return vkCreateBufferView(m_device, pCreateInfo, pAllocator, pView= ); + } + + void destroyBufferView(VkBufferView bufferView, const VkAllocationCall= backs *pAllocator =3D nullptr) { + vkDestroyBufferView(m_device, bufferView, pAllocator); + } + + VkResult createImage(const VkImageCreateInfo *pCreateInfo, const VkAll= ocationCallbacks *pAllocator, VkImage *pImage) { + return vkCreateImage(m_device, pCreateInfo, pAllocator, pImage); + } + + void destroyImage(VkImage image, const VkAllocationCallbacks *pAllocat= or =3D 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, con= st VkAllocationCallbacks *pAllocator, VkImageView *pView) { + return vkCreateImageView(m_device, pCreateInfo, pAllocator, pView); + } + + void destroyImageView(VkImageView imageView, const VkAllocationCallbac= ks *pAllocator =3D nullptr) { + vkDestroyImageView(m_device, imageView, pAllocator); + } + + VkResult createShaderModule(const VkShaderModuleCreateInfo *pCreateInf= o, const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) { + return vkCreateShaderModule(m_device, pCreateInfo, pAllocator, pSh= aderModule); + } + + void destroyShaderModule(VkShaderModule shaderModule, const VkAllocati= onCallbacks *pAllocator =3D nullptr) { + vkDestroyShaderModule(m_device, shaderModule, pAllocator); + } + + VkResult createPipelineCache(const VkPipelineCacheCreateInfo *pCreateI= nfo, const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCac= he) { + return vkCreatePipelineCache(m_device, pCreateInfo, pAllocator, pP= ipelineCache); + } + + VkResult createPipelineCache(const VkPipelineCacheCreateInfo &createIn= fo, const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCach= e) { + return vkCreatePipelineCache(m_device, &createInfo, pAllocator, pP= ipelineCache); + } + + void destroyPipelineCache(VkPipelineCache pipelineCache, const VkAlloc= ationCallbacks *pAllocator =3D nullptr) { + vkDestroyPipelineCache(m_device, pipelineCache, pAllocator); + } + + VkResult getPipelineCacheData(VkPipelineCache pipelineCache, size_t *p= DataSize, void *pData) { + return vkGetPipelineCacheData(m_device, pipelineCache, pDataSize, = pData); + } + + VkResult mergePipelineCaches(VkPipelineCache dstCache, uint32_t srcCac= heCount, const VkPipelineCache *pSrcCaches) { + return vkMergePipelineCaches(m_device, dstCache, srcCacheCount, pS= rcCaches); + } + + VkResult createGraphicsPipelines(VkPipelineCache pipelineCache, uint32= _t createInfoCount, const VkGraphicsPipelineCreateInfo *pCreateInfos, + const VkAllocationCallbacks *pAllocat= or, VkPipeline *pPipelines) { + return vkCreateGraphicsPipelines(m_device, pipelineCache, createIn= foCount, pCreateInfos, pAllocator, pPipelines); + } + + VkResult createComputePipelines(VkPipelineCache pipelineCache, uint32_= t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, + const VkAllocationCallbacks *pAllocato= r, VkPipeline *pPipelines) { + return vkCreateComputePipelines(m_device, pipelineCache, createInf= oCount, pCreateInfos, pAllocator, pPipelines); + } + + void destroyPipeline(VkPipeline pipeline, const VkAllocationCallbacks = *pAllocator =3D nullptr) { + vkDestroyPipeline(m_device, pipeline, pAllocator); + } + + VkResult createPipelineLayout(const VkPipelineLayoutCreateInfo *pCreat= eInfo, const VkAllocationCallbacks *pAllocator, + VkPipelineLayout *pPipelineLayout) { + return vkCreatePipelineLayout(m_device, pCreateInfo, pAllocator, p= PipelineLayout); + } + + VkResult createPipelineLayout(const VkPipelineLayoutCreateInfo &create= Info, const VkAllocationCallbacks *pAllocator, + VkPipelineLayout *pPipelineLayout) { + return vkCreatePipelineLayout(m_device, &createInfo, pAllocator, p= PipelineLayout); + } + + void destroyPipelineLayout(VkPipelineLayout pipelineLayout, const VkAl= locationCallbacks *pAllocator =3D nullptr) { + vkDestroyPipelineLayout(m_device, pipelineLayout, pAllocator); + } + + VkResult createSampler(const VkSamplerCreateInfo *pCreateInfo, const V= kAllocationCallbacks *pAllocator, VkSampler *pSampler) { + return vkCreateSampler(m_device, pCreateInfo, pAllocator, pSampler= ); + } + + void destroySampler(VkSampler sampler, const VkAllocationCallbacks *pA= llocator =3D nullptr) { + vkDestroySampler(m_device, sampler, pAllocator); + } + + VkResult createDescriptorSetLayout(const VkDescriptorSetLayoutCreateIn= fo *pCreateInfo, const VkAllocationCallbacks *pAllocator, + VkDescriptorSetLayout *pSetLayout) { + return vkCreateDescriptorSetLayout(m_device, pCreateInfo, pAllocat= or, pSetLayout); + } + + VkResult createDescriptorSetLayout(const VkDescriptorSetLayoutCreateIn= fo &createInfo, const VkAllocationCallbacks *pAllocator, + VkDescriptorSetLayout *pSetLayout) { + return vkCreateDescriptorSetLayout(m_device, &createInfo, pAllocat= or, pSetLayout); + } + + void destroyDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLay= out, const VkAllocationCallbacks *pAllocator =3D nullptr) { + vkDestroyDescriptorSetLayout(m_device, descriptorSetLayout, pAlloc= ator); + } + + VkResult createDescriptorPool(const VkDescriptorPoolCreateInfo *pCreat= eInfo, const VkAllocationCallbacks *pAllocator, + VkDescriptorPool *pDescriptorPool) { + return vkCreateDescriptorPool(m_device, pCreateInfo, pAllocator, p= DescriptorPool); + } + + void destroyDescriptorPool(VkDescriptorPool descriptorPool, const VkAl= locationCallbacks *pAllocator =3D nullptr) { + vkDestroyDescriptorPool(m_device, descriptorPool, pAllocator); + } + + VkResult resetDescriptorPool(VkDescriptorPool descriptorPool, VkDescri= ptorPoolResetFlags flags) { + return vkResetDescriptorPool(m_device, descriptorPool, flags); + } + + VkResult allocateDescriptorSets(const VkDescriptorSetAllocateInfo *pAl= locateInfo, VkDescriptorSet *pDescriptorSets) { + return vkAllocateDescriptorSets(m_device, pAllocateInfo, pDescript= orSets); + } + + VkResult freeDescriptorSets(VkDescriptorPool descriptorPool, uint32_t = descriptorSetCount, const VkDescriptorSet *pDescriptorSets) { + return vkFreeDescriptorSets(m_device, descriptorPool, descriptorSe= tCount, pDescriptorSets); + } + + void updateDescriptorSets(uint32_t descriptorWriteCount, const VkWrite= DescriptorSet *pDescriptorWrites, + uint32_t descriptorCopyCount, const VkCopyDe= scriptorSet *pDescriptorCopies) { + vkUpdateDescriptorSets(m_device, descriptorWriteCount, pDescriptor= Writes, descriptorCopyCount, pDescriptorCopies); + } + + VkResult createFramebuffer(const VkFramebufferCreateInfo *pCreateInfo,= const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) { + return vkCreateFramebuffer(m_device, pCreateInfo, pAllocator, pFra= mebuffer); + } + + void destroyFramebuffer(VkFramebuffer framebuffer, const VkAllocationC= allbacks *pAllocator =3D nullptr) { + vkDestroyFramebuffer(m_device, framebuffer, pAllocator); + } + + VkResult createRenderPass(const VkRenderPassCreateInfo *pCreateInfo, c= onst VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { + return vkCreateRenderPass(m_device, pCreateInfo, pAllocator, pRend= erPass); + } + + void destroyRenderPass(VkRenderPass renderPass, const VkAllocationCall= backs *pAllocator =3D nullptr) { + vkDestroyRenderPass(m_device, renderPass, pAllocator); + } + + void getRenderAreaGranularity(VkRenderPass renderPass, VkExtent2D *pGr= anularity) { + vkGetRenderAreaGranularity(m_device, renderPass, pGranularity); + } + + VkResult createCommandPool(const VkCommandPoolCreateInfo *pCreateInfo,= const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) { + return vkCreateCommandPool(m_device, pCreateInfo, pAllocator, pCom= mandPool); + } + + void destroyCommandPool(VkCommandPool commandPool, const VkAllocationC= allbacks *pAllocator =3D nullptr) { + vkDestroyCommandPool(m_device, commandPool, pAllocator); + } + + VkResult resetCommandPool(VkCommandPool commandPool, VkCommandPoolRese= tFlags flags) { + return vkResetCommandPool(m_device, commandPool, flags); + } + + VkResult allocateCommandBuffers(const VkCommandBufferAllocateInfo *pAl= locateInfo, VkCommandBuffer *pCommandBuffers) { + return vkAllocateCommandBuffers(m_device, pAllocateInfo, pCommandB= uffers); + } + + void freeCommandBuffers(VkCommandPool commandPool, uint32_t commandBuf= ferCount, const VkCommandBuffer *pCommandBuffers) { + vkFreeCommandBuffers(m_device, commandPool, commandBufferCount, pC= ommandBuffers); + } + + // VK_KHR_swapchain + VkResult createSwapchainKHR(const VkSwapchainCreateInfoKHR *pCreateInf= o, const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) { + return pfnCreateSwapchainKHR(m_device, pCreateInfo, pAllocator, pS= wapchain); + } + + void destroySwapchainKHR(VkSwapchainKHR swapchain, const VkAllocationC= allbacks *pAllocator =3D nullptr) { + pfnDestroySwapchainKHR(m_device, swapchain, pAllocator); + } + + VkResult getSwapchainImagesKHR(VkSwapchainKHR swapchain, uint32_t *pSw= apchainImageCount, VkImage *pSwapchainImages) { + return pfnGetSwapchainImagesKHR(m_device, swapchain, pSwapchainIma= geCount, pSwapchainImages); + } + + VkResult acquireNextImageKHR(VkSwapchainKHR swapchain, uint64_t timeou= t, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) { + return pfnAcquireNextImageKHR(m_device, swapchain, timeout, semaph= ore, fence, pImageIndex); + } + + // VK_KHR_maintenance1 + void trimCommandPoolKHR(VkCommandPool commandPool, VkCommandPoolTrimFl= agsKHR flags) { + pfnTrimCommandPoolKHR(m_device, commandPool, flags); + } + + // VK_KHR_descriptor_update_template + VkResult createDescriptorUpdateTemplateKHR(const VkDescriptorUpdateTem= plateCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks= *pAllocator, VkDescriptorUpdateTemplateKHR *pDescriptorUpdateTemplate) { + return pfnCreateDescriptorUpdateTemplateKHR(m_device, pCreateInfo,= pAllocator, pDescriptorUpdateTemplate); + } + + void destroyDescriptorUpdateTemplateKHR(VkDescriptorUpdateTemplateKHR = descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator =3D nullp= tr) { + pfnDestroyDescriptorUpdateTemplateKHR(m_device, descriptorUpdateTe= mplate, pAllocator); + } + + void updateDescriptorSetWithTemplateKHR(VkDescriptorSet descriptorSet,= VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void *pData)= { + pfnUpdateDescriptorSetWithTemplateKHR(m_device, descriptorSet, des= criptorUpdateTemplate, pData); + } + + // VK_KHR_external_memory_fd + VkResult getMemoryFdKHR(const VkMemoryGetFdInfoKHR *pGetFdInfo, int *p= Fd) { + return pfnGetMemoryFdKHR(m_device, pGetFdInfo, pFd); + } + + VkResult getMemoryFdKHR(const VkMemoryGetFdInfoKHR &getFdInfo, int *pF= d) { + return pfnGetMemoryFdKHR(m_device, &getFdInfo, pFd); + } + + VkResult getMemoryFdPropertiesKHR(VkExternalMemoryHandleTypeFlagBitsKH= R handleType, int fd, VkMemoryFdPropertiesKHR *pMemoryFdProperties) { + return pfnGetMemoryFdPropertiesKHR(m_device, handleType, fd, pMemo= ryFdProperties); + } + + // VK_KHR_external_semaphore_fd + VkResult importSemaphoreFdKHR(const VkImportSemaphoreFdInfoKHR *pImpor= tSemaphoreFdInfo) { + return pfnImportSemaphoreFdKHR(m_device, pImportSemaphoreFdInfo); + } + + VkResult getSemaphoreFdKHR(const VkSemaphoreGetFdInfoKHR *pGetFdInfo, = int *pFd) { + return pfnGetSemaphoreFdKHR(m_device, pGetFdInfo, pFd); + } + + VkResult getSemaphoreFdKHR(const VkSemaphoreGetFdInfoKHR &getFdInfo, i= nt *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 h= ave + * a destructor. Queues are owned by the device, and calling vkGetDeviceQu= eue + * with the same parameters multiple times returns the same queue. That me= ans + * 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 !=3D VK_NULL_HANDLE; } + + VkResult submit(uint32_t submitCount, const VkSubmitInfo *pSubmits, Vk= Fence fence =3D VK_NULL_HANDLE) { + return vkQueueSubmit(m_queue, submitCount, pSubmits, fence); + } + + VkResult submit(const VulkanArrayProxy &submitInfo, VkFe= nce fence =3D 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 *pB= indInfo, 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, uint3= 2_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 =3D { + .sType =3D VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, + .pNext =3D nullptr, + .flags =3D 0, + .connection =3D connection, + .window =3D window + }; + instance->createXcbSurfaceKHR(&createInfo, nullptr, &m_surface); + } + + VulkanSurface(VulkanInstance *instance, const VkXcbSurfaceCreateInfoKH= R &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_surfac= e *surface) + : m_instance(instance), m_surface(VK_NULL_HANDLE) + { + const VkWaylandSurfaceCreateInfoKHR createInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_= KHR, + .pNext =3D nullptr, + .flags =3D 0, + .display =3D display, + .surface =3D surface + }; + + instance->createWaylandSurfaceKHR(&createInfo, nullptr, &m_surface= ); + } + + VulkanSurface(VulkanInstance *instance, const VkWaylandSurfaceCreateIn= foKHR &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 =3D { + .sType =3D VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_= KHR, + .pNext =3D nullptr, + .flags =3D 0, + .window =3D window + }; + + instance->createAndroidSurfaceKHR(&createInfo, nullptr, &m_surface= ); + } + + VulkanSurface(VulkanInstance *instance, const VkAndroidSurfaceCreateIn= foKHR &createInfo) + : m_instance(instance), m_surface(VK_NULL_HANDLE) + { + instance->createAndroidSurfaceKHR(&createInfo, nullptr, &m_surface= ); + } +#endif + + VulkanSurface(const VulkanSurface &) =3D delete; + + VulkanSurface(VulkanSurface &&other) + { + m_instance =3D other.m_instance; + m_surface =3D other.m_surface; + + other.m_instance =3D nullptr; + other.m_surface =3D VK_NULL_HANDLE; + } + + ~VulkanSurface() override + { + if (m_surface) + m_instance->destroySurfaceKHR(m_surface, nullptr); + } + + bool isValid() const { return m_surface !=3D VK_NULL_HANDLE; } + + VkSurfaceKHR handle() const { return m_surface; } + + operator VkSurfaceKHR() const { return m_surface; } + + VulkanSurface &operator =3D (const VulkanSurface &other) =3D delete; + + VulkanSurface &operator =3D (VulkanSurface &&other) + { + m_instance =3D other.m_instance; + m_surface =3D other.m_surface; + + other.m_instance =3D nullptr; + other.m_surface =3D 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 &) =3D 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 =3D nullptr; + other.m_image =3D VK_NULL_HANDLE; + other.m_type =3D VK_IMAGE_TYPE_1D; + other.m_format =3D VK_FORMAT_UNDEFINED; + other.m_usage =3D 0; + other.m_extent =3D { 0, 0, 0 }; + other.m_mipLevels =3D 0; + } + + ~VulkanImage() override { + if (m_image) + m_device->destroyImage(m_image); + } + + VulkanImage &operator =3D (const VulkanImage &) =3D delete; + + VulkanImage &operator =3D (VulkanImage &&other) { + if (m_image) + m_device->destroyImage(m_image); + + m_device =3D other.m_device; + m_image =3D other.m_image; + m_type =3D other.m_type; + m_format =3D other.m_format; + m_usage =3D other.m_usage; + m_extent =3D other.m_extent; + m_mipLevels =3D other.m_mipLevels; + + other.m_device =3D nullptr; + other.m_image =3D VK_NULL_HANDLE; + other.m_type =3D VK_IMAGE_TYPE_1D; + other.m_format =3D VK_FORMAT_UNDEFINED; + other.m_usage =3D 0; + other.m_extent =3D { 0, 0, 0 }; + other.m_mipLevels =3D 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 =3D 0) const { return m_extent.width >> level= ; } + uint32_t height(int level =3D 0) const { return m_extent.height >> lev= el; } + uint32_t depth(int level =3D 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 =3D 0) const { return QSize(width(level), h= eight(level)); } + const QRect rect(int level =3D 0) const { return QRect(0, 0, width(lev= el), height(level)); } + + VkSubresourceLayout getSubresourceLayout(const VkImageSubresource &sub= resource) { + VkSubresourceLayout layout; + m_device->getImageSubresourceLayout(m_image, &subresource, &layout= ); + return layout; + } + + bool isValid() const { return m_image !=3D 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() me= thod, + * 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 &crea= teInfo) + : VulkanImage(device, createInfo) + { + } + + VulkanStagingImage(const VulkanStagingImage &other) =3D delete; + + VulkanStagingImage(VulkanStagingImage &&other) + : VulkanImage(std::forward(other)), + m_data(other.m_data) + { + other.m_data =3D nullptr; + } + + VulkanStagingImage &operator =3D (const VulkanStagingImage &other) =3D= delete; + + VulkanStagingImage &operator =3D (VulkanStagingImage &&other) { + VulkanImage::operator =3D (std::forward(other)= ); + m_data =3D other.m_data; + other.m_data =3D nullptr; + return *this; + } + + void setData(uint8_t *data) { m_data =3D data; } + uint8_t *data() const { return m_data; } + +private: + uint8_t *m_data =3D nullptr; +}; + + + +// ----------------------------------------------------------------------- + + + +class KWINVULKANUTILS_EXPORT VulkanImageView : public VulkanObject +{ +public: + typedef VkImageView NativeHandleType; + + VulkanImageView(VulkanDevice *device, const VkImageViewCreateInfo &cre= ateInfo) + : 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 &) =3D 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 =3D nullptr; + other.m_imageView =3D VK_NULL_HANDLE; + other.m_type =3D VK_IMAGE_VIEW_TYPE_1D; + other.m_format =3D VK_FORMAT_UNDEFINED; + } + + ~VulkanImageView() override { + if (m_imageView) + m_device->destroyImageView(m_imageView); + } + + VulkanImageView &operator =3D (const VulkanImageView &) =3D delete; + + VulkanImageView &operator =3D (VulkanImageView &&other) { + if (m_imageView) + m_device->destroyImageView(m_imageView); + + m_device =3D other.m_device; + m_imageView =3D other.m_imageView; + m_type =3D other.m_type; + m_format =3D other.m_format; + + other.m_device =3D nullptr; + other.m_imageView =3D VK_NULL_HANDLE; + other.m_type =3D VK_IMAGE_VIEW_TYPE_1D; + other.m_format =3D 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 !=3D 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 &) =3D 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 =3D nullptr; + other.m_framebuffer =3D VK_NULL_HANDLE; + other.m_width =3D 0; + other.m_height =3D 0; + other.m_layers =3D 0; + } + + ~VulkanFramebuffer() override { + if (m_framebuffer) + m_device->destroyFramebuffer(m_framebuffer); + } + + VulkanFramebuffer &operator =3D (const VulkanFramebuffer &) =3D delete; + + VulkanFramebuffer &operator =3D (VulkanFramebuffer &&other) { + if (m_framebuffer) + m_device->destroyFramebuffer(m_framebuffer); + + m_device =3D other.m_device; + m_framebuffer =3D other.m_framebuffer; + m_width =3D other.m_width; + m_height =3D other.m_height; + m_layers =3D other.m_layers; + + other.m_device =3D nullptr; + other.m_framebuffer =3D VK_NULL_HANDLE; + other.m_width =3D 0; + other.m_height =3D 0; + other.m_layers =3D 0; + + return *this; + } + + operator VkFramebuffer () const { return m_framebuffer; } + + VkFramebuffer handle() const { return m_framebuffer; } + + bool isValid() const { return m_framebuffer !=3D 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 &createInf= o) + : 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 &) =3D 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 =3D nullptr; + other.m_buffer =3D VK_NULL_HANDLE; + other.m_size =3D 0; + other.m_usage =3D 0; + } + + ~VulkanBuffer() override { + if (m_buffer) + m_device->destroyBuffer(m_buffer); + } + + VulkanBuffer &operator =3D (const VulkanBuffer &) =3D delete; + + VulkanBuffer &operator =3D (VulkanBuffer &&other) { + if (m_buffer) + m_device->destroyBuffer(m_buffer); + + m_device =3D other.m_device; + m_buffer =3D other.m_buffer; + m_size =3D other.m_size; + m_usage =3D other.m_usage; + + other.m_device =3D nullptr; + other.m_buffer =3D VK_NULL_HANDLE; + other.m_size =3D 0; + other.m_usage =3D 0; + + return *this; + } + + operator VkBuffer () const { return m_buffer; } + + VkBuffer handle() const { return m_buffer; } + + bool isValid() const { return m_buffer !=3D 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 &c= reateInfo) + : 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 =3D nullptr; + other.m_bufferView =3D VK_NULL_HANDLE; + other.m_format =3D VK_FORMAT_UNDEFINED; + other.m_offset =3D 0; + other.m_range =3D 0; + } + + VulkanBufferView(const VulkanBufferView &other) =3D delete; + + ~VulkanBufferView() { + if (m_bufferView) + m_device->destroyBufferView(m_bufferView); + } + + bool isValid() const { return m_bufferView !=3D 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 =3D (const VulkanBufferView &other) =3D del= ete; + + VulkanBufferView &operator =3D (VulkanBufferView &&other) { + if (m_bufferView) + m_device->destroyBufferView(m_bufferView); + + m_device =3D other.m_device; + m_bufferView =3D other.m_bufferView; + m_format =3D other.m_format; + m_offset =3D other.m_offset; + m_range =3D other.m_range; + + other.m_device =3D nullptr; + other.m_bufferView =3D VK_NULL_HANDLE; + other.m_format =3D VK_FORMAT_UNDEFINED; + other.m_offset =3D 0; + other.m_range =3D 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 &createI= nfo) + : 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 =3D nullptr; + other.m_sampler =3D VK_NULL_HANDLE; + } + + VulkanSampler(const VulkanSampler &other) =3D delete; + + ~VulkanSampler() { + if (m_sampler) + m_device->destroySampler(m_sampler); + } + + bool isValid() const { return m_sampler !=3D VK_NULL_HANDLE; } + + VkSampler handle() const { return m_sampler; } + operator VkSampler () const { return m_sampler; } + + VulkanSampler &operator =3D (const VulkanSampler &other) =3D delete; + + VulkanSampler &operator =3D (VulkanSampler &&other) { + if (m_sampler) + m_device->destroySampler(m_sampler); + + m_device =3D other.m_device; + m_sampler =3D other.m_sampler; + + other.m_device =3D nullptr; + other.m_sampler =3D 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 &c= reateInfo) + : m_device(device), + m_renderPass(VK_NULL_HANDLE) + { + device->createRenderPass(&createInfo, nullptr, &m_renderPass); + } + + VulkanRenderPass(VulkanDevice *device, + const VulkanArrayProxy attac= hments, + const VulkanArrayProxy subpasse= s, + const VulkanArrayProxy dependenc= ies =3D {}) + : m_device(device), + m_renderPass(VK_NULL_HANDLE) + { + const VkRenderPassCreateInfo createInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .attachmentCount =3D attachments.count(), + .pAttachments =3D attachments.data(), + .subpassCount =3D subpasses.count(), + .pSubpasses =3D subpasses.data(), + .dependencyCount =3D dependencies.count(), + .pDependencies =3D dependencies.data(), + }; + + device->createRenderPass(&createInfo, nullptr, &m_renderPass); + } + + VulkanRenderPass(VulkanRenderPass &&other) + : m_device(other.m_device), + m_renderPass(other.m_renderPass) + { + other.m_device =3D VK_NULL_HANDLE; + other.m_renderPass =3D VK_NULL_HANDLE; + } + + VulkanRenderPass(const VulkanRenderPass &other) =3D delete; + + ~VulkanRenderPass() { + if (m_renderPass) + m_device->destroyRenderPass(m_renderPass); + } + + bool isValid() const { return m_renderPass !=3D VK_NULL_HANDLE; } + + VkRenderPass handle() const { return m_renderPass; } + operator VkRenderPass () const { return m_renderPass; } + + VulkanRenderPass &operator =3D (const VulkanRenderPass &other) =3D del= ete; + + VulkanRenderPass &operator =3D (VulkanRenderPass &&other) { + if (m_renderPass) + m_device->destroyRenderPass(m_renderPass); + + m_device =3D other.m_device; + m_renderPass =3D other.m_renderPass; + + other.m_device =3D VK_NULL_HANDLE; + other.m_renderPass =3D 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 =3D { + .sType =3D VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_IN= FO, + .pNext =3D nullptr, + .flags =3D flags, + .queueFamilyIndex =3D 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 =3D nullptr; + other.m_commandPool =3D VK_NULL_HANDLE; + other.m_queueFamilyIndex =3D 0; + } + + VulkanCommandPool(const VulkanCommandPool &other) =3D delete; + + ~VulkanCommandPool() { + if (m_commandPool) + m_device->destroyCommandPool(m_commandPool); + } + + /** + * Recycles all of the resources from all of the command buffers alloc= ated + * 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 st= ate. + */ + void reset(VkCommandPoolResetFlags flags =3D 0) { + m_device->resetCommandPool(m_commandPool, flags); + } + + /** + * Recycles unused memory back to the system. + * + * This function requires VK_KHR_maintenance1. + */ + void trim(VkCommandPoolTrimFlagsKHR flags =3D 0) { + m_device->trimCommandPoolKHR(m_commandPool, flags); + } + + bool isValid() const { return m_commandPool !=3D VK_NULL_HANDLE; } + bool commandBuffersResettable() const { return m_createFlags & VK_COMM= AND_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 =3D (const VulkanCommandPool &other) =3D d= elete; + + VulkanCommandPool &operator =3D (VulkanCommandPool &&other) { + if (m_commandPool) + m_device->destroyCommandPool(m_commandPool); + + m_device =3D other.m_device; + m_commandPool =3D other.m_commandPool; + m_queueFamilyIndex =3D other.m_queueFamilyIndex; + + other.m_device =3D nullptr; + other.m_commandPool =3D VK_NULL_HANDLE; + other.m_queueFamilyIndex =3D 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, V= kCommandBufferLevel level) + : m_device(device), + m_commandPool(commandPool), + m_commandBuffer(VK_NULL_HANDLE), + m_autoDelete(true), + m_active(false), + m_renderPassActive(false) + { + const VkCommandBufferAllocateInfo allocateInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOC= ATE_INFO, + .pNext =3D nullptr, + .commandPool =3D commandPool, + .level =3D level, + .commandBufferCount =3D 1 + }; + + device->allocateCommandBuffers(&allocateInfo, &m_commandBuffer); + } + + VulkanCommandBuffer(const VulkanCommandBuffer &) =3D 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 =3D nullptr; + other.m_commandPool =3D VK_NULL_HANDLE; + other.m_commandBuffer =3D VK_NULL_HANDLE; + other.m_autoDelete =3D false; + other.m_active =3D false; + other.m_renderPassActive =3D false; + } + + ~VulkanCommandBuffer() { + if (m_autoDelete && m_commandBuffer) + free(); + } + + VulkanCommandBuffer &operator =3D (VulkanCommandBuffer &&other) { + if (m_autoDelete && m_commandBuffer) + free(); + + m_device =3D other.m_device; + m_commandPool =3D other.m_commandPool; + m_commandBuffer =3D other.m_commandBuffer; + m_autoDelete =3D other.m_autoDelete; + m_active =3D other.m_active; + m_renderPassActive =3D other.m_renderPassActive; + + other.m_device =3D nullptr; + other.m_commandPool =3D VK_NULL_HANDLE; + other.m_commandBuffer =3D VK_NULL_HANDLE; + other.m_autoDelete =3D false; + other.m_active =3D false; + other.m_renderPassActive =3D false; + + return *this; + } + + /** + * Returns true if the command buffer is valid; and false otherwise. + */ + bool isValid() const { return m_commandBuffer !=3D VK_NULL_HANDLE; } + + /** + * Returns true if the command buffer is in the recording state; and f= alse 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 =3D enable; } + + /** + * Returns true if the command buffer will be freed when the destructo= r is invoked; and false otherwise. + */ + bool autoDelete() const { return m_autoDelete; } + + /** + * Resets the command buffer, allowing it be recorded again. + */ + void reset(VkCommandBufferResetFlags flags =3D 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 =3D nullptr; + m_commandBuffer =3D VK_NULL_HANDLE; + m_commandPool =3D 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 VkCommandBufferInher= itanceInfo *pInheritanceInfo =3D nullptr) { + const VkCommandBufferBeginInfo beginInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_I= NFO, + .pNext =3D nullptr, + .flags =3D flags, + .pInheritanceInfo =3D pInheritanceInfo + }; + + vkBeginCommandBuffer(m_commandBuffer, &beginInfo); + m_active =3D true; + } + + void end() { + vkEndCommandBuffer(m_commandBuffer); + m_active =3D false; + } + + void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pi= peline) { + vkCmdBindPipeline(m_commandBuffer, pipelineBindPoint, pipeline); + } + + void setViewport(uint32_t firstViewport, uint32_t viewportCount, const= VkViewport *pViewports) { + vkCmdSetViewport(m_commandBuffer, firstViewport, viewportCount, pV= iewports); + } + + void setViewport(uint32_t firstViewport, const VulkanArrayProxy &viewports) { + vkCmdSetViewport(m_commandBuffer, firstViewport, viewports.count()= , viewports.data()); + } + + void setScissor(uint32_t firstScissor, uint32_t scissorCount, const Vk= Rect2D *pScissors) { + vkCmdSetScissor(m_commandBuffer, firstScissor, scissorCount, pScis= sors); + } + + void setScissor(uint32_t firstScissor, const VulkanArrayProxy &scissors) { + vkCmdSetScissor(m_commandBuffer, firstScissor, scissors.count(), s= cissors.data()); + } + + void setLineWidth(float lineWidth) { + vkCmdSetLineWidth(m_commandBuffer, lineWidth); + } + + void setDepthBias(float depthBiasConstantFactor, float depthBiasClamp,= float depthBiasSlopeFactor) { + vkCmdSetDepthBias(m_commandBuffer, depthBiasConstantFactor, depthB= iasClamp, depthBiasSlopeFactor); + } + + void setBlendConstants(const float blendConstants[4]) { + vkCmdSetBlendConstants(m_commandBuffer, blendConstants); + } + + void setDepthBounds(float minDepthBounds, float maxDepthBounds) { + vkCmdSetDepthBounds(m_commandBuffer, minDepthBounds, maxDepthBound= s); + } + + void setStencilCompareMask(VkStencilFaceFlags faceMask, uint32_t compa= reMask) { + vkCmdSetStencilCompareMask(m_commandBuffer, faceMask, compareMask); + } + + void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t writeMa= sk) { + vkCmdSetStencilWriteMask(m_commandBuffer, faceMask, writeMask); + } + + void setStencilReference(VkStencilFaceFlags faceMask, uint32_t referen= ce) { + vkCmdSetStencilReference(m_commandBuffer, faceMask, reference); + } + + void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipel= ineLayout layout, + uint32_t firstSet, uint32_t descriptorSetCount= , const VkDescriptorSet *pDescriptorSets, + uint32_t dynamicOffsetCount, const uint32_t *p= DynamicOffsets) { + vkCmdBindDescriptorSets(m_commandBuffer, pipelineBindPoint, layout= , firstSet, + descriptorSetCount, pDescriptorSets, dynam= icOffsetCount, pDynamicOffsets); + } + + void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, VkPipel= ineLayout layout, + uint32_t firstSet, const VulkanArrayProxy &descriptorSets, + const VulkanArrayProxy &dynamicOffse= ts =3D {}) { + vkCmdBindDescriptorSets(m_commandBuffer, pipelineBindPoint, layout= , firstSet, + descriptorSets.count(), descriptorSets.dat= a(), + dynamicOffsets.count(), dynamicOffsets.dat= a()); + } + + void bindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType= indexType) { + vkCmdBindIndexBuffer(m_commandBuffer, buffer, offset, indexType); + } + + void bindVertexBuffers(uint32_t firstBinding, uint32_t bindingCount, c= onst VkBuffer *pBuffers, const VkDeviceSize *pOffsets) { + vkCmdBindVertexBuffers(m_commandBuffer, firstBinding, bindingCount= , pBuffers, pOffsets); + } + + void bindVertexBuffers(uint32_t firstBinding, const VulkanArrayProxy &buffers, const VulkanArrayProxy &offsets) { + assert(buffers.count() =3D=3D offsets.count()); + vkCmdBindVertexBuffers(m_commandBuffer, firstBinding, buffers.coun= t(), buffers.data(), offsets.data()); + } + + void draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t first= Vertex, 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, first= Index, vertexOffset, firstInstance); + } + + void drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawC= ount, uint32_t stride) { + vkCmdDrawIndirect(m_commandBuffer, buffer, offset, drawCount, stri= de); + } + + void drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_= t drawCount, uint32_t stride) { + vkCmdDrawIndexedIndirect(m_commandBuffer, buffer, offset, drawCoun= t, 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 regio= nCount, const VkBufferCopy *pRegions) { + vkCmdCopyBuffer(m_commandBuffer, srcBuffer, dstBuffer, regionCount= , pRegions); + } + + void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, const VulkanAr= rayProxy ®ions) { + vkCmdCopyBuffer(m_commandBuffer, srcBuffer, dstBuffer, regions.cou= nt(), 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, VkFi= lter filter) { + vkCmdBlitImage(m_commandBuffer, srcImage, srcImageLayout, dstImage= , dstImageLayout, regionCount, pRegions, filter); + } + + void copyBufferToImage(VkBuffer srcBuffer, VkImage dstImage, VkImageLa= yout dstImageLayout, + uint32_t regionCount, const VkBufferImageCopy *= pRegions) { + vkCmdCopyBufferToImage(m_commandBuffer, srcBuffer, dstImage, dstIm= ageLayout, 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, VkDevice= Size dataSize, const void *pData) { + vkCmdUpdateBuffer(m_commandBuffer, dstBuffer, dstOffset, dataSize,= pData); + } + + void fillBuffer(VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSi= ze size, uint32_t data) { + vkCmdFillBuffer(m_commandBuffer, dstBuffer, dstOffset, size, data); + } + + void clearColorImage(VkImage image, VkImageLayout imageLayout, const V= kClearColorValue *pColor, + uint32_t rangeCount, const VkImageSubresourceRang= e *pRanges) { + vkCmdClearColorImage(m_commandBuffer, image, imageLayout, pColor, = rangeCount, pRanges); + } + + void clearDepthStencilImage(VkImage image, VkImageLayout imageLayout, = const VkClearDepthStencilValue *pDepthStencil, + uint32_t rangeCount, const VkImageSubresou= rceRange *pRanges) { + vkCmdClearDepthStencilImage(m_commandBuffer, image, imageLayout, p= DepthStencil, rangeCount, pRanges); + } + + void clearAttachments(uint32_t attachmentCount, const VkClearAttachmen= t *pAttachments, uint32_t rectCount, const VkClearRect *pRects) { + vkCmdClearAttachments(m_commandBuffer, attachmentCount, pAttachmen= ts, rectCount, pRects); + } + + void resolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkIm= age dstImage, VkImageLayout dstImageLayout, + uint32_t regionCount, const VkImageResolve *pRegions= ) { + vkCmdResolveImage(m_commandBuffer, srcImage, srcImageLayout, dstIm= age, 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, VkPipelineStageFlag= s dstStageMask, + uint32_t memoryBarrierCount, const VkMemoryBarrier *pM= emoryBarriers, + uint32_t bufferMemoryBarrierCount, const VkBufferMemor= yBarrier *pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, const VkImageMemoryB= arrier *pImageMemoryBarriers) { + vkCmdWaitEvents(m_commandBuffer, eventCount, pEvents, + srcStageMask, dstStageMask, + memoryBarrierCount, pMemoryBarriers, + bufferMemoryBarrierCount, pBufferMemoryBarriers, + imageMemoryBarrierCount, pImageMemoryBarriers); + } + + void pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStag= eFlags dstStageMask, VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, const VkMemoryBarrie= r *pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, const VkBuffer= MemoryBarrier *pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, const VkImageMe= moryBarrier *pImageMemoryBarriers) { + vkCmdPipelineBarrier(m_commandBuffer, srcStageMask, dstStageMask, = dependencyFlags, + memoryBarrierCount, pMemoryBarriers, + bufferMemoryBarrierCount, pBufferMemoryBarrie= rs, + imageMemoryBarrierCount, pImageMemoryBarriers= ); + } + + void pipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStag= eFlags dstStageMask, VkDependencyFlags dependencyFlags, + const VulkanArrayProxy &memoryBa= rriers, + const VulkanArrayProxy &bu= fferMemoryBarriers, + const VulkanArrayProxy &ima= geMemoryBarriers) { + vkCmdPipelineBarrier(m_commandBuffer, srcStageMask, dstStageMask, = dependencyFlags, + memoryBarriers.count(), memoryBarriers.data(), + bufferMemoryBarriers.count(), bufferMemoryBar= riers.data(), + imageMemoryBarriers.count(), imageMemoryBarri= ers.data()); + } + + void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlF= lags 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, queryC= ount); + } + + void writeTimestamp(VkPipelineStageFlagBits pipelineStage, VkQueryPool= queryPool, uint32_t query) { + vkCmdWriteTimestamp(m_commandBuffer, pipelineStage, queryPool, que= ry); + } + + void copyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, = uint32_t queryCount, + VkBuffer dstBuffer, VkDeviceSize dstOff= set, VkDeviceSize stride, VkQueryResultFlags flags) { + vkCmdCopyQueryPoolResults(m_commandBuffer, queryPool, firstQuery, = queryCount, dstBuffer, dstOffset, stride, flags); + } + + void pushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFl= ags, uint32_t offset, uint32_t size, const void *pValues) { + vkCmdPushConstants(m_commandBuffer, layout, stageFlags, offset, si= ze, pValues); + } + + void pushDescriptorSetKHR(VkPipelineBindPoint pipelineBindPoint, VkPip= elineLayout layout, uint32_t set, + uint32_t descriptorWriteCount, const VkWrite= DescriptorSet *pDescriptorWrites) { + pfnCmdPushDescriptorSetKHR(m_commandBuffer, pipelineBindPoint, lay= out, set, + descriptorWriteCount, pDescriptorWrites= ); + } + + void pushDescriptorSetKHR(VkPipelineBindPoint pipelineBindPoint, VkPip= elineLayout layout, uint32_t set, + const VulkanArrayProxy= &descriptorWrites) { + pfnCmdPushDescriptorSetKHR(m_commandBuffer, pipelineBindPoint, lay= out, set, + descriptorWrites.count(), descriptorWri= tes.data()); + } + + void pushDescriptorSetWithTemplateKHR(VkDescriptorUpdateTemplateKHR de= scriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void *= pData) { + pfnCmdPushDescriptorSetWithTemplateKHR(m_commandBuffer, descriptor= UpdateTemplate, layout, set, pData); + } + + void beginRenderPass(const VkRenderPassBeginInfo *pRenderPassBegin, Vk= SubpassContents contents) { + vkCmdBeginRenderPass(m_commandBuffer, pRenderPassBegin, contents); + m_renderPassActive =3D true; + } + + void beginRenderPass(const VkRenderPassBeginInfo &renderPassBegin, VkS= ubpassContents contents) { + vkCmdBeginRenderPass(m_commandBuffer, &renderPassBegin, contents); + m_renderPassActive =3D true; + } + + void nextSubpass(VkSubpassContents contents) { + vkCmdNextSubpass(m_commandBuffer, contents); + } + + void endRenderPass() { + vkCmdEndRenderPass(m_commandBuffer); + m_renderPassActive =3D false; + } + + void executeCommands(uint32_t commandBufferCount, const VkCommandBuffe= r *pCommandBuffers) { + vkCmdExecuteCommands(m_commandBuffer, commandBufferCount, pCommand= Buffers); + } + + // VK_EXT_discard_rectangles + void setDiscardRectangleEXT(uint32_t firstDiscardRectangle, uint32_t d= iscardRectangleCount, const VkRect2D *pDiscardRectangles) { + vkCmdSetDiscardRectangleEXT(m_commandBuffer, firstDiscardRectangle= , discardRectangleCount, pDiscardRectangles); + } + + void setDiscardRectangleEXT(uint32_t firstDiscardRectangle, const Vulk= anArrayProxy &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 &) =3D 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 =3D nullptr; + other.m_memory =3D VK_NULL_HANDLE; + other.m_size =3D 0; + other.m_flags =3D 0; + other.m_exportableHandleTypes =3D 0; + other.m_dedicated =3D false; + other.m_imported =3D false; + other.m_mapped =3D false; + } + + ~VulkanDeviceMemory() override { + if (m_memory) + m_device->freeMemory(m_memory, nullptr); + } + + VulkanDeviceMemory &operator =3D (const VulkanDeviceMemory &) =3D dele= te; + + VulkanDeviceMemory &operator =3D (VulkanDeviceMemory &&other) { + if (m_memory) + m_device->freeMemory(m_memory, nullptr); + + m_device =3D other.m_device; + m_memory =3D other.m_memory; + m_size =3D other.m_size; + m_flags =3D other.m_flags; + m_exportableHandleTypes =3D other.m_exportableHandleTypes; + m_dedicated =3D other.m_dedicated; + m_imported =3D other.m_imported; + m_mapped =3D other.m_mapped; + + other.m_device =3D nullptr; + other.m_memory =3D VK_NULL_HANDLE; + other.m_size =3D 0; + other.m_flags =3D 0; + other.m_exportableHandleTypes =3D 0; + other.m_dedicated =3D false; + other.m_imported =3D false; + other.m_mapped =3D false; + + return *this; + } + + VkDeviceMemory handle() const { return m_memory; } + operator VkDeviceMemory() const { return m_memory; } + + bool isValid() const { return m_memory !=3D VK_NULL_HANDLE; } + + VkDeviceSize size() const { return m_size; } + + VkMemoryPropertyFlags propertyFlags() const { return m_flags; } + VkExternalMemoryHandleTypeFlagsKHR exportableHandleTypes() const { ret= urn m_exportableHandleTypes; } + + bool isDeviceLocal() const { return m_flags & VK_MEMORY_PROPERTY_DEVIC= E_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_C= ACHED_BIT; } + bool isLazilyAllocated() const { return m_flags & VK_MEMORY_PROPERTY_L= AZILY_ALLOCATED_BIT; } + bool isDedicated() const { return m_dedicated; } + bool isImported() const { return m_imported; } + bool isExportable() const { return m_exportableHandleTypes !=3D 0; } + bool isMapped() const { return m_mapped; } + + VkResult getFd(VkExternalMemoryHandleTypeFlagBitsKHR handleType, int *= pFd) { + const VkMemoryGetFdInfoKHR getFdInfo { + .sType =3D VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + .pNext =3D nullptr, + .memory =3D m_memory, + .handleType =3D handleType + }; + assert((m_exportableHandleTypes & handleType) !=3D 0); + return m_device->getMemoryFdKHR(&getFdInfo, pFd); + } + + VkResult map(VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags = flags, void **ppData) { + VkResult result =3D m_device->mapMemory(m_memory, offset, size, fl= ags, ppData); + if (result =3D=3D VK_SUCCESS) + m_mapped =3D 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 =3D 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 =3D { + .sType =3D VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0 + }; + + m_device->createSemaphore(&createInfo, nullptr, &m_semaphore); + } + + VulkanSemaphore(VulkanDevice *device, const VkSemaphoreCreateInfo &cre= ateInfo) + : m_device(device), + m_semaphore(VK_NULL_HANDLE) + { + m_device->createSemaphore(&createInfo, nullptr, &m_semaphore); + } + + VulkanSemaphore(const VulkanSemaphore &other) =3D delete; + + VulkanSemaphore(VulkanSemaphore &&other) + : m_device(other.m_device), + m_semaphore(other.m_semaphore) + { + other.m_device =3D nullptr; + other.m_semaphore =3D VK_NULL_HANDLE; + } + + ~VulkanSemaphore() { + if (m_semaphore) + m_device->destroySemaphore(m_semaphore); + } + + VulkanSemaphore &operator =3D (const VulkanSemaphore &other) =3D delet= e; + + VulkanSemaphore &operator =3D (VulkanSemaphore &&other) { + if (m_semaphore) + m_device->destroySemaphore(m_semaphore); + + m_device =3D other.m_device; + m_semaphore =3D other.m_semaphore; + + other.m_device =3D nullptr; + other.m_semaphore =3D 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 =3D 0) + : m_device(device) + { + const VkFenceCreateInfo createInfo =3D { + .sType =3D VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 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 &) =3D delete; + + VulkanFence(VulkanFence &&other) + : m_device(other.m_device), + m_fence(other.m_fence) + { + other.m_device =3D nullptr; + other.m_fence =3D VK_NULL_HANDLE; + } + + ~VulkanFence() override { + if (m_fence) + m_device->destroyFence(m_fence); + } + + VulkanFence &operator =3D (const VulkanFence &) =3D delete; + + VulkanFence &operator =3D (VulkanFence &&other) { + if (m_fence) + m_device->destroyFence(m_fence); + + m_device =3D other.m_device; + m_fence =3D other.m_fence; + + other.m_device =3D nullptr; + other.m_fence =3D 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() =3D=3D VK_SUCCESS; + } + + void reset() { + m_device->resetFences(1, &m_fence); + } + + void wait(uint64_t timeout =3D 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 &) =3D delete; + + VulkanShaderModule(VulkanShaderModule &&other) + : VulkanObject(), + m_device(other.m_device), + m_shaderModule(other.m_shaderModule) + { + other.m_device =3D nullptr; + other.m_shaderModule =3D VK_NULL_HANDLE; + } + + ~VulkanShaderModule() override { + if (m_shaderModule) + m_device->destroyShaderModule(m_shaderModule, nullptr); + } + + VulkanShaderModule &operator =3D (const VulkanShaderModule &) =3D dele= te; + + VulkanShaderModule &operator =3D (VulkanShaderModule &&other) { + if (m_shaderModule) + m_device->destroyShaderModule(m_shaderModule, nullptr); + + m_device =3D other.m_device; + m_shaderModule =3D other.m_shaderModule; + + other.m_device =3D nullptr; + other.m_shaderModule =3D VK_NULL_HANDLE; + + return *this; + } + + bool isValid() const { return m_shaderModule !=3D 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 ®io= n) + : cmd(cmd), + region(region) + { + } + + template + void forEachRect(Func f) { + for (const QRect &r : region) { + const VkRect2D scissor =3D { + .offset =3D { (int32_t) r.x(), (int32_t) r.y() = }, + .extent =3D { (uint32_t) r.width(), (uint32_t) r.height() } + }; + + cmd->setScissor(0, 1, &scissor); + f(); + } + } + + void draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t first= Vertex, 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, inde= xCount, instanceCount, firstIndex, vertexOffset, firstInstance)); + } + + void drawIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_t drawC= ount, uint32_t stride) { + forEachRect(std::bind(&VulkanCommandBuffer::drawIndirect, cmd, buf= fer, offset, drawCount, stride)); + } + + void drawIndexedIndirect(VkBuffer buffer, VkDeviceSize offset, uint32_= t drawCount, uint32_t stride) { + forEachRect(std::bind(&VulkanCommandBuffer::drawIndexedIndirect, c= md, 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 buffer, VkDeviceSize o= ffset, VkDeviceSize range, void *data =3D nullptr) + : m_buffer(buffer), + m_offset(offset), + m_range(range), + m_data(data) + { + } + + std::shared_ptr 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 m_buffer; + VkDeviceSize m_offset; + VkDeviceSize m_range; + void *m_data; +}; + + + +// ----------------------------------------------------------------------- + + + +class KWINVULKANUTILS_EXPORT VulkanDeviceMemoryAllocator +{ +public: + VulkanDeviceMemoryAllocator(VulkanDevice *device, const std::vector &enabledDeviceExtensions); + virtual ~VulkanDeviceMemoryAllocator(); + + VulkanDevice *device() const { return m_device; } + + /** + * Returns the index of the first memory type in memoryTypeBits that h= as 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 memoryTy= peBits that has + * all the flags in optimal set, or if that fails, the first memory ty= pe that has + * all the flags in required set. + * + * The memory will be allocated as non-dedicated and non-exportable. + */ + std::shared_ptr allocateMemory(VkDeviceSize size, + uint32_t memoryType= Bits, + VkMemoryPropertyFla= gs optimal, + VkMemoryPropertyFla= gs 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 t= hat has + * all the flags in optimal set, or if that fails, the first memory ty= pe that has + * all the flags in required set. + * + * The memory will be allocated as dedicated if the implementation ind= icates that + * dedicated memory is preferred or required for the given buffer. + * + * The memory will be allocated as non-exportable. + */ + std::shared_ptr allocateMemory(std::shared_ptr &buffer, + VkMemoryPropertyFla= gs optimal, + VkMemoryPropertyFla= gs required); + + /** + * Allocates memory for the given image, and binds the image to the me= mory object. + * + * The memory will be allocated from the first supported memory type t= hat has + * all the flags in optimal set, or if that fails, the first memory ty= pe that has + * all the flags in required set. + * + * The memory will be allocated as dedicated if the implementation ind= icates that + * dedicated memory is preferred or required for the given image. + * + * The memory will be allocated as non-exportable. + */ + std::shared_ptr allocateMemory(std::shared_ptr &image, + VkMemoryPropertyFla= gs optimal, + VkMemoryPropertyFla= gs required); + + /** + * Returns the memory properties for the physical device. + */ + const VkPhysicalDeviceMemoryProperties &memoryProperties() const { ret= urn m_memoryProperties; } + +protected: + /** + * @internal + */ + std::shared_ptr allocateMemoryInternal(VkDeviceSiz= e size, uint32_t memoryTypeBits, + VkMemoryPro= pertyFlags optimal, + VkMemoryPro= pertyFlags required, + const void = *pAllocateInfoNext); + +private: + VulkanDevice *m_device; + VkPhysicalDeviceMemoryProperties m_memoryProperties; + bool m_haveExternalMemory =3D false; + bool m_haveExternalMemoryFd =3D false; + bool m_haveDedicatedAllocation =3D false; + bool m_haveGetMemoryRequirements2 =3D false; + bool m_haveBindMemory2 =3D false; + bool m_haveExternalMemoryDmaBuf =3D false; +}; + + + +// ----------------------------------------------------------------------- + + + +class KWINVULKANUTILS_EXPORT VulkanCircularAllocatorBase +{ +public: + VulkanCircularAllocatorBase(const VulkanCircularAllocatorBase &) =3D d= elete; + + virtual ~VulkanCircularAllocatorBase(); + + /** + * Inserts any non-coherent mapped memory ranges that need to be flush= ed 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> it); + + /** + * Creates and returns a frame boundary object. + * + * This object should be associated with the fence passed to vkQueueSu= bmit() when submitting + * command buffers that access memory allocated from the ring buffer. + * + * The FrameBoundary object holds a strong reference to the buffer, pr= eventing it from being + * deleted while it is busy, along with the busy offset within the rin= g buffer. + * When the FrameBoundary object is destroyed, its destructor moves th= e tail pointer in the + * internal buffer, allowing the allocated memory ranges to be reused. + */ + std::shared_ptr createFrameBoundary(); + + VulkanCircularAllocatorBase &operator =3D (const VulkanCircularAllocat= orBase &) =3D delete; + +protected: + class CircularBuffer; + + VulkanCircularAllocatorBase(VulkanDevice *device, uint32_t nonCoherent= AtomSize); + +protected: + VulkanDevice *m_device; + std::shared_ptr m_circularBuffer; + std::vector> m_orphanedBuffers; + VkDeviceSize m_nonCoherentAtomSize =3D 1; +}; + + + +// ----------------------------------------------------------------------- + + + +/** + * VulkanUploadManager is used for streaming vertices, uniforms and image = data. + */ +class KWINVULKANUTILS_EXPORT VulkanUploadManager : public VulkanCircularAl= locatorBase +{ +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 &) =3D 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_minTexel= BufferOffsetAlignment; } + + /** + * Returns the minimum uniform buffer offset alignment. + */ + VkDeviceSize minUniformBufferOffsetAlignment() const { return m_minUni= formBufferOffsetAlignment; } + + /** + * Returns the minimum storage buffer offset alignment. + */ + VkDeviceSize minStorageBufferOffsetAlignment() const { return m_minSto= rageBufferOffsetAlignment; } + + /** + * Allocates size bytes of data from the upload buffer. + */ + VulkanBufferRange allocate(size_t size, uint32_t alignment =3D 4); + + /** + * Uploads size bytes of data into the upload buffer. + */ + VulkanBufferRange upload(const void *data, size_t size, uint32_t align= ment =3D 4) { + auto range =3D allocate(size, alignment); + memcpy(range.data(), data, size); + return range; + } + + /** + * Uploads size bytes of data into the upload buffer, aligning the all= ocation + * 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 all= ocation + * 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 all= ocation + * 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 + VulkanBufferRange emplace(Args&&... args) { + auto range =3D allocate(sizeof(T), 4); + new(range.data()) T(std::forward(args)...); + return range; + } + + /** + * Emplaces an object of type T in the upload buffer, aligning the all= ocation + * to the minimum uniform buffer offset alignment. + */ + template + VulkanBufferRange emplaceUniform(Args&&... args) { + auto range =3D allocate(sizeof(T), m_minUniformBufferOffsetAlignme= nt); + new(range.data()) T(std::forward(args)...); + return range; + } + + VulkanUploadManager &operator =3D (const VulkanUploadManager &) =3D de= lete; + +private: + void reallocate(size_t minimumSize); + +private: + VulkanDeviceMemoryAllocator *m_allocator; + size_t m_initialSize; + VkBufferUsageFlags m_bufferUsage; + VkMemoryPropertyFlags m_optimalMemoryFlags; + VkDeviceSize m_minTexelBufferOffsetAlignment =3D 4; + VkDeviceSize m_minUniformBufferOffsetAlignment =3D 4; + VkDeviceSize m_minStorageBufferOffsetAlignment =3D 4; +}; + + + +// ----------------------------------------------------------------------- + + + +/** + * VulkanStagingImageAllocator allocates and binds images to memory alloca= ted from a ring buffer. + */ +class KWINVULKANUTILS_EXPORT VulkanStagingImageAllocator : public VulkanCi= rcularAllocatorBase +{ +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 r= ing buffer. + * + * All images created by this method must use the same tiling mode, + * and must not be sparse or exportable. + */ + std::shared_ptr createImage(const VkImageCreateInf= o &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_HAND= LE) {} + + VulkanPipelineCache(VulkanDevice *device, size_t initialDataSize =3D 0= , const void *pInitialData =3D nullptr) + : m_device(device), + m_cache(VK_NULL_HANDLE) + { + device->createPipelineCache({ + .sType =3D VK_STRUCTURE_TYPE_PIPE= LINE_CACHE_CREATE_INFO, + .pNext =3D nullptr, + .flags =3D 0, + .initialDataSize =3D initialDataS= ize, + .pInitialData =3D pInitialData + }, nullptr, &m_cache); + } + + VulkanPipelineCache(VulkanPipelineCache &&other) + : m_device(other.m_device), + m_cache(other.m_cache) + { + other.m_device =3D VK_NULL_HANDLE; + other.m_cache =3D VK_NULL_HANDLE; + } + + VulkanPipelineCache(const VulkanPipelineCache &other) =3D 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 !=3D VK_NULL_HANDLE; } + + std::vector data() { + size_t size =3D 0; + m_device->getPipelineCacheData(m_cache, &size, nullptr); + + std::vector data(size); + m_device->getPipelineCacheData(m_cache, &size, data.data()); + return data; + } + + VulkanPipelineCache &operator =3D (const VulkanPipelineCache &other) = =3D delete; + + VulkanPipelineCache &operator =3D (VulkanPipelineCache &&other) { + if (m_cache) + m_device->destroyPipelineCache(m_cache); + + m_device =3D other.m_device; + m_cache =3D other.m_cache; + + other.m_device =3D nullptr; + other.m_cache =3D 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 =3D 0, + Texture =3D 1, + TwoTextures =3D 2, + DecorationStagingImages =3D 3, + MaterialCount =3D 4, + }; + + /** + * The traits of the pipeline, such as filters applied to the material, + * how fragments are rasterized, etc. + */ + enum Trait { + NoTraits =3D 0, + PreMultipliedAlphaBlend =3D (1 << 0), + Modulate =3D (1 << 1), + Desaturate =3D (1 << 2), + CrossFade =3D (1 << 3), + }; + + Q_DECLARE_FLAGS(Traits, Trait); + + /** + * The type of descriptors that will be used with the pipeline. + */ + enum DescriptorType { + DescriptorSet =3D 0, + PushDescriptors =3D 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 =3D 0, /// Render pass that targets images wit= h the swap chain format + OffscreenRenderPass, /// Render pass that targets VK_FORMAT_R8= G8B8A8_UNORM images + RenderPassTypeCount + }; + + /** + * The topology of the primitives rendered by the pipeline. + */ + enum Topology { + PointList =3D VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + LineList =3D VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + LineStrip =3D VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, + TriangleList =3D VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + TriangleStrip =3D VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + TriangleFan =3D 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 =3D brightness * opacity; + const float a =3D opacity; + memcpy(m_matrix, matrix.constData(), 64); + m_modulation[0] =3D rgb; + m_modulation[1] =3D rgb; + m_modulation[2] =3D rgb; + m_modulation[3] =3D a; + m_saturation =3D saturation; + m_crossFadeProgress =3D crossFadeProgress; + m_pad[0] =3D 0.0f; + m_pad[1] =3D 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 p= ipelines + * @param offscreenRenderPass Render pass for offscreen compatible pi= pelines + * @param nearestSampler Nearest-neighbor sampler to be used as = an immutable sampler + * @param linearSampler Linear sampler to be used as an immutab= le sampler + * @param havePushDescriptors Indicates whether VK_KHR_push_descripto= r is supported by the device + */ + VulkanPipelineManager(VulkanDevice *device, VulkanPipelineCache *cache, + VkSampler nearestSampler, VkSampler linearSample= r, + VkRenderPass swapchainRenderPass, VkRenderPass o= ffscreenRenderPass, + bool havePushDescriptors); + + /** + * Destroys the VulkanPipelineManager. + */ + ~VulkanPipelineManager(); + + /** + * Returns true if the VulkanPipelineManager is valid, and false other= wise. + */ + bool isValid() const { return m_valid; } + + /** + * Returns a pipeline and a pipeline layout matching the given materia= l, triats, descriptor type and topology. + */ + std::tuple pipeline(Material material, + Traits traits, + DescriptorType descr= iptorType, + Topology topology, + RenderPassType rende= rPassType); + + VkDescriptorSetLayout descriptorSetLayout(Material material) const { r= eturn 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, Descriptor= Type 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 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 =3D VK_NULL_HANDLE; + VkSampler m_linearSampler =3D VK_NULL_HANDLE; + uint32_t m_maxDiscardRectangles =3D 0; + bool m_havePushDescriptors =3D false; + bool m_valid =3D false; +}; + + + +// ----------------------------------------------------------------------- + + + +KWINVULKANUTILS_EXPORT QByteArray enumToString(VkFormat format); +KWINVULKANUTILS_EXPORT QByteArray enumToString(VkResult result); +KWINVULKANUTILS_EXPORT QByteArray enumToString(VkPresentModeKHR mode); +KWINVULKANUTILS_EXPORT QByteArray enumToString(VkPhysicalDeviceType physic= alDeviceType); + +KWINVULKANUTILS_EXPORT QByteArray vendorName(uint32_t vendorID); +KWINVULKANUTILS_EXPORT QByteArray driverVersionString(uint32_t vendorID, u= int32_t driverVersion); + +} // namespace KWin + +#endif // KWINVULKANUTILS_H diff --git a/libkwineffects/kwinvulkanutils_funcs.cpp b/libkwineffects/kwin= vulkanutils_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 =C2=A9 2017-2018 Fredrik H=C3=B6glund + +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 . +*********************************************************************/ + +#include "kwinvulkanutils_funcs.h" + +#define RESOLVE(name) \ + pfn ##name =3D (PFN_vk ##name) vkGetInstanceProcAddr(instance, "vk" #n= ame) + +namespace KWin +{ + +// VK_KHR_surface +PFN_vkDestroySurfaceKHR pfnDestroySurfaceKHR; +PFN_vkGetPhysicalDeviceSurfaceSupportKHR pfnGetPhysicalDeviceSurfaceS= upportKHR; +PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR pfnGetPhysicalDeviceSurfaceC= apabilitiesKHR; +PFN_vkGetPhysicalDeviceSurfaceFormatsKHR pfnGetPhysicalDeviceSurfaceF= ormatsKHR; +PFN_vkGetPhysicalDeviceSurfacePresentModesKHR pfnGetPhysicalDeviceSurfaceP= resentModesKHR; + +#ifdef VK_USE_PLATFORM_XCB_KHR +// VK_KHR_xcb_surface +PFN_vkCreateXcbSurfaceKHR pfnCreateXcbSurfaceKHR; +PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR pfnGetPhysicalDeviceXcbPr= esentationSupportKHR; +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +// VK_KHR_wayland_surface +PFN_vkCreateWaylandSurfaceKHR pfnCreateWaylandSurfa= ceKHR; +PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR pfnGetPhysicalDeviceW= aylandPresentationSupportKHR; +#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 pfnCreateDescriptorUpdateTemplat= eKHR; +PFN_vkDestroyDescriptorUpdateTemplateKHR pfnDestroyDescriptorUpdateTempla= teKHR; +PFN_vkUpdateDescriptorSetWithTemplateKHR pfnUpdateDescriptorSetWithTempla= teKHR; +PFN_vkCmdPushDescriptorSetWithTemplateKHR pfnCmdPushDescriptorSetWithTempl= ateKHR; + +// VK_EXT_debug_report +PFN_vkCreateDebugReportCallbackEXT pfnCreateDebugReportCallbackEXT; +PFN_vkDestroyDebugReportCallbackEXT pfnDestroyDebugReportCallbackEXT; +PFN_vkDebugReportMessageEXT pfnDebugReportMessageEXT; + +// VK_KHR_get_physical_device_properties2 +PFN_vkGetPhysicalDeviceFeatures2KHR pfnGetPhysicalDevic= eFeatures2KHR; +PFN_vkGetPhysicalDeviceProperties2KHR pfnGetPhysicalDevic= eProperties2KHR; +PFN_vkGetPhysicalDeviceFormatProperties2KHR pfnGetPhysicalDevic= eFormatProperties2KHR; +PFN_vkGetPhysicalDeviceImageFormatProperties2KHR pfnGetPhysicalDevic= eImageFormatProperties2KHR; +PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR pfnGetPhysicalDevic= eQueueFamilyProperties2KHR; +PFN_vkGetPhysicalDeviceMemoryProperties2KHR pfnGetPhysicalDevic= eMemoryProperties2KHR; +PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR pfnGetPhysicalDevic= eSparseImageFormatProperties2KHR; + +// VK_KHR_external_memory_capabilities +PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfnGetPhysicalDeviceExt= ernalBufferPropertiesKHR; + +// VK_KHR_external_memory_fd +PFN_vkGetMemoryFdKHR pfnGetMemoryFdKHR; +PFN_vkGetMemoryFdPropertiesKHR pfnGetMemoryFdPropertiesKHR; + +// VK_KHR_external_semaphore_capabilities +PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR pfnGetPhysicalDevice= ExternalSemaphorePropertiesKHR; + +// VK_KHR_external_semaphore_fd +PFN_vkImportSemaphoreFdKHR pfnImportSemaphoreFdKHR; +PFN_vkGetSemaphoreFdKHR pfnGetSemaphoreFdKHR; + +// VK_KHR_get_memory_requirements2 +PFN_vkGetImageMemoryRequirements2KHR pfnGetImageMemoryRequirements2K= HR; +PFN_vkGetBufferMemoryRequirements2KHR pfnGetBufferMemoryRequirements2= KHR; +PFN_vkGetImageSparseMemoryRequirements2KHR pfnGetImageSparseMemoryRequirem= ents2KHR; + +// 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/kwinvu= lkanutils_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 =C2=A9 2017-2018 Fredrik H=C3=B6glund + +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 . +*********************************************************************/ + +#ifndef KWINVULKANUTILS_FUNCS_H +#define KWINVULKANUTILS_FUNCS_H + +#include + +#define VK_USE_PLATFORM_XCB_KHR +#define VK_USE_PLATFORM_WAYLAND_KHR +#include + +namespace KWin +{ + +class VulkanExtensionPropertyList; + +// VK_KHR_surface +extern KWINVULKANUTILS_EXPORT PFN_vkDestroySurfaceKHR = pfnDestroySurfaceKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceSurfaceSupportKHR = pfnGetPhysicalDeviceSurfaceSupportKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKH= R pfnGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceSurfaceFormatsKHR = pfnGetPhysicalDeviceSurfaceFormatsKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceSurfacePresentModesKH= R pfnGetPhysicalDeviceSurfacePresentModesKHR; + +#ifdef VK_USE_PLATFORM_XCB_KHR +// VK_KHR_xcb_surface +extern KWINVULKANUTILS_EXPORT PFN_vkCreateXcbSurfaceKHR = pfnCreateXcbSurfaceKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceXcbPresentationSuppor= tKHR pfnGetPhysicalDeviceXcbPresentationSupportKHR; +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +// VK_KHR_wayland_surface +extern KWINVULKANUTILS_EXPORT PFN_vkCreateWaylandSurfaceKHR = pfnCreateWaylandSurfaceKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceWaylandPresentationSu= pportKHR pfnGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +// VK_KHR_android_surface +extern KWINVULKANUTILS_EXPORT PFN_vkCreateAndroidSurfaceKHR pfnCreateAndro= idSurfaceKHR; +#endif + +// VK_KHR_swapchain +extern KWINVULKANUTILS_EXPORT PFN_vkCreateSwapchainKHR pfnCreateSwapcha= inKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkDestroySwapchainKHR pfnDestroySwapch= ainKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetSwapchainImagesKHR pfnGetSwapchainI= magesKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkAcquireNextImageKHR pfnAcquireNextIm= ageKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkQueuePresentKHR pfnQueuePresentK= HR; + +// VK_KHR_maintenance1 +extern KWINVULKANUTILS_EXPORT PFN_vkTrimCommandPoolKHR pfnTrimCommandPoolK= HR; + +// VK_KHR_push_descriptor +extern KWINVULKANUTILS_EXPORT PFN_vkCmdPushDescriptorSetKHR pfnCmdPushDesc= riptorSetKHR; + +// VK_KHR_descriptor_update_template +extern KWINVULKANUTILS_EXPORT PFN_vkCreateDescriptorUpdateTemplateKHR pf= nCreateDescriptorUpdateTemplateKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkDestroyDescriptorUpdateTemplateKHR pf= nDestroyDescriptorUpdateTemplateKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkUpdateDescriptorSetWithTemplateKHR pf= nUpdateDescriptorSetWithTemplateKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkCmdPushDescriptorSetWithTemplateKHR pf= nCmdPushDescriptorSetWithTemplateKHR; + +// VK_EXT_debug_report +extern KWINVULKANUTILS_EXPORT PFN_vkCreateDebugReportCallbackEXT pfnCreat= eDebugReportCallbackEXT; +extern KWINVULKANUTILS_EXPORT PFN_vkDestroyDebugReportCallbackEXT pfnDestr= oyDebugReportCallbackEXT; +extern KWINVULKANUTILS_EXPORT PFN_vkDebugReportMessageEXT pfnDebug= ReportMessageEXT; + +// 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_vkGetPhysicalDeviceImageFormatProperties= 2KHR pfnGetPhysicalDeviceImageFormatProperties2KHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceQueueFamilyProperties= 2KHR pfnGetPhysicalDeviceQueueFamilyProperties2KHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceMemoryProperties2KHR = pfnGetPhysicalDeviceMemoryProperties2KHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceSparseImageFormatProp= erties2KHR pfnGetPhysicalDeviceSparseImageFormatProperties2KHR; + +// VK_KHR_external_memory_capabilities +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceExternalBufferPropert= iesKHR pfnGetPhysicalDeviceExternalBufferPropertiesKHR; + +// VK_KHR_external_memory_fd +extern KWINVULKANUTILS_EXPORT PFN_vkGetMemoryFdKHR pfnGetMemoryF= dKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetMemoryFdPropertiesKHR pfnGetMemoryF= dPropertiesKHR; + +// VK_KHR_external_semaphore_capabilities +extern KWINVULKANUTILS_EXPORT PFN_vkGetPhysicalDeviceExternalSemaphoreProp= ertiesKHR pfnGetPhysicalDeviceExternalSemaphorePropertiesKHR; + +// VK_KHR_external_semaphore_fd +extern KWINVULKANUTILS_EXPORT PFN_vkImportSemaphoreFdKHR pfnImportSemaphor= eFdKHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetSemaphoreFdKHR pfnGetSemaphoreFd= KHR; + +// VK_KHR_get_memory_requirements2 +extern KWINVULKANUTILS_EXPORT PFN_vkGetImageMemoryRequirements2KHR p= fnGetImageMemoryRequirements2KHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetBufferMemoryRequirements2KHR p= fnGetBufferMemoryRequirements2KHR; +extern KWINVULKANUTILS_EXPORT PFN_vkGetImageSparseMemoryRequirements2KHR p= fnGetImageSparseMemoryRequirements2KHR; + +// VK_EXT_discard_rectangles +extern KWINVULKANUTILS_EXPORT PFN_vkCmdSetDiscardRectangleEXT pfnCmdSetDis= cardRectangleEXT; + +// VK_KHR_bind_memory2 +extern KWINVULKANUTILS_EXPORT PFN_vkBindBufferMemory2KHR pfnBindBufferMemo= ry2KHR; +extern KWINVULKANUTILS_EXPORT PFN_vkBindImageMemory2KHR pfnBindImageMemory= 2KHR; + +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 . Q_LOGGING_CATEGORY(LIBKWINEFFECTS, "libkwineffects", QtCriticalMsg) Q_LOGGING_CATEGORY(LIBKWINGLUTILS, "libkwinglutils", QtCriticalMsg) Q_LOGGING_CATEGORY(LIBKWINXRENDERUTILS, "libkwinxrenderutils", QtCriticalM= sg) +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 . Q_DECLARE_LOGGING_CATEGORY(LIBKWINEFFECTS) Q_DECLARE_LOGGING_CATEGORY(LIBKWINGLUTILS) Q_DECLARE_LOGGING_CATEGORY(LIBKWINXRENDERUTILS) +Q_DECLARE_LOGGING_CATEGORY(LIBKWINVULKANUTILS) = #endif