From cf9b8231bd0979b564b746a4cf11d18f568d9f60 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 15 Dec 2023 08:28:29 +0100 Subject: [PATCH] gpu: Update to memoryformat Vulkan code The existing code for setting up formats was copied from the old Vulkan renderer and never updated. --- gsk/gpu/gskvulkanimage.c | 780 ++++++++++++--------------------------- 1 file changed, 237 insertions(+), 543 deletions(-) diff --git a/gsk/gpu/gskvulkanimage.c b/gsk/gpu/gskvulkanimage.c index 18f350b5d3..c58b6c570c 100644 --- a/gsk/gpu/gskvulkanimage.c +++ b/gsk/gpu/gskvulkanimage.c @@ -44,414 +44,18 @@ struct _GskVulkanImage G_DEFINE_TYPE (GskVulkanImage, gsk_vulkan_image, GSK_TYPE_GPU_IMAGE) -typedef struct _GskMemoryFormatInfo GskMemoryFormatInfo; - -struct _GskMemoryFormatInfo -{ - VkFormat format; - VkComponentMapping components; -}; - -static const GskMemoryFormatInfo * -gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format) -{ -#define SWIZZLE(a, b, c, d) { VK_COMPONENT_SWIZZLE_ ## a, VK_COMPONENT_SWIZZLE_ ## b, VK_COMPONENT_SWIZZLE_ ## c, VK_COMPONENT_SWIZZLE_ ## d } -#define DEFAULT_SWIZZLE SWIZZLE (R, G, B, A) - switch (format) - { - case GDK_MEMORY_A8B8G8R8_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(A, B, G, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_B8G8R8A8_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(B, G, R, A) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(G, B, A, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_B8G8R8A8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_B8G8R8A8_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(B, G, R, A) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_A8R8G8B8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(G, B, A, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R8G8B8A8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_A8B8G8R8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(A, B, G, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_X8B8G8R8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(A, B, G, ONE) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - case GDK_MEMORY_B8G8R8X8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_B8G8R8A8_UNORM, SWIZZLE(R, G, B, ONE) }, - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(B, G, R, ONE) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_X8R8G8B8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(G, B, A, ONE) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R8G8B8X8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(R, G, B, ONE) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R8G8B8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8B8_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_B8G8R8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_B8G8R8_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_R8G8B8_UNORM, SWIZZLE(B, G, R, A) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R16G16B16: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16B16_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16B16A16_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R16G16B16A16: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16B16A16_UNORM, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R16G16B16_FLOAT: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16B16_SFLOAT, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16B16A16_SFLOAT, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R16G16B16A16_FLOAT: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16B16A16_SFLOAT, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R32G32B32_FLOAT: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R32G32B32_SFLOAT, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R32G32B32A32_SFLOAT, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_R32G32B32A32_FLOAT: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R32G32B32A32_SFLOAT, DEFAULT_SWIZZLE }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_G8A8_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8_UNORM, SWIZZLE (R, R, R, G) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_G8A8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8G8_UNORM, SWIZZLE (R, R, R, G) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_G8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, ONE) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_G16A16_PREMULTIPLIED: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16_UNORM, SWIZZLE (R, R, R, G) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_G16A16: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16G16_UNORM, SWIZZLE (R, R, R, G) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_G16: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, ONE) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_A8: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_A16: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_A16_FLOAT: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R16_SFLOAT, SWIZZLE (R, R, R, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_A32_FLOAT: - { - static const GskMemoryFormatInfo info[] = { - { VK_FORMAT_R32_SFLOAT, SWIZZLE (R, R, R, R) }, - { VK_FORMAT_UNDEFINED } - }; - return info; - } - - case GDK_MEMORY_N_FORMATS: - default: - g_assert_not_reached (); - return NULL; - } -#undef DEFAULT_SWIZZLE -#undef SWIZZLE -} - static gboolean -gsk_memory_format_info_is_framebuffer_compatible (const GskMemoryFormatInfo *format) +gsk_component_mapping_is_framebuffer_compatible (const VkComponentMapping *components) { - if (format->components.r != VK_COMPONENT_SWIZZLE_R || - format->components.g != VK_COMPONENT_SWIZZLE_G || - format->components.b != VK_COMPONENT_SWIZZLE_B || - format->components.a != VK_COMPONENT_SWIZZLE_A) + if (components->r != VK_COMPONENT_SWIZZLE_R || + components->g != VK_COMPONENT_SWIZZLE_G || + components->b != VK_COMPONENT_SWIZZLE_B || + components->a != VK_COMPONENT_SWIZZLE_A) return FALSE; return TRUE; } -static GdkMemoryFormat -gsk_memory_format_get_fallback (GdkMemoryFormat format) -{ - switch (format) - { - case GDK_MEMORY_A8B8G8R8_PREMULTIPLIED: - case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: - case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: - case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: - case GDK_MEMORY_B8G8R8A8: - case GDK_MEMORY_A8R8G8B8: - case GDK_MEMORY_R8G8B8A8: - case GDK_MEMORY_A8B8G8R8: - case GDK_MEMORY_R8G8B8: - return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - - case GDK_MEMORY_B8G8R8X8: - case GDK_MEMORY_X8R8G8B8: - case GDK_MEMORY_X8B8G8R8: - case GDK_MEMORY_R8G8B8X8: - case GDK_MEMORY_B8G8R8: - return GDK_MEMORY_R8G8B8; - - case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: - return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; - - case GDK_MEMORY_R16G16B16: - case GDK_MEMORY_R16G16B16A16: - return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; - - case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: - return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; - - case GDK_MEMORY_R16G16B16_FLOAT: - case GDK_MEMORY_R16G16B16A16_FLOAT: - return GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED; - - case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: - return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - - case GDK_MEMORY_R32G32B32_FLOAT: - case GDK_MEMORY_R32G32B32A32_FLOAT: - return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; - - case GDK_MEMORY_G8A8_PREMULTIPLIED: - case GDK_MEMORY_G8A8: - return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - - case GDK_MEMORY_G8: - return GDK_MEMORY_R8G8B8; - - case GDK_MEMORY_G16A16_PREMULTIPLIED: - case GDK_MEMORY_G16A16: - return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; - - case GDK_MEMORY_G16: - return GDK_MEMORY_R16G16B16; - - case GDK_MEMORY_A8: - return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - case GDK_MEMORY_A16: - return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; - case GDK_MEMORY_A16_FLOAT: - return GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED; - case GDK_MEMORY_A32_FLOAT: - return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; - - case GDK_MEMORY_N_FORMATS: - default: - return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - } -} - static gboolean gsk_vulkan_device_supports_format (GskVulkanDevice *device, VkFormat format, @@ -556,16 +160,17 @@ gsk_vulkan_device_supports_format (GskVulkanDevice *device, static void gsk_vulkan_image_create_view (GskVulkanImage *self, - VkSamplerYcbcrConversion vk_conversion, - const GskMemoryFormatInfo *format) + VkFormat vk_format, + const VkComponentMapping *vk_components, + VkSamplerYcbcrConversion vk_conversion) { GSK_VK_CHECK (vkCreateImageView, self->display->vk_device, &(VkImageViewCreateInfo) { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = self->vk_image, .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = format->format, - .components = format->components, + .format = vk_format, + .components = *vk_components, .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, @@ -582,6 +187,56 @@ gsk_vulkan_image_create_view (GskVulkanImage *self, &self->vk_image_view); } +static gboolean +gsk_vulkan_device_check_format (GskVulkanDevice *device, + VkFormat vk_format, + const VkComponentMapping *vk_components, + GskGpuImageFlags required_flags, + VkImageTiling vk_tiling, + VkImageUsageFlags vk_usage, + gsize width, + gsize height, + VkImageTiling *out_tiling, + GskGpuImageFlags *out_flags) +{ +#define CHECK_FLAGS (GSK_GPU_IMAGE_NO_BLIT | GSK_GPU_IMAGE_FILTERABLE | GSK_GPU_IMAGE_RENDERABLE) + GskGpuImageFlags flags; + + if (vk_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT && + !gsk_component_mapping_is_framebuffer_compatible (vk_components)) + return FALSE; + + if (gsk_vulkan_device_supports_format (device, + vk_format, + 0, 1, + vk_tiling, vk_usage, + width, height, + &flags) && + ((flags & required_flags & CHECK_FLAGS) == (required_flags & CHECK_FLAGS))) + { + *out_tiling = vk_tiling; + *out_flags = flags; + return TRUE; + } + + if (vk_tiling == VK_IMAGE_TILING_LINEAR && + gsk_vulkan_device_supports_format (device, + vk_format, + 0, 1, + VK_IMAGE_TILING_OPTIMAL, vk_usage, + width, height, + &flags) && + ((flags & required_flags & CHECK_FLAGS) == (required_flags & CHECK_FLAGS))) + { + *out_tiling = VK_IMAGE_TILING_OPTIMAL; + *out_flags = flags; + return TRUE; + } + + return FALSE; +#undef CHECK_FLAGS +} + static GskVulkanImage * gsk_vulkan_image_new (GskVulkanDevice *device, GdkMemoryFormat format, @@ -598,51 +253,48 @@ gsk_vulkan_image_new (GskVulkanDevice *device, VkMemoryRequirements requirements; GskVulkanImage *self; VkDevice vk_device; - const GskMemoryFormatInfo *vk_format; GskGpuImageFlags flags; -#define CHECK_FLAGS (GSK_GPU_IMAGE_NO_BLIT | GSK_GPU_IMAGE_FILTERABLE | GSK_GPU_IMAGE_RENDERABLE) + VkFormat vk_format; + VkComponentMapping vk_components; g_assert (width > 0 && height > 0); - while (TRUE) + /* First, try the actual format */ + vk_format = gdk_memory_format_vk_format (format, &vk_components); + if (vk_format == VK_FORMAT_UNDEFINED || + !gsk_vulkan_device_check_format (device, vk_format, &vk_components, required_flags, + tiling, usage, width, height, + &tiling, &flags)) { - for (vk_format = gsk_memory_format_get_vk_format_infos (format); - vk_format->format != VK_FORMAT_UNDEFINED; - vk_format++) + /* Second, try the potential RGBA format */ + vk_format = gdk_memory_format_vk_rgba_format (format, NULL, &vk_components); + if (vk_format == VK_FORMAT_UNDEFINED || + !gsk_vulkan_device_check_format (device, vk_format, &vk_components, required_flags, + tiling, usage, width, height, + &tiling, &flags)) { - if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT && - !gsk_memory_format_info_is_framebuffer_compatible (vk_format)) - continue; + const GdkMemoryFormat *fallbacks; + gsize i; - if (gsk_vulkan_device_supports_format (device, - vk_format->format, - 0, 1, - tiling, usage, - width, height, - &flags) && - ((flags & required_flags & CHECK_FLAGS) == (required_flags & CHECK_FLAGS))) - break; - - if (tiling == VK_IMAGE_TILING_LINEAR && - gsk_vulkan_device_supports_format (device, - vk_format->format, - 0, 1, - VK_IMAGE_TILING_OPTIMAL, usage, - width, height, - &flags) && - ((flags & required_flags & CHECK_FLAGS) == (required_flags & CHECK_FLAGS))) + /* Next, try the fallbacks */ + fallbacks = gdk_memory_format_get_fallbacks (format); + for (i = 0; fallbacks[i] != -1; i++) { - tiling = VK_IMAGE_TILING_OPTIMAL; - break; + vk_format = gdk_memory_format_vk_format (fallbacks[i], &vk_components); + if (vk_format != VK_FORMAT_UNDEFINED && + gsk_vulkan_device_check_format (device, vk_format, &vk_components, required_flags, + tiling, usage, width, height, + &tiling, &flags)) + { + format = fallbacks[i]; + break; + } } + + /* No format found. Likely, the width/height are too big */ + if (fallbacks[i] == -1) + return NULL; } - if (vk_format->format != VK_FORMAT_UNDEFINED) - break; - - if (format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) - return NULL; - - format = gsk_memory_format_get_fallback (format); } if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT) @@ -659,7 +311,7 @@ gsk_vulkan_image_new (GskVulkanDevice *device, self->display = g_object_ref (gsk_gpu_device_get_display (GSK_GPU_DEVICE (device))); gdk_display_ref_vulkan (self->display); - self->vk_format = vk_format->format; + self->vk_format = vk_format; self->vk_tiling = tiling; self->vk_usage = usage; self->vk_pipeline_stage = stage; @@ -673,7 +325,7 @@ gsk_vulkan_image_new (GskVulkanDevice *device, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .flags = 0, .imageType = VK_IMAGE_TYPE_2D, - .format = vk_format->format, + .format = vk_format, .extent = { width, height, 1 }, .mipLevels = (flags & GSK_GPU_IMAGE_CAN_MIPMAP) ? gsk_vulkan_mipmap_levels (width, height) : 1, .arrayLayers = 1, @@ -705,10 +357,9 @@ gsk_vulkan_image_new (GskVulkanDevice *device, self->allocation.vk_memory, self->allocation.offset); - gsk_vulkan_image_create_view (self, VK_NULL_HANDLE, vk_format); + gsk_vulkan_image_create_view (self, vk_format, &vk_components, VK_NULL_HANDLE); return self; -#undef CHECK_FLAGS } GskGpuImage * @@ -802,15 +453,14 @@ gsk_vulkan_image_new_for_swapchain (GskVulkanDevice *device, gsk_gpu_image_setup (GSK_GPU_IMAGE (self), 0, GDK_MEMORY_DEFAULT, width, height); gsk_vulkan_image_create_view (self, - VK_NULL_HANDLE, - &(GskMemoryFormatInfo) { - format, - { VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_A - } - }); + format, + &(VkComponentMapping) { + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }, + VK_NULL_HANDLE); return GSK_GPU_IMAGE (self); } @@ -866,32 +516,26 @@ gsk_vulkan_image_new_for_offscreen (GskVulkanDevice *device, } #ifdef HAVE_DMABUF -GskGpuImage * -gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device, - GdkMemoryFormat format, - gsize width, - gsize height) +static gboolean +gsk_vulkan_device_check_dmabuf_format (GskVulkanDevice *device, + VkFormat vk_format, + const VkComponentMapping *vk_components, + gsize width, + gsize height, + uint64_t modifiers[100], + GskGpuImageFlags *out_flags, + gsize *out_n_modifiers) + { + const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; VkDrmFormatModifierPropertiesEXT drm_mod_properties[100]; VkDrmFormatModifierPropertiesListEXT drm_properties; - uint64_t modifiers[100]; VkPhysicalDevice vk_phys_device; - VkDevice vk_device; VkFormatProperties2 properties; VkImageFormatProperties2 image_properties; - VkFormatFeatureFlags required; - const GskMemoryFormatInfo *format_info; - VkMemoryRequirements requirements; - GskVulkanImage *self; - VkResult res; - gsize i, n_modifiers; GskGpuImageFlags flags; - - if (!gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_DMABUF)) - return NULL; - - vk_phys_device = gsk_vulkan_device_get_vk_physical_device (device); - vk_device = gsk_vulkan_device_get_vk_device (device); + gsize i, n_modifiers; + VkResult res; drm_properties = (VkDrmFormatModifierPropertiesListEXT) { .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, @@ -903,77 +547,129 @@ gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device, .pNext = &drm_properties }; - required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; + if (!gsk_component_mapping_is_framebuffer_compatible (vk_components)) + return FALSE; - while (TRUE) + vk_phys_device = gsk_vulkan_device_get_vk_physical_device (device); + + vkGetPhysicalDeviceFormatProperties2 (vk_phys_device, + vk_format, + &properties); + + flags = GSK_GPU_IMAGE_FILTERABLE | GSK_GPU_IMAGE_RENDERABLE; + n_modifiers = 0; + for (i = 0; i < drm_properties.drmFormatModifierCount; i++) { - for (format_info = gsk_memory_format_get_vk_format_infos (format); - format_info != VK_FORMAT_UNDEFINED; - format_info++) + if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & required) != required) + continue; + + image_properties = (VkImageFormatProperties2) { + .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + }; + res = vkGetPhysicalDeviceImageFormatProperties2 (vk_phys_device, + &(VkPhysicalDeviceImageFormatInfo2) { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .format = vk_format, + .type = VK_IMAGE_TYPE_2D, + .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .flags = 0, + .pNext = &(VkPhysicalDeviceImageDrmFormatModifierInfoEXT) { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, + .drmFormatModifier = drm_mod_properties[i].drmFormatModifier, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 1, + .pQueueFamilyIndices = (uint32_t[1]) { gsk_vulkan_device_get_vk_queue_family_index (device) }, + } + }, + &image_properties); + if (res != VK_SUCCESS) + continue; + + if (image_properties.imageFormatProperties.maxExtent.width < width || + image_properties.imageFormatProperties.maxExtent.height < height) + continue; + + /* we could check the real used format after creation, but for now: */ + if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) == 0) + flags |= GSK_GPU_IMAGE_NO_BLIT; + if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) == 0) + flags &= ~GSK_GPU_IMAGE_FILTERABLE; + if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) == 0) + flags &= ~GSK_GPU_IMAGE_RENDERABLE; + + modifiers[n_modifiers++] = drm_mod_properties[i].drmFormatModifier; + } + + if (n_modifiers == 0) + return FALSE; + + *out_flags = flags; + *out_n_modifiers = n_modifiers; + return TRUE; +} + +GskGpuImage * +gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device, + GdkMemoryFormat format, + gsize width, + gsize height) +{ + uint64_t modifiers[100]; + VkDevice vk_device; + VkFormat vk_format; + VkComponentMapping vk_components; + VkMemoryRequirements requirements; + GskVulkanImage *self; + VkResult res; + gsize n_modifiers; + GskGpuImageFlags flags; + + if (!gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_DMABUF)) + return NULL; + + vk_device = gsk_vulkan_device_get_vk_device (device); + + /* First, try the actual format */ + vk_format = gdk_memory_format_vk_format (format, &vk_components); + if (vk_format == VK_FORMAT_UNDEFINED || + !gsk_vulkan_device_check_dmabuf_format (device, vk_format, &vk_components, width, height, + modifiers, &flags, &n_modifiers)) + { + /* Second, try the potential RGBA format, but as a fallback */ + GdkMemoryFormat rgba_format; + vk_format = gdk_memory_format_vk_rgba_format (format, &rgba_format, NULL); + if (vk_format != VK_FORMAT_UNDEFINED) + vk_format = gdk_memory_format_vk_format (rgba_format, &vk_components); + if (vk_format != VK_FORMAT_UNDEFINED && + gsk_vulkan_device_check_dmabuf_format (device, vk_format, &vk_components, width, height, + modifiers, &flags, &n_modifiers)) { - if (!gsk_memory_format_info_is_framebuffer_compatible (format_info)) - continue; + format = rgba_format; + } + else + { + const GdkMemoryFormat *fallbacks; + gsize i; - vkGetPhysicalDeviceFormatProperties2 (vk_phys_device, - format_info->format, - &properties); - - flags = GSK_GPU_IMAGE_FILTERABLE | GSK_GPU_IMAGE_RENDERABLE; - n_modifiers = 0; - for (i = 0; i < drm_properties.drmFormatModifierCount; i++) + /* Next, try the fallbacks */ + fallbacks = gdk_memory_format_get_fallbacks (format); + for (i = 0; fallbacks[i] != -1; i++) { - if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & required) != required) - continue; - - image_properties = (VkImageFormatProperties2) { - .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, - }; - res = vkGetPhysicalDeviceImageFormatProperties2 (vk_phys_device, - &(VkPhysicalDeviceImageFormatInfo2) { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - .format = format_info->format, - .type = VK_IMAGE_TYPE_2D, - .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, - .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - .flags = 0, - .pNext = &(VkPhysicalDeviceImageDrmFormatModifierInfoEXT) { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, - .drmFormatModifier = drm_mod_properties[i].drmFormatModifier, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 1, - .pQueueFamilyIndices = (uint32_t[1]) { gsk_vulkan_device_get_vk_queue_family_index (device) }, - } - }, - &image_properties); - if (res != VK_SUCCESS) - continue; - - if (image_properties.imageFormatProperties.maxExtent.width < width || - image_properties.imageFormatProperties.maxExtent.height < height) - continue; - - /* we could check the real used format after creation, but for now: */ - if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) == 0) - flags |= GSK_GPU_IMAGE_NO_BLIT; - if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) == 0) - flags &= ~GSK_GPU_IMAGE_FILTERABLE; - if ((drm_mod_properties[i].drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) == 0) - flags &= ~GSK_GPU_IMAGE_RENDERABLE; - - modifiers[n_modifiers++] = drm_mod_properties[i].drmFormatModifier; + vk_format = gdk_memory_format_vk_format (fallbacks[i], &vk_components); + if (vk_format != VK_FORMAT_UNDEFINED && + gsk_vulkan_device_check_dmabuf_format (device, vk_format, &vk_components, width, height, + modifiers, &flags, &n_modifiers)) + { + format = fallbacks[i]; + break; + } } - if (n_modifiers > 0) - break; + /* No format found. Likely, the width/height are too big */ + if (fallbacks[i] == -1) + return NULL; } - - if (n_modifiers > 0) - break; - - if (format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) - return NULL; - - format = gsk_memory_format_get_fallback (format); } self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL); @@ -981,7 +677,7 @@ gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device, self->display = g_object_ref (gsk_gpu_device_get_display (GSK_GPU_DEVICE (device))); gdk_display_ref_vulkan (self->display); self->vk_tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; - self->vk_format = format_info->format; + self->vk_format = vk_format; self->vk_pipeline_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; self->vk_image_layout = VK_IMAGE_LAYOUT_UNDEFINED; self->vk_access = 0; @@ -997,7 +693,7 @@ gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .flags = 0, .imageType = VK_IMAGE_TYPE_2D, - .format = format_info->format, + .format = vk_format, .extent = { width, height, 1 }, .mipLevels = 1, .arrayLayers = 1, @@ -1055,7 +751,7 @@ gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device, self->allocation.vk_memory, self->allocation.offset); - gsk_vulkan_image_create_view (self, VK_NULL_HANDLE, format_info); + gsk_vulkan_image_create_view (self, vk_format, &vk_components, VK_NULL_HANDLE); return GSK_GPU_IMAGE (self); } @@ -1340,11 +1036,9 @@ gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device, vk_conversion = VK_NULL_HANDLE; gsk_vulkan_image_create_view (self, - vk_conversion, - &(GskMemoryFormatInfo) { - vk_format, - vk_components, - }); + vk_format, + &vk_components, + vk_conversion); GDK_DEBUG (DMABUF, "Vulkan uploaded %zux%zu %.4s::%016llx %sdmabuf", width, height,