6#define GL_GLEXT_PROTOTYPES
11#include <QVarLengthArray>
12#include <QOpenGLContext>
13#include <QtGui/qopengl.h>
14#include <QtOpenGL/private/qvkconvenience_p.h>
26#define DECL_VK_FUNCTION(name) \
27 PFN_ ## name name = nullptr;
29#define IMPL_VK_FUNCTION(name) \
30 name = reinterpret_cast<PFN_ ## name>(f_glGetVkProcAddrNV(#name)); \
32 qCritical() << "ERROR in Vulkan proc lookup. Could not find " #name; \
92 void initFunctions(PFNGLGETVKPROCADDRNVPROC f_glGetVkProcAddrNV) {
131 int findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags
properties);
134 bool transitionImageLayout(VkImage
image, VkFormat , VkImageLayout oldLayout, VkImageLayout newLayout);
135 bool createBuffer(VkDeviceSize
size, VkBufferUsageFlags
usage, VkMemoryPropertyFlags
properties, VkBuffer&
buffer, VkDeviceMemory& bufferMemory);
136 VkCommandBuffer beginSingleTimeCommands();
137 void endSingleTimeCommands(VkCommandBuffer commandBuffer);
139 void createCommandPool();
141 bool createLogicalDevice();
144 VkInstance m_instance = VK_NULL_HANDLE;
145 VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
146 VkDevice m_device = VK_NULL_HANDLE;
147 VkCommandPool m_commandPool = VK_NULL_HANDLE;
149 VkQueue m_graphicsQueue = VK_NULL_HANDLE;
151 bool m_initFailed =
false;
163int VulkanWrapperPrivate::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags
properties)
165 VkPhysicalDeviceMemoryProperties memProperties;
166 vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties);
168 for (uint32_t
i = 0;
i < memProperties.memoryTypeCount;
i++) {
174 qCritical(
"VulkanWrapper: failed to find suitable memory type!");
181 VkImageCreateInfo imageInfo = {};
182 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
183 imageInfo.imageType = VK_IMAGE_TYPE_2D;
184 imageInfo.extent.width =
size.width();
185 imageInfo.extent.height =
size.height();
186 imageInfo.extent.depth = 1;
187 imageInfo.mipLevels = 1;
188 imageInfo.arrayLayers = 1;
189 imageInfo.format =
format;
190 imageInfo.tiling = tiling;
191 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
192 imageInfo.usage =
usage;
193 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
194 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
196 VkImage
image = VK_NULL_HANDLE;
198 if (vkCreateImage(m_device, &imageInfo,
nullptr, &
image) != VK_SUCCESS) {
199 qCritical(
"VulkanWrapper: failed to create image!");
203 std::unique_ptr imageWrapper = std::make_unique<VulkanImageWrapper>();
204 imageWrapper->textureImage =
image;
205 imageWrapper->imgMemSize = memSize;
206 imageWrapper->imgSize =
size;
208 VkMemoryRequirements memRequirements;
209 vkGetImageMemoryRequirements(m_device,
image, &memRequirements);
211 VkExportMemoryAllocateInfoKHR exportAllocInfo = {};
212 exportAllocInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
213 exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
215 VkMemoryAllocateInfo allocInfo = {};
216 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
217 allocInfo.allocationSize = memRequirements.size;
218 int memoryType = findMemoryType(memRequirements.memoryTypeBits,
properties);
221 allocInfo.memoryTypeIndex = memoryType;
222 allocInfo.pNext = &exportAllocInfo;
224 if (vkAllocateMemory(m_device, &allocInfo,
nullptr, &imageWrapper->textureImageMemory) != VK_SUCCESS) {
225 qCritical(
"VulkanWrapper: failed to allocate image memory!");
229 int res = vkBindImageMemory(m_device,
image, imageWrapper->textureImageMemory, 0);
233 VkMemoryGetFdInfoKHR memoryFdInfo = {};
234 memoryFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
235 memoryFdInfo.memory = imageWrapper->textureImageMemory;
236 memoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
238 res = vkGetMemoryFdKHR(m_device, &memoryFdInfo, &imageWrapper->imgFd);
241 return imageWrapper.release();
245bool VulkanWrapperPrivate::transitionImageLayout(VkImage
image, VkFormat , VkImageLayout oldLayout, VkImageLayout newLayout)
249 VkImageMemoryBarrier barrier = {};
250 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
251 barrier.oldLayout = oldLayout;
252 barrier.newLayout = newLayout;
253 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
254 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
255 barrier.image =
image;
256 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
257 barrier.subresourceRange.baseMipLevel = 0;
258 barrier.subresourceRange.levelCount = 1;
259 barrier.subresourceRange.baseArrayLayer = 0;
260 barrier.subresourceRange.layerCount = 1;
262 VkPipelineStageFlags sourceStage;
263 VkPipelineStageFlags destinationStage;
265 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
266 barrier.srcAccessMask = 0;
267 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
269 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
270 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
271 }
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
272 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
273 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
275 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
276 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
278 qCritical(
"VulkanWrapper: unsupported layout transition!");
282 vkCmdPipelineBarrier(
284 sourceStage, destinationStage,
291 endSingleTimeCommands(commandBuffer);
295bool VulkanWrapperPrivate::createBuffer(VkDeviceSize
size, VkBufferUsageFlags
usage, VkMemoryPropertyFlags
properties, VkBuffer&
buffer, VkDeviceMemory& bufferMemory)
297 VkBufferCreateInfo bufferInfo = {};
298 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
299 bufferInfo.size =
size;
300 bufferInfo.usage =
usage;
301 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
303 if (vkCreateBuffer(m_device, &bufferInfo,
nullptr, &
buffer) != VK_SUCCESS) {
304 qCritical(
"VulkanWrapper: failed to create buffer!");
308 VkMemoryRequirements memRequirements;
309 vkGetBufferMemoryRequirements(m_device,
buffer, &memRequirements);
311 VkMemoryAllocateInfo allocInfo = {};
312 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
313 allocInfo.allocationSize = memRequirements.size;
314 allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits,
properties);
316 if (vkAllocateMemory(m_device, &allocInfo,
nullptr, &bufferMemory) != VK_SUCCESS) {
317 qCritical(
"VulkanWrapper: failed to allocate buffer memory!");
321 vkBindBufferMemory(m_device,
buffer, bufferMemory, 0);
326VkCommandBuffer VulkanWrapperPrivate::beginSingleTimeCommands()
328 VkCommandBufferAllocateInfo allocInfo = {};
329 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
330 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
331 allocInfo.commandPool = m_commandPool;
332 allocInfo.commandBufferCount = 1;
337 int res = vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer);
341 VkCommandBufferBeginInfo beginInfo = {};
342 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
343 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
345 res = vkBeginCommandBuffer(commandBuffer, &beginInfo);
351void VulkanWrapperPrivate::endSingleTimeCommands(VkCommandBuffer commandBuffer)
353 int res = vkEndCommandBuffer(commandBuffer);
357 VkSubmitInfo submitInfo = {};
358 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
359 submitInfo.commandBufferCount = 1;
362 vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
363 vkQueueWaitIdle(m_graphicsQueue);
365 vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
368void VulkanWrapperPrivate::copyBufferToImage(VkBuffer
buffer, VkImage
image, uint32_t
width, uint32_t
height)
372 VkBufferImageCopy region = {};
373 region.bufferOffset = 0;
374 region.bufferRowLength = 0;
375 region.bufferImageHeight = 0;
376 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
377 region.imageSubresource.mipLevel = 0;
378 region.imageSubresource.baseArrayLayer = 0;
379 region.imageSubresource.layerCount = 1;
380 region.imageOffset = {0, 0, 0};
381 region.imageExtent = {
387 vkCmdCopyBufferToImage(commandBuffer,
buffer,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
389 endSingleTimeCommands(commandBuffer);
392void VulkanWrapperPrivate::createCommandPool()
396 VkCommandPoolCreateInfo poolInfo = {};
397 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
400 if (vkCreateCommandPool(m_device, &poolInfo,
nullptr, &m_commandPool) != VK_SUCCESS) {
402 qCritical(
"VulkanWrapperPrivate: could not create command pool");
410 uint32_t queueFamilyCount = 0;
411 vkGetPhysicalDeviceQueueFamilyProperties(
device, &queueFamilyCount,
nullptr);
415 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
416 vkGetPhysicalDeviceQueueFamilyProperties(
device, &queueFamilyCount, queueFamilies.data());
418#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
419 for (
const auto& queueFamily : queueFamilies) {
420 qDebug() <<
"....q" <<
"count" << queueFamily.queueCount << queueFamily.timestampValidBits <<
hex << queueFamily.queueFlags;
425 for (
const auto& queueFamily : queueFamilies) {
426 if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
436bool VulkanWrapperPrivate::createLogicalDevice()
440 std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
441 std::set<int> uniqueQueueFamilies = {
indices.graphicsFamily};
443 float queuePriority = 1.0f;
444 for (
int queueFamily : uniqueQueueFamilies) {
445 VkDeviceQueueCreateInfo queueCreateInfo = {};
446 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
447 queueCreateInfo.queueFamilyIndex = queueFamily;
448 queueCreateInfo.queueCount = 1;
449 queueCreateInfo.pQueuePriorities = &queuePriority;
450 queueCreateInfos.push_back(queueCreateInfo);
453 VkPhysicalDeviceFeatures deviceFeatures = {};
455 VkDeviceCreateInfo createInfo = {};
456 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
458 createInfo.queueCreateInfoCount =
static_cast<uint32_t
>(queueCreateInfos.size());
459 createInfo.pQueueCreateInfos = queueCreateInfos.data();
461 createInfo.pEnabledFeatures = &deviceFeatures;
463 if (vkCreateDevice(m_physicalDevice, &createInfo,
nullptr, &m_device) != VK_SUCCESS) {
464 qCritical(
"VulkanWrapper: failed to create logical device!");
468 vkGetDeviceQueue(m_device,
indices.graphicsFamily, 0, &m_graphicsQueue);
482 int texWidth =
size.width();
483 int texHeight =
size.height();
487 qCritical(
"VulkanWrapper: failed to load texture image!");
491 VkBuffer stagingBuffer;
492 VkDeviceMemory stagingBufferMemory;
493 ok = createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
499 vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &
data);
501 memcpy(
data,
pixels,
static_cast<size_t>(bufferSize));
502 vkUnmapMemory(m_device, stagingBufferMemory);
506 std::unique_ptr<VulkanImageWrapper> imageWrapper(createImage(vkFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
size, bufferSize));
512 const VkImage textureImage = imageWrapper->textureImage;
514 ok = transitionImageLayout(textureImage, vkFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
520 copyBufferToImage(stagingBuffer, textureImage,
static_cast<uint32_t
>(texWidth),
static_cast<uint32_t
>(texHeight));
521 transitionImageLayout(textureImage, vkFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
523 vkDestroyBuffer(m_device, stagingBuffer,
nullptr);
524 vkFreeMemory(m_device, stagingBufferMemory,
nullptr);
526 return imageWrapper.release();
535 ::close(imageWrapper->
imgFd);
538 vkDestroyImage(m_device, imageWrapper->
textureImage,
nullptr);
545 VkApplicationInfo applicationInfo = {};
546 applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
547 applicationInfo.pNext =
nullptr;
548 applicationInfo.pApplicationName =
nullptr;
549 applicationInfo.applicationVersion = 0;
550 applicationInfo.pEngineName =
nullptr;
551 applicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
552 applicationInfo.apiVersion = VK_MAKE_VERSION(1, 0, 5);
554 VkInstanceCreateInfo instanceCreateInfo = {};
555 instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
556 instanceCreateInfo.pNext =
nullptr;
557 instanceCreateInfo.flags = 0;
558 instanceCreateInfo.pApplicationInfo = &applicationInfo;
559 instanceCreateInfo.enabledLayerCount = 0;
560 instanceCreateInfo.ppEnabledLayerNames =
nullptr;
561 instanceCreateInfo.enabledExtensionCount = 0;
562 instanceCreateInfo.ppEnabledExtensionNames =
nullptr;
564 auto f_glGetVkProcAddrNV =
reinterpret_cast<PFNGLGETVKPROCADDRNVPROC
>(glContext->
getProcAddress(
"glGetVkProcAddrNV"));
566 if (!f_glGetVkProcAddrNV) {
567 qCritical(
"VulkanWrapper: Could not find Vulkan/GL interop function glGetVkProcAddrNV");
572 initFunctions(f_glGetVkProcAddrNV);
574 VkResult instanceCreationResult = vkCreateInstance(&instanceCreateInfo,
nullptr, &m_instance);
578 if (instanceCreationResult != VK_SUCCESS) {
579 qCritical() <<
"VulkanWrapper: Failed to create Vulkan instance: Error "
580 << instanceCreationResult;
587 auto res = vkEnumeratePhysicalDevices(m_instance, &devCount,
nullptr);
592 res = vkEnumeratePhysicalDevices(m_instance, &devCount, dev.
data());
595#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
596 VkPhysicalDeviceProperties
props;
598 vkGetPhysicalDeviceProperties(dev[0], &
props);
601 <<
"apiVersion" <<
props.apiVersion
602 <<
"driverVersion" <<
props.driverVersion
603 <<
"vendorID" <<
props.vendorID
604 <<
"deviceID" <<
props.deviceID
605 <<
"deviceType" <<
props.deviceType
606 <<
"deviceName" <<
props.deviceName;
609 m_physicalDevice = dev[0];
611 bool ok = createLogicalDevice();
613 qCritical(
"VulkanWrapperPrivate: could not create logical device");
618 VkPhysicalDeviceMemoryProperties memProps;
621 vkGetPhysicalDeviceMemoryProperties(dev[0], &memProps);
623#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
624 qDebug() <<
"Physical memory properties:\n" <<
"types:" << memProps.memoryTypeCount <<
"heaps:" << memProps.memoryHeapCount;
625 for (
uint i = 0;
i < memProps.memoryTypeCount; ++
i)
626 qDebug() <<
" " <<
i <<
"heap" << memProps.memoryTypes[
i].heapIndex <<
"flags" <<
hex << memProps.memoryTypes[
i].propertyFlags;
628 for (
uint i = 0;
i < memProps.memoryHeapCount; ++
i)
629 qDebug() <<
" " <<
i <<
"size" << memProps.memoryHeaps[
i].size <<
"flags" <<
hex << memProps.memoryHeaps[
i].flags;
632 int gpuMemoryType = -1;
634 for (
uint i = 0;
i < memProps.memoryTypeCount; ++
i) {
635 if (memProps.memoryTypes[
i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
641 if (gpuMemoryType < 0) {
642 qCritical(
"VulkanWrapper: Could not find GPU memory!");
647#ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG
648 qDebug() <<
"GPU memory type:" << gpuMemoryType <<
"heap:" << memProps.memoryTypes[gpuMemoryType].heapIndex;
650 for (
int f = 0;
f <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
f++)
652 VkFormatProperties formatProps;
653 vkGetPhysicalDeviceFormatProperties(dev[0], VkFormat(
f), &formatProps);
654 qDebug() <<
"format" <<
f <<
"features" <<
hex << formatProps.linearTilingFeatures << formatProps.optimalTilingFeatures << formatProps.bufferFeatures;
673 VkFormat vkFormat = VkFormat(QVkConvenience::vkFormatFromGlFormat(glInternalFormat));
674 if (vkFormat == VK_FORMAT_UNDEFINED)
688 return imgWrapper->
imgFd;
IOBluetoothDevice * device
QFunctionPointer getProcAddress(const QByteArray &procName) const
Resolves the function pointer to an OpenGL extension function, identified by procName.
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
VulkanImageWrapper * createTextureImage(const QImage &img)
VulkanImageWrapper * createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, VkFormat vkFormat)
VulkanWrapperPrivate(QOpenGLContext *glContext)
void freeTextureImage(VulkanImageWrapper *imageWrapper)
int getImageInfo(const VulkanImageWrapper *imgWrapper, int *memSize, int *w=nullptr, int *h=nullptr)
VulkanWrapper(QOpenGLContext *glContext)
VulkanImageWrapper * createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, uint glInternalFormat)
void freeTextureImage(VulkanImageWrapper *imageWrapper)
VulkanImageWrapper * createTextureImage(const QImage &img)
Combined button and popup list for selecting options.
VkCommandBuffer commandBuffer
static const QCssKnownValue properties[NumProperties - 1]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLsizei const GLenum * props
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum const void * pixels
GLint GLsizei GLsizei GLenum format
GLsizei GLenum const void * indices
GLfloat GLfloat GLfloat GLfloat h
GLsizeiptr const void GLenum usage
VkDeviceMemory textureImageMemory
#define IMPL_VK_FUNCTION(name)
static QT_BEGIN_NAMESPACE constexpr bool vwExtraDebug
#define DECL_VK_FUNCTION(name)