// Initialize Vulkan and composite stuff with a compute queue #include "rendervulkan.hpp" #include "main.hpp" #include "composite.h" PFN_vkGetMemoryFdKHR dyn_vkGetMemoryFdKHR; const VkApplicationInfo appInfo = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "steamcompmgr", .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .pEngineName = "just some code", .engineVersion = VK_MAKE_VERSION(1, 0, 0), .apiVersion = VK_API_VERSION_1_0, }; std::vector< const char * > g_vecSDLInstanceExts; VkInstance instance; VkSurfaceKHR surface; VkSurfaceCapabilitiesKHR surfaceCaps; std::vector< VkSurfaceFormatKHR > surfaceFormats; std::vector< VkPresentModeKHR > presentModes; uint32_t g_nSwapChainImageIndex; VkSwapchainKHR swapChain; std::vector< VkImage > swapChainImages; std::vector< VkImageView > swapChainImageViews; VkPhysicalDevice physicalDevice; uint32_t queueFamilyIndex; VkQueue queue; VkShaderModule shaderModule; VkDevice device; VkCommandPool commandPool; VkDescriptorPool descriptorPool; struct VkPhysicalDeviceMemoryProperties memoryProperties; int g_nOutImage; // ping/pong between two RTs CVulkanTexture outputImage[2]; std::unordered_map g_mapVulkanTextures; std::atomic g_nMaxVulkanTexHandle; #define MAX_DEVICE_COUNT 8 #define MAX_QUEUE_COUNT 8 #define VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA (VkStructureType)1000001002 #define VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA (VkStructureType)1000001003 struct wsi_image_create_info { VkStructureType sType; const void *pNext; bool scanout; uint32_t modifier_count; const uint64_t *modifiers; }; struct wsi_memory_allocate_info { VkStructureType sType; const void *pNext; bool implicit_sync; }; struct { uint32_t DRMFormat; VkFormat vkFormat; } s_DRMVKFormatTable[] = { { DRM_FORMAT_XRGB8888, VK_FORMAT_A8B8G8R8_UNORM_PACK32 }, { DRM_FORMAT_ARGB8888, VK_FORMAT_A8B8G8R8_UNORM_PACK32 }, { DRM_FORMAT_RGBA8888, VK_FORMAT_R8G8B8A8_UNORM }, { DRM_FORMAT_INVALID, VK_FORMAT_UNDEFINED }, }; static inline uint32_t VulkanFormatToDRM( VkFormat vkFormat ) { for ( int i = 0; s_DRMVKFormatTable[i].vkFormat != VK_FORMAT_UNDEFINED; i++ ) { if ( s_DRMVKFormatTable[i].vkFormat == vkFormat ) { return s_DRMVKFormatTable[i].DRMFormat; } } return DRM_FORMAT_INVALID; } static inline VkFormat DRMFormatToVulkan( uint32_t nDRMFormat ) { for ( int i = 0; s_DRMVKFormatTable[i].vkFormat != VK_FORMAT_UNDEFINED; i++ ) { if ( s_DRMVKFormatTable[i].DRMFormat == nDRMFormat ) { return s_DRMVKFormatTable[i].vkFormat; } } return VK_FORMAT_UNDEFINED; } int32_t findMemoryType( VkMemoryPropertyFlags properties, uint32_t requiredTypeBits ) { for ( uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++ ) { if ( ( ( 1 << i ) & requiredTypeBits ) == 0 ) continue; if ( ( properties & memoryProperties.memoryTypes[ i ].propertyFlags ) != properties ) continue; return i; } return -1; } bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, bool bFlippable, bool bTextureable, wlr_dmabuf_attributes *pDMA /* = nullptr */ ) { VkResult res = VK_ERROR_INITIALIZATION_FAILED; VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL; VkImageUsageFlags usage = bTextureable ? VK_IMAGE_USAGE_SAMPLED_BIT : VK_IMAGE_USAGE_STORAGE_BIT; VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; // Possible extensions for below wsi_image_create_info wsiImageCreateInfo = {}; VkExternalMemoryImageCreateInfo externalImageCreateInfo = {}; VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.extent.width = width; imageInfo.extent.height = height; imageInfo.extent.depth = 1; imageInfo.mipLevels = 1; imageInfo.arrayLayers = 1; imageInfo.format = format; imageInfo.tiling = tiling; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageInfo.usage = usage; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; if ( pDMA != nullptr ) { assert( format == DRMFormatToVulkan( pDMA->format ) ); } if ( bFlippable == true ) { wsiImageCreateInfo.sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA; wsiImageCreateInfo.scanout = VK_TRUE; wsiImageCreateInfo.pNext = imageInfo.pNext; imageInfo.pNext = &wsiImageCreateInfo; } if ( pDMA != nullptr ) { externalImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; externalImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; externalImageCreateInfo.pNext = imageInfo.pNext; imageInfo.pNext = &externalImageCreateInfo; } if (vkCreateImage(device, &imageInfo, nullptr, &m_vkImage) != VK_SUCCESS) { return false; } VkMemoryRequirements memRequirements; vkGetImageMemoryRequirements(device, m_vkImage, &memRequirements); // Possible pNexts wsi_memory_allocate_info wsiAllocInfo = {}; VkImportMemoryFdInfoKHR importMemoryInfo = {}; VkExportMemoryAllocateInfo memory_export_info = {}; VkMemoryDedicatedAllocateInfo memory_dedicated_info = {}; VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(properties, memRequirements.memoryTypeBits ); if ( bFlippable == true || pDMA != nullptr ) { memory_dedicated_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; memory_dedicated_info.image = m_vkImage; memory_dedicated_info.buffer = VK_NULL_HANDLE; memory_dedicated_info.pNext = allocInfo.pNext; allocInfo.pNext = &memory_dedicated_info; } if ( bFlippable == true ) { wsiAllocInfo.sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA; wsiAllocInfo.implicit_sync = true; wsiAllocInfo.pNext = allocInfo.pNext; allocInfo.pNext = &wsiAllocInfo; memory_export_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; memory_export_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; memory_export_info.pNext = allocInfo.pNext; allocInfo.pNext = &memory_export_info; } if ( pDMA != nullptr ) { // Memory already provided by pDMA importMemoryInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; importMemoryInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; importMemoryInfo.fd = pDMA->fd[0]; importMemoryInfo.pNext = allocInfo.pNext; allocInfo.pNext = &importMemoryInfo; } if (vkAllocateMemory(device, &allocInfo, nullptr, &m_vkImageMemory) != VK_SUCCESS) { return false; } res = vkBindImageMemory(device, m_vkImage, m_vkImageMemory, 0); if ( res != VK_SUCCESS ) return false; if ( bFlippable == true ) { // We assume we own the memory when doing this right now. // We could support the import scenario as well if needed assert( bTextureable == false ); m_DMA.modifier = DRM_FORMAT_MOD_INVALID; m_DMA.n_planes = 1; m_DMA.width = width; m_DMA.height = height; m_DMA.format = VulkanFormatToDRM( format ); const VkMemoryGetFdInfoKHR memory_get_fd_info = { .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, .pNext = NULL, .memory = m_vkImageMemory, .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, }; res = dyn_vkGetMemoryFdKHR(device, &memory_get_fd_info, &m_DMA.fd[0]); if ( res != VK_SUCCESS ) return false; const VkImageSubresource image_subresource = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, .arrayLayer = 0, }; VkSubresourceLayout image_layout; vkGetImageSubresourceLayout(device, m_vkImage, &image_subresource, &image_layout); m_DMA.stride[0] = image_layout.rowPitch; m_FBID = drm_fbid_from_dmabuf( &g_DRM, &m_DMA ); if ( m_FBID == 0 ) return false; } VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = m_vkImage; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.format = format; createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; createInfo.subresourceRange.baseMipLevel = 0; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; res = vkCreateImageView(device, &createInfo, nullptr, &m_vkImageView); if ( res != VK_SUCCESS ) return false; m_bInitialized = true; m_bFlippable = bFlippable; return true; } int init_device() { uint32_t physicalDeviceCount; VkPhysicalDevice deviceHandles[MAX_DEVICE_COUNT]; VkQueueFamilyProperties queueFamilyProperties[MAX_QUEUE_COUNT]; vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, 0); physicalDeviceCount = physicalDeviceCount > MAX_DEVICE_COUNT ? MAX_DEVICE_COUNT : physicalDeviceCount; vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, deviceHandles); for (uint32_t i = 0; i < physicalDeviceCount; ++i) { uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(deviceHandles[i], &queueFamilyCount, NULL); queueFamilyCount = queueFamilyCount > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : queueFamilyCount; vkGetPhysicalDeviceQueueFamilyProperties(deviceHandles[i], &queueFamilyCount, queueFamilyProperties); for (uint32_t j = 0; j < queueFamilyCount; ++j) { if ( queueFamilyProperties[j].queueFlags & VK_QUEUE_COMPUTE_BIT && !(queueFamilyProperties[j].queueFlags & VK_QUEUE_GRAPHICS_BIT ) ) { queueFamilyIndex = j; physicalDevice = deviceHandles[i]; } } if (physicalDevice) { break; } } vkGetPhysicalDeviceMemoryProperties( physicalDevice, &memoryProperties ); float queuePriorities = 1.0f; VkDeviceQueueCreateInfo queueCreateInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = queueFamilyIndex, .queueCount = 1, .pQueuePriorities = &queuePriorities }; std::vector< const char * > vecEnabledDeviceExtensions; if ( BIsNested() == true ) { vecEnabledDeviceExtensions.push_back( VK_KHR_SWAPCHAIN_EXTENSION_NAME ); } vecEnabledDeviceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME ); vecEnabledDeviceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME ); VkDeviceCreateInfo deviceCreateInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queueCreateInfo, .enabledLayerCount = 0, .ppEnabledLayerNames = 0, .enabledExtensionCount = (uint32_t)vecEnabledDeviceExtensions.size(), .ppEnabledExtensionNames = vecEnabledDeviceExtensions.data(), .pEnabledFeatures = 0, }; VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, NULL, &device); if ( result != VK_SUCCESS ) { return false; } vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); if ( queue == VK_NULL_HANDLE ) return false; VkShaderModuleCreateInfo shaderModuleCreateInfo = {}; shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shaderModuleCreateInfo.codeSize = composite_spv_len; shaderModuleCreateInfo.pCode = (const uint32_t*)composite_spv; VkResult res = vkCreateShaderModule( device, &shaderModuleCreateInfo, nullptr, &shaderModule ); if ( res != VK_SUCCESS ) { return false; } VkCommandPoolCreateInfo commandPoolCreateInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = nullptr, .flags = 0, .queueFamilyIndex = queueFamilyIndex, }; res = vkCreateCommandPool(device, &commandPoolCreateInfo, 0, &commandPool); if ( res != VK_SUCCESS ) { return false; } // probably hard to hit that even with 3 overlays, and a bunch of tracked windows // famous last words //#define k_nMaxSets 20 #define k_nMaxSets 2000 // don't have time to cache or free stuff VkDescriptorPoolSize descriptorPoolSize[] = { { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, k_nMaxSets * 1, }, { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, k_nMaxSets * k_nMaxLayers, }, { VK_DESCRIPTOR_TYPE_SAMPLER, k_nMaxSets * k_nMaxLayers, }, }; VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, nullptr, .flags = 0, .maxSets = k_nMaxSets, .poolSizeCount = 3, descriptorPoolSize }; res = vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, 0, &descriptorPool); if ( res != VK_SUCCESS ) { return false; } return true; } void fini_device() { vkDestroyDevice(device, 0); } void acquire_next_image( void ) { vkAcquireNextImageKHR( device, swapChain, UINT64_MAX, VK_NULL_HANDLE, VK_NULL_HANDLE, &g_nSwapChainImageIndex ); } void vulkan_present_to_window( void ) { VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; // presentInfo.waitSemaphoreCount = 1; // presentInfo.pWaitSemaphores = signalSemaphores; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &swapChain; presentInfo.pImageIndices = &g_nSwapChainImageIndex; vkQueuePresentKHR( queue, &presentInfo ); acquire_next_image(); } int vulkan_init(void) { VkResult result = VK_ERROR_INITIALIZATION_FAILED; std::vector< const char * > vecEnabledInstanceExtensions; vecEnabledInstanceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME ); vecEnabledInstanceExtensions.insert( vecEnabledInstanceExtensions.end(), g_vecSDLInstanceExts.begin(), g_vecSDLInstanceExts.end() ); const VkInstanceCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &appInfo, .enabledExtensionCount = (uint32_t)vecEnabledInstanceExtensions.size(), .ppEnabledExtensionNames = vecEnabledInstanceExtensions.data(), }; result = vkCreateInstance(&createInfo, 0, &instance); if ( result != VK_SUCCESS ) return 0; if ( init_device() != 1 ) { return 0; } if ( BIsNested() == true ) { SDL_Vulkan_CreateSurface( window, instance, &surface ); if ( surface == VK_NULL_HANDLE ) return 0; result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( physicalDevice, surface, &surfaceCaps ); if ( result != VK_SUCCESS ) return 0; uint32_t formatCount = 0; result = vkGetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, surface, &formatCount, nullptr ); if ( result != VK_SUCCESS ) return 0; if ( formatCount != 0 ) { surfaceFormats.resize( formatCount ); vkGetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, surface, &formatCount, surfaceFormats.data() ); if ( result != VK_SUCCESS ) return 0; } uint32_t presentModeCount = 0; result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr ); if ( result != VK_SUCCESS ) return 0; if ( presentModeCount != 0 ) { presentModes.resize(presentModeCount); result = vkGetPhysicalDeviceSurfacePresentModesKHR( physicalDevice, surface, &presentModeCount, presentModes.data() ); if ( result != VK_SUCCESS ) return 0; } uint32_t imageCount = surfaceCaps.minImageCount + 1; VkSwapchainCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.surface = surface; createInfo.minImageCount = imageCount; createInfo.imageFormat = surfaceFormats[0].format; createInfo.imageColorSpace = surfaceFormats[0].colorSpace; createInfo.imageExtent = { g_nOutputWidth, g_nOutputHeight }; createInfo.imageArrayLayers = 1; createInfo.imageUsage = VK_IMAGE_USAGE_STORAGE_BIT; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.preTransform = surfaceCaps.currentTransform; createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.presentMode = presentModes[0]; createInfo.clipped = VK_TRUE; createInfo.oldSwapchain = VK_NULL_HANDLE; if (vkCreateSwapchainKHR( device, &createInfo, nullptr, &swapChain) != VK_SUCCESS ) { return 0; } vkGetSwapchainImagesKHR( device, swapChain, &imageCount, nullptr ); swapChainImages.resize( imageCount ); swapChainImageViews.resize( imageCount ); vkGetSwapchainImagesKHR( device, swapChain, &imageCount, swapChainImages.data() ); for ( uint32_t i = 0; i < swapChainImages.size(); i++ ) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[ i ]; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.format = surfaceFormats[ 0 ].format; createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; createInfo.subresourceRange.baseMipLevel = 0; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; result = vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[ i ]); if ( result != VK_SUCCESS ) return false; } acquire_next_image(); } dyn_vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr( device, "vkGetMemoryFdKHR" ); if ( dyn_vkGetMemoryFdKHR == nullptr ) return 0; if ( BIsNested() == false ) { VkFormat imageFormat = DRMFormatToVulkan( g_nDRMFormat ); if ( imageFormat == VK_FORMAT_UNDEFINED ) { return 0; } bool bSuccess = outputImage[0].BInit( g_nOutputWidth, g_nOutputHeight, imageFormat, true, false ); if ( bSuccess != true ) return 0; bSuccess = outputImage[1].BInit( g_nOutputWidth, g_nOutputHeight, imageFormat, true, false ); if ( bSuccess != true ) return 0; } return 1; } VulkanTexture_t vulkan_create_texture_from_dmabuf( struct wlr_dmabuf_attributes *pDMA ) { VulkanTexture_t ret = 0; CVulkanTexture *pTex = new CVulkanTexture(); if ( pTex->BInit( pDMA->width, pDMA->height, DRMFormatToVulkan( pDMA->format ), false, true, pDMA ) == false ) { delete pTex; return ret; } ret = ++g_nMaxVulkanTexHandle; g_mapVulkanTextures[ ret ] = pTex; return ret; } void vulkan_free_texture( VulkanTexture_t vulkanTex ) { if ( vulkanTex == 0 ) return; assert( g_mapVulkanTextures[ vulkanTex ] != nullptr ); // actually free something at some point } bool vulkan_composite( struct VulkanPipeline_t *pPipeline ) { CVulkanTexture *pTex[ k_nMaxLayers ] = {}; uint32_t nTexCount = 0; for ( uint32_t i = 0; i < k_nMaxLayers; i ++ ) { if ( pPipeline->layerBindings[ i ].tex != 0 ) { pTex[ i ] = g_mapVulkanTextures[ pPipeline->layerBindings[ i ].tex ]; assert( pTex[ i ] ); nTexCount++; } } std::vector< VkDescriptorSetLayoutBinding > vecLayoutBindings; VkDescriptorSetLayoutBinding descriptorSetLayoutBindings = { .binding = 0, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, }; vecLayoutBindings.push_back( descriptorSetLayoutBindings ); // first binding is target storage image for ( uint32_t i = 0; i < nTexCount; i++ ) { descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; descriptorSetLayoutBindings.binding = 1 + ( i * 2 ); vecLayoutBindings.push_back( descriptorSetLayoutBindings ); descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptorSetLayoutBindings.binding = 1 + ( i * 2 ) + 1; vecLayoutBindings.push_back( descriptorSetLayoutBindings ); } VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .bindingCount = 1 + ( nTexCount * 2 ), vecLayoutBindings.data() }; VkDescriptorSetLayout descriptorSetLayout; VkResult res = vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, 0, &descriptorSetLayout); if ( res != VK_SUCCESS ) { return false; } VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, 1, &descriptorSetLayout, 0, 0 }; VkPipelineLayout pipelineLayout; res = vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, 0, &pipelineLayout); if ( res != VK_SUCCESS ) { return false; } VkComputePipelineCreateInfo computePipelineCreateInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 0, 0, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, VK_SHADER_STAGE_COMPUTE_BIT, shaderModule, "main", 0 }, pipelineLayout, 0, 0 }; VkPipeline pipeline; res = vkCreateComputePipelines(device, 0, 1, &computePipelineCreateInfo, 0, &pipeline); if ( res != VK_SUCCESS ) { return false; } VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, nullptr, descriptorPool, 1, &descriptorSetLayout }; VkDescriptorSet descriptorSet = VK_NULL_HANDLE; res = vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet); if ( res != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE ) { return false; } { VkDescriptorImageInfo imageInfo = { .imageView = BIsNested() ? swapChainImageViews[ g_nSwapChainImageIndex ] : outputImage[ g_nOutImage ].m_vkImageView, .imageLayout = VK_IMAGE_LAYOUT_GENERAL }; VkWriteDescriptorSet writeDescriptorSet = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = descriptorSet, .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .pImageInfo = &imageInfo, .pBufferInfo = nullptr, .pTexelBufferView = nullptr, }; vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } for ( uint32_t i = 0; i < nTexCount; i++ ) { VkSampler sampler = VK_NULL_HANDLE; VkSamplerCreateInfo samplerCreateInfo = { .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .pNext = nullptr, .magFilter = pPipeline->layerBindings[ i ].bFilter ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, .minFilter = pPipeline->layerBindings[ i ].bFilter ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, .unnormalizedCoordinates = VK_TRUE, }; res = vkCreateSampler( device, &samplerCreateInfo, nullptr, &sampler ); if ( res != VK_SUCCESS ) { return false; } { VkDescriptorImageInfo imageInfo = { .imageView = pTex[ i ]->m_vkImageView, // TODO figure out what it is exactly for the wayland surfaces .imageLayout = VK_IMAGE_LAYOUT_GENERAL, }; VkWriteDescriptorSet writeDescriptorSet = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = descriptorSet, .dstBinding = 1 + (i * 2), .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, .pImageInfo = &imageInfo, .pBufferInfo = nullptr, .pTexelBufferView = nullptr, }; vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } { VkDescriptorImageInfo imageInfo = { .sampler = sampler, }; VkWriteDescriptorSet writeDescriptorSet = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = descriptorSet, .dstBinding = 1 + (i * 2) + 1, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, .pImageInfo = &imageInfo, .pBufferInfo = nullptr, .pTexelBufferView = nullptr, }; vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } } VkCommandBufferAllocateInfo commandBufferAllocateInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 }; VkCommandBuffer commandBuffer; res = vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, &commandBuffer); if ( res != VK_SUCCESS ) { return false; } VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0 }; res = vkBeginCommandBuffer(commandBuffer, &commandBufferBeginInfo); if ( res != VK_SUCCESS ) { return false; } vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, &descriptorSet, 0, 0); vkCmdDispatch(commandBuffer, g_nOutputWidth / 16, g_nOutputHeight / 16, 1); res = vkEndCommandBuffer(commandBuffer); if ( res != VK_SUCCESS ) { return false; } VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 0, 0, 0, 1, &commandBuffer, 0, 0 }; res = vkQueueSubmit(queue, 1, &submitInfo, 0); if ( res != VK_SUCCESS ) { return false; } vkQueueWaitIdle( queue ); g_nOutImage = !g_nOutImage; return true; } uint32_t vulkan_get_last_composite_fbid( void ) { return outputImage[ !g_nOutImage ].m_FBID; }