From 129e31cd4f790d982a6ae14e649aeb1da07b917b Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Thu, 18 Nov 2021 17:04:02 -0500 Subject: [PATCH] zink: hook up planar image format creation it'll explode if used for anything, but this is how it's done Reviewed-by: Dave Airlie Part-of: --- src/gallium/drivers/zink/zink_device_info.py | 1 + src/gallium/drivers/zink/zink_resource.c | 159 +++++++++++++++++++++++---- src/gallium/drivers/zink/zink_resource.h | 4 + 3 files changed, 140 insertions(+), 24 deletions(-) diff --git a/src/gallium/drivers/zink/zink_device_info.py b/src/gallium/drivers/zink/zink_device_info.py index a861295..1d9c26e 100644 --- a/src/gallium/drivers/zink/zink_device_info.py +++ b/src/gallium/drivers/zink/zink_device_info.py @@ -117,6 +117,7 @@ EXTENSIONS = [ features=True, conditions=["$feats.indexTypeUint8"]), Extension("VK_KHR_image_format_list"), + Extension("VK_KHR_sampler_ycbcr_conversion"), Extension("VK_KHR_imageless_framebuffer", alias="imgless", features=True, diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index d8b4490..b865725 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -34,6 +34,7 @@ #endif #include "vulkan/wsi/wsi_common.h" +#include "vk_format.h" #include "util/slab.h" #include "util/u_blitter.h" #include "util/u_debug.h" @@ -189,6 +190,11 @@ check_ici(struct zink_screen *screen, VkImageCreateInfo *ici, uint64_t modifier) VkImageFormatProperties2 props2; props2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; props2.pNext = NULL; + VkSamplerYcbcrConversionImageFormatProperties ycbcr_props; + ycbcr_props.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES; + ycbcr_props.pNext = NULL; + if (screen->info.have_KHR_sampler_ycbcr_conversion) + props2.pNext = &ycbcr_props; VkPhysicalDeviceImageFormatInfo2 info; info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; info.format = ici->format; @@ -209,6 +215,9 @@ check_ici(struct zink_screen *screen, VkImageCreateInfo *ici, uint64_t modifier) info.pNext = NULL; ret = VKSCR(GetPhysicalDeviceImageFormatProperties2)(screen->pdev, &info, &props2); + /* this is using VK_IMAGE_CREATE_EXTENDED_USAGE_BIT and can't be validated */ + if (vk_format_aspects(ici->format) & VK_IMAGE_ASPECT_PLANE_1_BIT) + ret = VK_SUCCESS; image_props = props2.imageFormatProperties; } else ret = VKSCR(GetPhysicalDeviceImageFormatProperties)(screen->pdev, ici->format, ici->imageType, @@ -220,18 +229,20 @@ static VkImageUsageFlags get_image_usage_for_feats(struct zink_screen *screen, VkFormatFeatureFlags feats, const struct pipe_resource *templ, unsigned bind) { VkImageUsageFlags usage = 0; + bool is_planar = util_format_get_num_planes(templ->format) > 1; + if (bind & ZINK_BIND_TRANSIENT) usage |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; else { /* sadly, gallium doesn't let us know if it'll ever need this, so we have to assume */ - if (feats & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) + if (is_planar || (feats & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)) usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - if (feats & VK_FORMAT_FEATURE_TRANSFER_DST_BIT) + if (is_planar || (feats & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; if (feats & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) usage |= VK_IMAGE_USAGE_SAMPLED_BIT; - if ((feats & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) && (bind & PIPE_BIND_SHADER_IMAGE)) { + if ((is_planar || (feats & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) && (bind & PIPE_BIND_SHADER_IMAGE)) { assert(templ->nr_samples <= 1 || screen->info.feats.features.shaderStorageImageMultisample); usage |= VK_IMAGE_USAGE_STORAGE_BIT; } @@ -242,7 +253,7 @@ get_image_usage_for_feats(struct zink_screen *screen, VkFormatFeatureFlags feats usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; if ((bind & (PIPE_BIND_LINEAR | PIPE_BIND_SHARED)) != (PIPE_BIND_LINEAR | PIPE_BIND_SHARED)) usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - } else + } else if (!(bind & ZINK_BIND_VIDEO)) return 0; } @@ -335,7 +346,10 @@ create_ici(struct zink_screen *screen, VkImageCreateInfo *ici, const struct pipe { ici->sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; ici->pNext = NULL; - ici->flags = modifiers_count || dmabuf || bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DEPTH_STENCIL) ? 0 : VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + if (util_format_get_num_planes(templ->format) > 1) + ici->flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + else + ici->flags = modifiers_count || dmabuf || bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DEPTH_STENCIL) ? 0 : VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; ici->usage = 0; ici->queueFamilyIndexCount = 0; @@ -459,21 +473,32 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t if (!obj) return NULL; - VkMemoryRequirements reqs; + VkMemoryRequirements reqs = {0}; VkMemoryPropertyFlags flags; bool need_dedicated = false; bool shared = templ->bind & PIPE_BIND_SHARED; VkExternalMemoryHandleTypeFlags export_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; - + unsigned num_planes = util_format_get_num_planes(templ->format); + VkImageAspectFlags plane_aspects[] = { + VK_IMAGE_ASPECT_PLANE_0_BIT, + VK_IMAGE_ASPECT_PLANE_1_BIT, + VK_IMAGE_ASPECT_PLANE_2_BIT, + }; VkExternalMemoryHandleTypeFlags external = 0; + bool needs_export = (templ->bind & ZINK_BIND_VIDEO) != 0; if (whandle) { - if (whandle->type == WINSYS_HANDLE_TYPE_FD) { + if (whandle->type == WINSYS_HANDLE_TYPE_FD || whandle->type == ZINK_EXTERNAL_MEMORY_HANDLE) + needs_export |= true; + else + unreachable("unknown handle type"); + } + if (needs_export) { + if (whandle && whandle->type == ZINK_EXTERNAL_MEMORY_HANDLE) { + external = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + } else { external = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; export_types |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - } else if (whandle->type == ZINK_EXTERNAL_MEMORY_HANDLE) { - external = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; - } else - unreachable("unknown handle type"); + } } /* TODO: remove linear for wsi */ @@ -515,6 +540,8 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t if (!success) goto fail1; + obj->render_target = (ici.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0; + if (shared || external) { emici.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; emici.pNext = NULL; @@ -528,11 +555,6 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t idfmeci.pNext = ici.pNext; idfmeci.drmFormatModifier = mod; - /* TODO: store these values from other planes in their - * respective zink_resource, and walk the next-pointers to - * build up the planar array here instead. - */ - assert(util_format_get_num_planes(templ->format) == 1); idfmeci.drmFormatModifierPlaneCount = 1; VkSubresourceLayout plane_layout = { .offset = whandle->offset, @@ -576,6 +598,60 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t image_wsi_info.pNext = ici.pNext; ici.pNext = &image_wsi_info; } + if (util_format_is_yuv(templ->format)) { + VkFormatFeatureFlags feats = VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM; + switch (ici.tiling) { + case VK_IMAGE_TILING_LINEAR: + feats = screen->format_props[templ->format].linearTilingFeatures; + break; + case VK_IMAGE_TILING_OPTIMAL: + feats = screen->format_props[templ->format].optimalTilingFeatures; + break; + case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: + /* + If is tiling then VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, the value of + imageCreateFormatFeatures is found by calling vkGetPhysicalDeviceFormatProperties2 + with VkImageFormatProperties::format equal to VkImageCreateInfo::format and with + VkDrmFormatModifierPropertiesListEXT chained into VkImageFormatProperties2; by + collecting all members of the returned array + VkDrmFormatModifierPropertiesListEXT::pDrmFormatModifierProperties + whose drmFormatModifier belongs to imageCreateDrmFormatModifiers; and by taking the bitwise + intersection, over the collected array members, of drmFormatModifierTilingFeatures. + (The resultant imageCreateFormatFeatures may be empty). + * -Chapter 12. Resource Creation + */ + for (unsigned i = 0; i < screen->modifier_props[templ->format].drmFormatModifierCount; i++) + feats &= screen->modifier_props[templ->format].pDrmFormatModifierProperties[i].drmFormatModifierTilingFeatures; + break; + default: + unreachable("unknown tiling"); + } + if (feats & VK_FORMAT_FEATURE_DISJOINT_BIT) + ici.flags |= VK_IMAGE_CREATE_DISJOINT_BIT; + VkSamplerYcbcrConversionCreateInfo sycci = {0}; + sycci.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO; + sycci.pNext = NULL; + sycci.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; + sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709; + sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; + sycci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + sycci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + sycci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + sycci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + if (!feats || (feats & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) { + sycci.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; + sycci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; + } else { + assert(feats & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT); + sycci.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT; + sycci.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT; + } + sycci.chromaFilter = VK_FILTER_LINEAR; + sycci.forceExplicitReconstruction = VK_FALSE; + VkResult res = VKSCR(CreateSamplerYcbcrConversion)(screen->dev, &sycci, NULL, &obj->sampler_conversion); + if (res != VK_SUCCESS) + goto fail1; + } VkResult result = VKSCR(CreateImage)(screen->dev, &ici, NULL, &obj->image); if (result != VK_SUCCESS) { @@ -614,9 +690,22 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t ded.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS; ded.pNext = NULL; req2.pNext = &ded; - VKSCR(GetImageMemoryRequirements2)(screen->dev, &info2, &req2); - memcpy(&reqs, &req2.memoryRequirements, sizeof(VkMemoryRequirements)); - need_dedicated = ded.prefersDedicatedAllocation || ded.requiresDedicatedAllocation; + VkImagePlaneMemoryRequirementsInfo plane; + plane.sType = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO; + plane.pNext = NULL; + if (num_planes > 1) + info2.pNext = &plane; + for (unsigned i = 0; i < num_planes; i++) { + assert(i < ARRAY_SIZE(plane_aspects)); + plane.planeAspect = plane_aspects[i]; + VKSCR(GetImageMemoryRequirements2)(screen->dev, &info2, &req2); + if (!i) + reqs.alignment = req2.memoryRequirements.alignment; + obj->plane_sizes[i] = req2.memoryRequirements.size; + reqs.size += req2.memoryRequirements.size; + reqs.memoryTypeBits |= req2.memoryRequirements.memoryTypeBits; + need_dedicated |= ded.prefersDedicatedAllocation || ded.requiresDedicatedAllocation; + } } else { VKSCR(GetImageMemoryRequirements)(screen->dev, obj->image, &reqs); } @@ -675,7 +764,7 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t } VkExportMemoryAllocateInfo emai; - if (templ->bind & PIPE_BIND_SHARED && shared) { + if ((templ->bind & ZINK_BIND_VIDEO) || ((templ->bind & PIPE_BIND_SHARED) && shared)) { emai.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; emai.handleTypes = export_types; @@ -739,9 +828,28 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t if (VKSCR(BindBufferMemory)(screen->dev, obj->buffer, zink_bo_get_mem(obj->bo), obj->offset) != VK_SUCCESS) goto fail3; } else { - if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE)) - if (VKSCR(BindImageMemory)(screen->dev, obj->image, zink_bo_get_mem(obj->bo), obj->offset) != VK_SUCCESS) + if (num_planes > 1) { + VkBindImageMemoryInfo infos[3]; + VkBindImagePlaneMemoryInfo planes[3]; + unsigned offset = 0; + for (unsigned i = 0; i < num_planes; i++) { + infos[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; + infos[i].pNext = &planes[i]; + infos[i].image = obj->image; + infos[i].memory = zink_bo_get_mem(obj->bo); + infos[i].memoryOffset = offset; + planes[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; + planes[i].pNext = NULL; + planes[i].planeAspect = plane_aspects[i]; + offset += obj->plane_sizes[i]; + } + if (VKSCR(BindImageMemory2)(screen->dev, num_planes, infos) != VK_SUCCESS) goto fail3; + } else { + if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE)) + if (VKSCR(BindImageMemory)(screen->dev, obj->image, zink_bo_get_mem(obj->bo), obj->offset) != VK_SUCCESS) + goto fail3; + } } return obj; @@ -909,8 +1017,11 @@ zink_resource_get_param(struct pipe_screen *pscreen, struct pipe_context *pctx, default: unreachable("how many planes you got in this thing?"); } - } else + } else if (res->obj->sampler_conversion) { + aspect = VK_IMAGE_ASPECT_PLANE_0_BIT; + } else { aspect = res->aspect; + } switch (param) { case PIPE_RESOURCE_PARAM_NPLANES: if (screen->info.have_EXT_image_drm_format_modifier) diff --git a/src/gallium/drivers/zink/zink_resource.h b/src/gallium/drivers/zink/zink_resource.h index 5e99dca..5c14679 100644 --- a/src/gallium/drivers/zink/zink_resource.h +++ b/src/gallium/drivers/zink/zink_resource.h @@ -44,6 +44,7 @@ struct zink_bo; #define ZINK_MAP_TEMPORARY (PIPE_MAP_DRV_PRV << 0) #define ZINK_BIND_TRANSIENT (1 << 30) //transient fb attachment +#define ZINK_BIND_VIDEO (1 << 31) struct mem_key { unsigned seen_count; @@ -75,6 +76,7 @@ struct zink_resource_object { bool storage_init; //layout was set for image bool transfer_dst; + bool render_target; bool is_buffer; struct zink_bo *bo; @@ -83,6 +85,8 @@ struct zink_resource_object { VkImageUsageFlags vkusage; uint64_t modifier; VkImageAspectFlags modifier_aspect; + VkSamplerYcbcrConversionKHR sampler_conversion; + unsigned plane_sizes[3]; bool host_visible; bool coherent; -- 2.7.4