From: Chad Versace <chadvers...@chromium.org> For now, we support dma_buf images for only a single format, VK_FORMAT_R8G8B8A8_UNORM. And the image must be a "simple" image: 2D, single-sample, non-mipmappped, non-array, non-cube. --- src/intel/vulkan/anv_extensions.py | 1 + src/intel/vulkan/anv_formats.c | 144 ++++++++++++++++++++++++++++- src/intel/vulkan/anv_image.c | 182 ++++++++++++++++++++++++++++++++++--- src/intel/vulkan/anv_private.h | 6 ++ 4 files changed, 320 insertions(+), 13 deletions(-)
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py index 3abadff2dc..5601aaf60d 100644 --- a/src/intel/vulkan/anv_extensions.py +++ b/src/intel/vulkan/anv_extensions.py @@ -76,6 +76,7 @@ EXTENSIONS = [ Extension('VK_KHR_xcb_surface', 6, 'VK_USE_PLATFORM_XCB_KHR'), Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'), Extension('VK_KHX_multiview', 1, True), + Extension('VK_MESAX_external_image_dma_buf', 0, True), Extension('VK_MESAX_external_memory_dma_buf', 0, True), ] diff --git a/src/intel/vulkan/anv_formats.c b/src/intel/vulkan/anv_formats.c index 83a0b5ad68..64cbe69718 100644 --- a/src/intel/vulkan/anv_formats.c +++ b/src/intel/vulkan/anv_formats.c @@ -466,16 +466,64 @@ void anv_GetPhysicalDeviceFormatProperties( pFormatProperties); } +static void +get_dma_buf_format_props(struct anv_physical_device *phys_dev, + VkFormat vk_format, + VkDmaBufFormatPropertiesMESAX *props) +{ + struct anv_format anv_format = anv_formats[vk_format]; + VK_OUTARRAY_MAKE(mod_props, props->pModifierProperties, + &props->modifierCount); + + VkFormatFeatureFlags image_features = 0; + if (vk_format == VK_FORMAT_R8G8B8A8_UNORM) { + /* FINISHME: Support more formats for dma_buf images. */ + + /* For dma_buf images, we must use the exact format provided by the + * user. We must not adjust the format, as we do for non-external + * images, with swizzles and other tricks. In other words, the image's + * "base" format and "adjusted" format must be the same. + */ + image_features = get_image_format_properties(&phys_dev->info, + /*base format*/ anv_format.isl_format, + /*adjusted format*/ anv_format); + } + + if (image_features == 0) + return; + + /* Return DRM format modifiers in order of decreasing preference. */ + vk_outarray_append(&mod_props, p) { + p->drmFormatModifier = I915_FORMAT_MOD_Y_TILED; + p->imageFeatures = image_features; + } + + vk_outarray_append(&mod_props, p) { + p->drmFormatModifier = I915_FORMAT_MOD_X_TILED; + p->imageFeatures = image_features; + } + + vk_outarray_append(&mod_props, p) { + p->drmFormatModifier = DRM_FORMAT_MOD_LINEAR; + p->imageFeatures = image_features; + } +} + void anv_GetPhysicalDeviceFormatProperties2KHR( VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties) { + ANV_FROM_HANDLE(anv_physical_device, phys_dev, physicalDevice); + anv_GetPhysicalDeviceFormatProperties(physicalDevice, format, &pFormatProperties->formatProperties); vk_foreach_struct(ext, pFormatProperties->pNext) { switch (ext->sType) { + case VK_STRUCTURE_TYPE_DMA_BUF_FORMAT_PROPERTIES_MESAX: + get_dma_buf_format_props(phys_dev, format, (VkDmaBufFormatPropertiesMESAX *) ext); + break; default: anv_debug_ignored_stype(ext->sType); break; @@ -680,6 +728,91 @@ static const VkExternalMemoryPropertiesKHR dma_buf_mem_props = { VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_MESAX, }; +static VkResult +get_dma_buf_image_format_props(struct anv_physical_device *phys_dev, + const VkPhysicalDeviceImageFormatInfo2KHR *base_info, + VkImageFormatProperties2KHR *base_props, + VkExternalImageFormatPropertiesKHR *external_props, + VkDmaBufImageFormatPropertiesMESAX *dma_buf_props) +{ + /* We reject vkGetPhysicalDeviceImageFormatProperties2KHR() on the + * DMA_BUF_BIT unless the user adds VkDmaBufImageFormatPropertiesMESAX to + * the output chain. The spec permits this behavior but does not require + * it. + */ + if (dma_buf_props == NULL) { + return vk_errorf(VK_ERROR_FORMAT_NOT_SUPPORTED, + "dma_buf images require VkDmaBufImageFormatPropertiesMESAX"); + } + + VK_OUTARRAY_MAKE(mod_props, dma_buf_props->pModifierProperties, + &dma_buf_props->modifierCount); + + if (base_info->type != VK_IMAGE_TYPE_2D) { + return vk_errorf(VK_ERROR_FORMAT_NOT_SUPPORTED, + "dma_buf images require VK_IMAGE_TYPE_2D"); + } + + if (base_info->flags != 0) { + return vk_errorf(VK_ERROR_FORMAT_NOT_SUPPORTED, + "dma_buf images support no VkImageCreateFlags"); + } + + if (base_info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + return vk_errorf(VK_ERROR_FORMAT_NOT_SUPPORTED, + "dma_buf images do not support " + "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT"); + } + + if (base_info->format != VK_FORMAT_R8G8B8A8_UNORM) { + /* FINISHME: Support more formats for dma_buf images. */ + return vk_errorf(VK_ERROR_FORMAT_NOT_SUPPORTED, + "dma_buf images do not support VkFormat 0x%x", + base_info->format); + } + + /* We restrict some properties on dma_buf images. */ + base_props->imageFormatProperties.maxMipLevels = 1; + base_props->imageFormatProperties.maxArrayLayers = 1; + base_props->imageFormatProperties.sampleCounts = VK_SAMPLE_COUNT_1_BIT; + + /* Return DRM format modifiers in order of decreasing preference. */ + if (base_info->tiling == VK_IMAGE_TILING_OPTIMAL) { + vk_outarray_append(&mod_props, p) { + p->drmFormatModifier = I915_FORMAT_MOD_Y_TILED; + p->maxRowPitch = 0; + p->rowPitchAlignment = 0; + p->imageFormatProperties = base_props->imageFormatProperties; + } + + vk_outarray_append(&mod_props, p) { + p->drmFormatModifier = I915_FORMAT_MOD_X_TILED; + p->maxRowPitch = 0; + p->rowPitchAlignment = 0; + p->imageFormatProperties = base_props->imageFormatProperties; + } + } + + vk_outarray_append(&mod_props, p) { + p->drmFormatModifier = DRM_FORMAT_MOD_LINEAR; + p->maxRowPitch = 1 << 18; /* See RENDER_SURFACE_STATE::SurfacePitch */ + p->rowPitchAlignment = 1; + p->imageFormatProperties = base_props->imageFormatProperties; + } + + /* Clobber the base properties. + * + * TODO(chadv): Explain why the interaction between + * VK_MESAX_external_image_dma_buf and VK_KHX_external_memory_capabilities + * requires us to zero the base properties. + */ + base_props->imageFormatProperties = (VkImageFormatProperties) {0}; + + external_props->externalMemoryProperties = dma_buf_mem_props; + + return vk_outarray_status(&mod_props); +} + VkResult anv_GetPhysicalDeviceImageFormatProperties2KHR( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* base_info, @@ -688,6 +821,7 @@ VkResult anv_GetPhysicalDeviceImageFormatProperties2KHR( ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice); const VkPhysicalDeviceExternalImageFormatInfoKHR *external_info = NULL; VkExternalImageFormatPropertiesKHR *external_props = NULL; + VkDmaBufImageFormatPropertiesMESAX *dma_buf_props = NULL; VkResult result; result = anv_get_image_format_properties(physical_device, base_info, @@ -713,6 +847,9 @@ VkResult anv_GetPhysicalDeviceImageFormatProperties2KHR( case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR: external_props = (void *) s; break; + case VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_FORMAT_PROPERTIES_MESAX: + dma_buf_props = (void *) s; + break; default: anv_debug_ignored_stype(s->sType); break; @@ -732,7 +869,12 @@ VkResult anv_GetPhysicalDeviceImageFormatProperties2KHR( external_props->externalMemoryProperties = opaque_fd_props; break; case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_MESAX: - /* Fallthrough. We support dma_buf for VkBuffer but not yet VkImage. */ + result = get_dma_buf_image_format_props(physical_device, base_info, + base_props, external_props, + dma_buf_props); + if (result != VK_SUCCESS) + goto fail; + break; default: /* From the Vulkan 1.0.42 spec: * diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c index 48101d4461..1f8e5a208d 100644 --- a/src/intel/vulkan/anv_image.c +++ b/src/intel/vulkan/anv_image.c @@ -108,11 +108,31 @@ get_surface(struct anv_image *image, VkImageAspectFlags aspect) } static isl_tiling_flags_t -choose_isl_tiling_flags(const struct anv_image_create_info *anv_info) +choose_isl_tiling_flags(const struct anv_image_create_info *anv_info, + const VkImportImageDmaBufInfoMESAX *import_dma_buf_info, + const VkExportImageDmaBufInfoMESAX *export_dma_buf_info) { - isl_tiling_flags_t flags; - - if (anv_info->vk_info->tiling == VK_IMAGE_TILING_LINEAR) { + isl_tiling_flags_t flags = 0; + + if (import_dma_buf_info) { + uint64_t mod = import_dma_buf_info->drmFormatModifier; + enum isl_tiling t; + enum isl_aux_usage a; + if (isl_tiling_from_drm_format_mod(mod, &t, &a) && + a == ISL_AUX_USAGE_NONE) { + flags = 1 << t; + } + } else if (export_dma_buf_info) { + for (uint32_t i = 0; i < export_dma_buf_info->drmFormatModifierCount; ++i) { + uint64_t mod = export_dma_buf_info->pDrmFormatModifiers[i]; + enum isl_tiling t; + enum isl_aux_usage a; + if (isl_tiling_from_drm_format_mod(mod, &t, &a) && + a == ISL_AUX_USAGE_NONE) { + flags |= 1 << t; + } + } + } else if (anv_info->vk_info->tiling == VK_IMAGE_TILING_LINEAR) { flags = ISL_TILING_LINEAR_BIT; } else { flags = ISL_TILING_ANY_MASK; @@ -121,9 +141,49 @@ choose_isl_tiling_flags(const struct anv_image_create_info *anv_info) if (anv_info->isl_tiling_flags) flags &= anv_info->isl_tiling_flags; + assert(flags != 0); + return flags; } +static enum isl_format +choose_isl_format(const struct anv_device *dev, + const VkImageCreateInfo *base_info, + VkImageAspectFlagBits aspect, + VkExternalMemoryHandleTypeFlagsKHR handle_types) +{ + /* We don't yet support images compatible with multiple handle types + * because our choice of format depends on the handle type. For + * non-external images and opaque fd images, we choose an "adjusted" + * format. For dma_buf images, we must use the exact format provided by the + * user. + */ + assert(__builtin_popcount(handle_types) <= 1); + + if (handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_MESAX) { + return anv_get_raw_isl_format(&dev->info, base_info->format); + } else { + return anv_get_isl_format(&dev->info, base_info->format, aspect, + base_info->tiling); + } +} + +static uint32_t +choose_row_pitch(const struct anv_image_create_info *anv_info, + const VkImportImageDmaBufPlaneInfoMESAX *plane_info) +{ + if (anv_info->stride != 0) + return anv_info->stride; + + if (plane_info) { + assert(plane_info->rowPitch > 0); + return plane_info->rowPitch; + } + + /* Let isl choose the pitch. */ + return 0; +} + static void set_min_surface_offset(const struct anv_image *image, struct anv_surface *surf) { @@ -328,8 +388,24 @@ static void make_aux_surface_maybe(const struct anv_device *dev, const VkImageCreateInfo *base_info, VkImageAspectFlags aspect, + VkExternalMemoryHandleTypeFlagsKHR handle_types, struct anv_image *image) { + /* We don't yet support images compatible with multiple handle types + * because our choice of aux surface depends on the handle type. For + * non-external images and opaque fd images, we choose the optimal aux + * surface. For dma_buf images, we must use the aux surface specified by + * the user. + */ + assert(__builtin_popcount(handle_types) <= 1); + + if (handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_MESAX) { + /* As of 2017-02-25, drm_fourcc.h still does not define a format modifier + * for any aux surface. + */ + return; + } + if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT) { make_hiz_surface_maybe(dev, base_info, image); } else if (aspect == VK_IMAGE_ASPECT_COLOR_BIT && base_info->samples == 1) { @@ -348,7 +424,10 @@ make_aux_surface_maybe(const struct anv_device *dev, static void make_main_surface(const struct anv_device *dev, const struct anv_image_create_info *anv_info, + const VkImportImageDmaBufInfoMESAX *import_dma_buf_info, + const VkExportImageDmaBufInfoMESAX *export_dma_buf_info, VkImageAspectFlags aspect, + VkExternalMemoryHandleTypeFlagsKHR handle_types, struct anv_image *image) { const VkImageCreateInfo *base_info = anv_info->vk_info; @@ -360,14 +439,21 @@ make_main_surface(const struct anv_device *dev, [VK_IMAGE_TYPE_3D] = ISL_SURF_DIM_3D, }; - const isl_tiling_flags_t tiling_flags = choose_isl_tiling_flags(anv_info); + const VkImportImageDmaBufPlaneInfoMESAX *plane_info = NULL; + if (import_dma_buf_info) + plane_info = &import_dma_buf_info->pPlanes[0]; + + const isl_tiling_flags_t tiling_flags = + choose_isl_tiling_flags(anv_info, import_dma_buf_info, export_dma_buf_info); + const uint32_t row_pitch = choose_row_pitch(anv_info, plane_info); + struct anv_surface *anv_surf = get_surface(image, aspect); image->extent = anv_sanitize_image_extent(base_info->imageType, base_info->extent); - enum isl_format format = anv_get_isl_format(&dev->info, base_info->format, - aspect, base_info->tiling); + const enum isl_format format = + choose_isl_format(dev, base_info, aspect, handle_types); assert(format != ISL_FORMAT_UNSUPPORTED); ok = isl_surf_init(&dev->isl_dev, &anv_surf->isl, @@ -380,7 +466,7 @@ make_main_surface(const struct anv_device *dev, .array_len = base_info->arrayLayers, .samples = base_info->samples, .min_alignment = 0, - .row_pitch = anv_info->stride, + .row_pitch = row_pitch, .usage = choose_isl_surf_usage(base_info->flags, image->usage, aspect), .tiling_flags = tiling_flags); @@ -389,7 +475,12 @@ make_main_surface(const struct anv_device *dev, */ assert(ok); - set_min_surface_offset(image, anv_surf); + if (plane_info) { + anv_surf->offset = plane_info->offset; + } else { + set_min_surface_offset(image, anv_surf); + } + add_surface(image, anv_surf); } @@ -401,10 +492,36 @@ anv_image_create(VkDevice _device, { ANV_FROM_HANDLE(anv_device, device, _device); const VkImageCreateInfo *base_info = anv_info->vk_info; + const VkImportImageDmaBufInfoMESAX *import_dma_buf_info = NULL; + const VkExportImageDmaBufInfoMESAX *export_dma_buf_info = NULL; + VkExternalMemoryHandleTypeFlagsKHR handle_types = 0; struct anv_image *image = NULL; assert(base_info->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); + vk_foreach_struct_const(s, base_info->pNext) { + switch (s->sType) { + case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR: + handle_types = + ((const VkExternalMemoryImageCreateInfoKHR *) s)->handleTypes; + assert((handle_types & ~ANV_SUPPORTED_MEMORY_HANDLE_TYPES) == 0); + break; + case VK_STRUCTURE_TYPE_IMPORT_IMAGE_DMA_BUF_INFO_MESAX: + import_dma_buf_info = (const void *) s; + break; + case VK_STRUCTURE_TYPE_EXPORT_IMAGE_DMA_BUF_INFO_MESAX: + export_dma_buf_info = (const void *) s; + break; + default: + anv_debug_ignored_stype(s->sType); + break; + } + } + + /* For dma_buf images, we require the user to provide DRM format modifiers. */ + assert((bool)(handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_MESAX) == + (import_dma_buf_info || export_dma_buf_info)); + anv_assert(base_info->mipLevels > 0); anv_assert(base_info->arrayLayers > 0); anv_assert(base_info->samples > 0); @@ -431,8 +548,9 @@ anv_image_create(VkDevice _device, uint32_t b; for_each_bit(b, image->aspects) { VkImageAspectFlagBits aspect = 1 << b; - make_main_surface(device, anv_info, aspect, image); - make_aux_surface_maybe(device, base_info, aspect, image); + make_main_surface(device, anv_info, import_dma_buf_info, + export_dma_buf_info, aspect, handle_types, image); + make_aux_surface_maybe(device, base_info, aspect, handle_types, image); } *pImage = anv_image_to_handle(image); @@ -535,13 +653,53 @@ void anv_GetImageSubresourceLayout( } } +static VkResult +get_image_dma_buf_props(const struct anv_image *image, + VkImageDmaBufPropertiesMESAX* dma_buf_props) +{ + VK_OUTARRAY_MAKE(planes, dma_buf_props->pPlanes, + &dma_buf_props->planeCount); + bool ok UNUSED; + + /* For now, we support exactly one format for dma_buf images. */ + assert(image->vk_format == VK_FORMAT_R8G8B8A8_UNORM); + + /* For now, We don't support dma_buf images with auxiliary surfaces. */ + assert(image->aux_surface.isl.size == 0); + + ok = isl_surf_get_drm_format_mod(&image->color_surface.isl, + image->aux_usage, + &dma_buf_props->drmFormatModifier); + assert(ok); + + vk_outarray_append(&planes, p) { + p->offset = image->color_surface.offset; + p->rowPitch = image->color_surface.isl.row_pitch; + } + + return vk_outarray_status(&planes); +} + VkResult anv_GetImagePropertiesEXT( VkDevice device_h, VkImage image_h, VkImagePropertiesEXT* base_props) { + ANV_FROM_HANDLE(anv_image, image, image_h); + VkResult result; + vk_foreach_struct(s, base_props->pNext) { - anv_debug_ignored_stype(s->sType); + switch (s->sType) { + case VK_STRUCTURE_TYPE_IMAGE_DMA_BUF_PROPERTIES_MESAX: + result = get_image_dma_buf_props(image, + (VkImageDmaBufPropertiesMESAX *) s); + if (result != VK_SUCCESS) + return result; + break; + default: + anv_debug_ignored_stype(s->sType); + break; + } } return VK_SUCCESS; diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 08f69a0c8c..e841291a10 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -30,7 +30,13 @@ #include <pthread.h> #include <assert.h> #include <stdint.h> + #include <i915_drm.h> +#include <drm_fourcc.h> + +#ifndef DRM_FORMAT_MOD_LINEAR /* new in Linux 4.10 */ +#define DRM_FORMAT_MOD_LINEAR 0 +#endif #ifdef HAVE_VALGRIND #include <valgrind.h> -- 2.13.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev