From 56fb91ea725c86d5f3556f50ceac2268d84f2f48 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Mon, 27 Dec 2021 19:14:25 +0100 Subject: [PATCH] rendervulkan: Use drmformats everywhere, create srgb and linear image views --- src/rendervulkan.cpp | 117 ++++++++++++++++++++++++++++++------------- src/rendervulkan.hpp | 7 +-- src/steamcompmgr.cpp | 2 +- 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp index d4c058b..6badecb 100644 --- a/src/rendervulkan.cpp +++ b/src/rendervulkan.cpp @@ -155,6 +155,17 @@ static void vk_errorf(VkResult result, const char *fmt, ...) { vk_log.errorf("%s (VkResult: %d)", buf, result); } +template +Target *pNextFind(const Base *base, VkStructureType sType) +{ + for ( ; base; base = (const Base *)base->pNext ) + { + if (base->sType == sType) + return (Target *) base; + } + return nullptr; +} + #define MAX_DEVICE_COUNT 8 #define MAX_QUEUE_COUNT 8 @@ -275,6 +286,7 @@ static VkResult getModifierProps( const VkImageCreateInfo *imageInfo, uint64_t m VkPhysicalDeviceImageDrmFormatModifierInfoEXT modifierFormatInfo = {}; VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {}; VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {}; + VkImageFormatListCreateInfo formatList = {}; VkImageFormatProperties2 imageProps = {}; modifierFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT; @@ -293,13 +305,20 @@ static VkResult getModifierProps( const VkImageCreateInfo *imageInfo, uint64_t m imageFormatInfo.usage = imageInfo->usage; imageFormatInfo.flags = imageInfo->flags; + const VkImageFormatListCreateInfo *readonlyList = pNextFind(imageInfo, VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO); + if ( readonlyList != nullptr ) + { + formatList = *readonlyList; + formatList.pNext = std::exchange(imageFormatInfo.pNext, &formatList); + } + imageProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; imageProps.pNext = externalFormatProps; return vkGetPhysicalDeviceImageFormatProperties2(physicalDevice, &imageFormatInfo, &imageProps); } -bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, createFlags flags, wlr_dmabuf_attributes *pDMA /* = nullptr */ ) +bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA /* = nullptr */ ) { VkResult res = VK_ERROR_INITIALIZATION_FAILED; @@ -351,16 +370,32 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr imageInfo.extent.depth = 1; imageInfo.mipLevels = 1; imageInfo.arrayLayers = 1; - imageInfo.format = format; + imageInfo.format = DRMFormatToVulkan(drmFormat, false); 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; + assert( imageInfo.format != VK_FORMAT_UNDEFINED ); + + std::array formats = { + DRMFormatToVulkan(drmFormat, false), + DRMFormatToVulkan(drmFormat, true), + }; + VkImageFormatListCreateInfo formatList = {}; + formatList.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO; + formatList.viewFormatCount = (uint32_t)formats.size(); + formatList.pViewFormats = formats.data(); + if ( formats[0] != formats[1] ) + { + formatList.pNext = std::exchange(imageInfo.pNext, &formatList); + imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + } + if ( pDMA != nullptr ) { - assert( format == DRMFormatToVulkan( pDMA->format, true ) || format == DRMFormatToVulkan( pDMA->format, false ) ); + assert( drmFormat == pDMA->format ); } if ( g_vulkanSupportsModifiers && pDMA && pDMA->modifier != DRM_FORMAT_MOD_INVALID ) @@ -377,7 +412,7 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr ( externalImageProperties.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT ) ) { modifierInfo.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT; - modifierInfo.pNext = imageInfo.pNext; + modifierInfo.pNext = std::exchange(imageInfo.pNext, &modifierInfo); modifierInfo.drmFormatModifier = pDMA->modifier; modifierInfo.drmFormatModifierPlaneCount = pDMA->n_planes; modifierInfo.pPlaneLayouts = modifierPlaneLayouts; @@ -388,8 +423,6 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr modifierPlaneLayouts[i].rowPitch = pDMA->stride[i]; } - imageInfo.pNext = &modifierInfo; - imageInfo.tiling = tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; } } @@ -397,7 +430,6 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr std::vector modifiers = {}; if ( flags.bFlippable == true && g_vulkanSupportsModifiers && !pDMA ) { - uint32_t drmFormat = VulkanFormatToDRM( format ); assert( drmFormat != DRM_FORMAT_INVALID ); uint64_t linear = DRM_FORMAT_MOD_LINEAR; @@ -440,12 +472,10 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr assert( modifiers.size() > 0 ); modifierListInfo.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT; - modifierListInfo.pNext = imageInfo.pNext; + modifierListInfo.pNext = std::exchange(imageInfo.pNext, &modifierListInfo); modifierListInfo.pDrmFormatModifiers = modifiers.data(); modifierListInfo.drmFormatModifierCount = modifiers.size(); - imageInfo.pNext = &modifierListInfo; - imageInfo.tiling = tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; } @@ -454,18 +484,14 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr // We want to scan-out the image wsiImageCreateInfo.sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA; wsiImageCreateInfo.scanout = VK_TRUE; - wsiImageCreateInfo.pNext = imageInfo.pNext; - - imageInfo.pNext = &wsiImageCreateInfo; + wsiImageCreateInfo.pNext = std::exchange(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; + externalImageCreateInfo.pNext = std::exchange(imageInfo.pNext, &externalImageCreateInfo); } m_width = width; @@ -581,7 +607,7 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr struct wlr_dmabuf_attributes dmabuf = {}; dmabuf.width = width; dmabuf.height = height; - dmabuf.format = VulkanFormatToDRM( format ); + dmabuf.format = drmFormat; assert( dmabuf.format != DRM_FORMAT_INVALID ); // TODO: disjoint planes support @@ -609,10 +635,10 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr } dmabuf.modifier = imgModifierProps.drmFormatModifier; - assert( DRMModifierProps.count( format ) > 0); - assert( DRMModifierProps[ format ].count( dmabuf.modifier ) > 0); + assert( DRMModifierProps.count( m_format ) > 0); + assert( DRMModifierProps[ m_format ].count( dmabuf.modifier ) > 0); - dmabuf.n_planes = DRMModifierProps[ format ][ dmabuf.modifier ].drmFormatModifierPlaneCount; + dmabuf.n_planes = DRMModifierProps[ m_format ][ dmabuf.modifier ].drmFormatModifierPlaneCount; const VkImageAspectFlagBits planeAspects[] = { VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT, @@ -684,7 +710,7 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = m_vkImage; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = format; + createInfo.format = DRMFormatToVulkan(drmFormat, false);; createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; @@ -695,12 +721,25 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, VkFormat format, cr createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; - res = vkCreateImageView(device, &createInfo, nullptr, &m_vkImageView); + res = vkCreateImageView(device, &createInfo, nullptr, &m_srgbView); if ( res != VK_SUCCESS ) { vk_errorf( res, "vkCreateImageView failed" ); return false; } + if ( flags.bSampled ) + { + VkImageViewUsageCreateInfo viewUsageInfo = {}; + viewUsageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; + viewUsageInfo.usage = usage & ~VK_IMAGE_USAGE_STORAGE_BIT; + createInfo.pNext = &viewUsageInfo; + createInfo.format = DRMFormatToVulkan(drmFormat, true); + res = vkCreateImageView(device, &createInfo, nullptr, &m_linearView); + if ( res != VK_SUCCESS ) { + vk_errorf( res, "vkCreateImageView failed" ); + return false; + } + } } if ( flags.bMappable ) @@ -730,10 +769,16 @@ CVulkanTexture::~CVulkanTexture( void ) m_pMappedData = nullptr; } - if ( m_vkImageView != VK_NULL_HANDLE ) + if ( m_srgbView != VK_NULL_HANDLE ) { - vkDestroyImageView( device, m_vkImageView, nullptr ); - m_vkImageView = VK_NULL_HANDLE; + vkDestroyImageView( device, m_srgbView, nullptr ); + m_srgbView = VK_NULL_HANDLE; + } + + if ( m_linearView != VK_NULL_HANDLE ) + { + vkDestroyImageView( device, m_linearView, nullptr ); + m_linearView = VK_NULL_HANDLE; } if ( m_FBID != 0 ) @@ -1186,12 +1231,13 @@ retry: if ( g_vulkanSupportsModifiers ) { vecEnabledDeviceExtensions.push_back( VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME ); - vecEnabledDeviceExtensions.push_back( VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME ); // Required. if ( !BIsNested() ) vecEnabledDeviceExtensions.push_back( VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME ); } + vecEnabledDeviceExtensions.push_back( VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME ); + vecEnabledDeviceExtensions.push_back( VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME ); vecEnabledDeviceExtensions.push_back( VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME ); @@ -1648,7 +1694,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) pOutput->outputImage[1] = nullptr; pOutput->outputImage[0] = std::make_shared(); - bool bSuccess = pOutput->outputImage[0]->BInit( g_nOutputWidth, g_nOutputHeight, pOutput->outputFormat, outputImageflags ); + bool bSuccess = pOutput->outputImage[0]->BInit( g_nOutputWidth, g_nOutputHeight, VulkanFormatToDRM(pOutput->outputFormat), outputImageflags ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -1656,7 +1702,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) } pOutput->outputImage[1] = std::make_shared(); - bSuccess = pOutput->outputImage[1]->BInit( g_nOutputWidth, g_nOutputHeight, pOutput->outputFormat, outputImageflags ); + bSuccess = pOutput->outputImage[1]->BInit( g_nOutputWidth, g_nOutputHeight, VulkanFormatToDRM(pOutput->outputFormat), outputImageflags ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -1932,20 +1978,20 @@ std::shared_ptr vulkan_create_texture_from_dmabuf( struct wlr_dm CVulkanTexture::createFlags texCreateFlags; texCreateFlags.bSampled = true; - if ( pTex->BInit( pDMA->width, pDMA->height, DRMFormatToVulkan( pDMA->format, true ), texCreateFlags, pDMA ) == false ) + if ( pTex->BInit( pDMA->width, pDMA->height, pDMA->format, texCreateFlags, pDMA ) == false ) return nullptr; return pTex; } -std::shared_ptr vulkan_create_texture_from_bits( uint32_t width, uint32_t height, VkFormat format, CVulkanTexture::createFlags texCreateFlags, void *bits ) +std::shared_ptr vulkan_create_texture_from_bits( uint32_t width, uint32_t height, uint32_t drmFormat, CVulkanTexture::createFlags texCreateFlags, void *bits ) { std::shared_ptr pTex = std::make_shared(); texCreateFlags.bSampled = true; texCreateFlags.bTransferDst = true; - if ( pTex->BInit( width, height, format, texCreateFlags ) == false ) + if ( pTex->BInit( width, height, drmFormat, texCreateFlags ) == false ) return nullptr; memcpy( pUploadBuffer, bits, width * height * 4 ); @@ -2050,7 +2096,7 @@ void vulkan_update_descriptor( struct Composite_t *pComposite, struct VulkanPipe } else { - targetImageView = g_output.outputImage[ g_output.nOutImage ]->m_vkImageView; + targetImageView = g_output.outputImage[ g_output.nOutImage ]->m_srgbView; } VkDescriptorImageInfo imageInfo = { @@ -2083,7 +2129,7 @@ void vulkan_update_descriptor( struct Composite_t *pComposite, struct VulkanPipe float_is_integer(pComposite->data.vOffset[i].y); VkImageView imageView = pPipeline->layerBindings[ i ].tex - ? pPipeline->layerBindings[ i ].tex->m_vkImageView + ? pPipeline->layerBindings[ i ].tex->m_linearView : VK_NULL_HANDLE; VulkanSamplerCacheKey_t samplerKey; @@ -2287,7 +2333,7 @@ bool vulkan_composite( struct Composite_t *pComposite, struct VulkanPipeline_t * screenshotImageFlags.bMappable = true; screenshotImageFlags.bTransferDst = true; - bool bSuccess = pScreenshotImage->BInit( currentOutputWidth, currentOutputHeight, g_output.outputFormat, screenshotImageFlags ); + bool bSuccess = pScreenshotImage->BInit( currentOutputWidth, currentOutputHeight, VulkanFormatToDRM(g_output.outputFormat), screenshotImageFlags ); assert( bSuccess ); @@ -2580,7 +2626,6 @@ std::shared_ptr vulkan_create_texture_from_wlr_buffer( struct wl return 0; } - VkFormat format = DRMFormatToVulkan( drmFormat, true ); uint32_t width = buf->width; uint32_t height = buf->height; @@ -2644,7 +2689,7 @@ std::shared_ptr vulkan_create_texture_from_wlr_buffer( struct wl CVulkanTexture::createFlags texCreateFlags = {}; texCreateFlags.bSampled = true; texCreateFlags.bTransferDst = true; - if ( pTex->BInit( width, height, format, texCreateFlags ) == false ) + if ( pTex->BInit( width, height, drmFormat, texCreateFlags ) == false ) return nullptr; VkCommandBuffer commandBuffer; diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp index 1b9fa7a..78b4556 100644 --- a/src/rendervulkan.hpp +++ b/src/rendervulkan.hpp @@ -119,7 +119,7 @@ public: bool bLinear : 1; }; - bool BInit( uint32_t width, uint32_t height, VkFormat format, createFlags flags, wlr_dmabuf_attributes *pDMA = nullptr ); + bool BInit( uint32_t width, uint32_t height, uint32_t drmFormat, createFlags flags, wlr_dmabuf_attributes *pDMA = nullptr ); CVulkanTexture( void ); ~CVulkanTexture( void ); @@ -129,7 +129,8 @@ public: VkImage m_vkImage = VK_NULL_HANDLE; VkDeviceMemory m_vkImageMemory = VK_NULL_HANDLE; - VkImageView m_vkImageView = VK_NULL_HANDLE; + VkImageView m_srgbView = VK_NULL_HANDLE; + VkImageView m_linearView = VK_NULL_HANDLE; uint32_t m_width = 0, m_height = 0; uint32_t m_unRowPitch = 0; @@ -153,7 +154,7 @@ bool vulkan_init_formats(void); bool vulkan_make_output(void); std::shared_ptr vulkan_create_texture_from_dmabuf( struct wlr_dmabuf_attributes *pDMA ); -std::shared_ptr vulkan_create_texture_from_bits( uint32_t width, uint32_t height, VkFormat format, CVulkanTexture::createFlags texCreateFlags, void *bits ); +std::shared_ptr vulkan_create_texture_from_bits( uint32_t width, uint32_t height, uint32_t drmFormat, CVulkanTexture::createFlags texCreateFlags, void *bits ); std::shared_ptr vulkan_create_texture_from_wlr_buffer( struct wlr_buffer *buf ); uint32_t vulkan_texture_get_fbid( const std::shared_ptr& vulkanTex ); diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index c6daa64..de07d76 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -1089,7 +1089,7 @@ bool MouseCursor::getTexture() // TODO: choose format & modifiers from cursor plane } - m_texture = vulkan_create_texture_from_bits(m_width, m_height, VK_FORMAT_B8G8R8A8_SRGB, texCreateFlags, cursorBuffer.data()); + m_texture = vulkan_create_texture_from_bits(m_width, m_height, DRM_FORMAT_ARGB8888, texCreateFlags, cursorBuffer.data()); assert(m_texture); XFree(image); m_dirty = false;