[Mesa-dev] [RFC v2 16/22] RFC: anv: Implement VK_MESAX_external_image_dma_buf
Louis-Francis Ratté-Boulianne
lfrb at collabora.com
Thu Aug 31 04:24:24 UTC 2017
From: Chad Versace <chadversary at 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
More information about the mesa-dev
mailing list