[Mesa-dev] [RFC PATCH 09/13] RFC: anv: Implement VK_MESAX_external_image_dma_buf
Chad Versace
chadversary at chromium.org
Mon Mar 6 20:40:18 UTC 2017
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_device.c | 4 +
src/intel/vulkan/anv_entrypoints_gen.py | 1 +
src/intel/vulkan/anv_formats.c | 147 ++++++++++++++++++++++++++-
src/intel/vulkan/anv_image.c | 173 ++++++++++++++++++++++++++++++--
src/intel/vulkan/anv_private.h | 6 ++
5 files changed, 320 insertions(+), 11 deletions(-)
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index cc5f57b0f86..b2dce7695fc 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -326,6 +326,10 @@ static const VkExtensionProperties device_extensions[] = {
.extensionName = VK_MESAX_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
.specVersion = 0,
},
+ {
+ .extensionName = VK_MESAX_EXTERNAL_IMAGE_DMA_BUF_EXTENSION_NAME,
+ .specVersion = 0,
+ },
};
static void *
diff --git a/src/intel/vulkan/anv_entrypoints_gen.py b/src/intel/vulkan/anv_entrypoints_gen.py
index 7ba070be5e4..b49a9c54e27 100644
--- a/src/intel/vulkan/anv_entrypoints_gen.py
+++ b/src/intel/vulkan/anv_entrypoints_gen.py
@@ -43,6 +43,7 @@ supported_extensions = [
'VK_KHX_external_memory',
'VK_KHX_external_memory_capabilities',
'VK_KHX_external_memory_fd',
+ 'VK_MESAX_external_image_dma_buf',
'VK_MESAX_external_memory_dma_buf',
]
diff --git a/src/intel/vulkan/anv_formats.c b/src/intel/vulkan/anv_formats.c
index cbbbd0bc0d8..98a321a0a82 100644
--- a/src/intel/vulkan/anv_formats.c
+++ b/src/intel/vulkan/anv_formats.c
@@ -471,16 +471,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];
+ ANV_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. */
+ anv_outarray_append(&mod_props, p) {
+ p->drmFormatModifier = I915_FORMAT_MOD_Y_TILED;
+ p->imageFeatures = image_features;
+ }
+
+ anv_outarray_append(&mod_props, p) {
+ p->drmFormatModifier = I915_FORMAT_MOD_X_TILED;
+ p->imageFeatures = image_features;
+ }
+
+ anv_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;
@@ -685,6 +733,94 @@ static const VkExternalMemoryPropertiesKHX 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,
+ VkExternalImageFormatPropertiesKHX *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");
+ }
+
+ ANV_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) {
+ anv_outarray_append(&mod_props, p) {
+ p->drmFormatModifier = I915_FORMAT_MOD_Y_TILED;
+ p->maxRowPitch = 0;
+ p->rowPitchAlignment = 0;
+ p->imageFormatProperties = base_props->imageFormatProperties;
+ }
+
+ anv_outarray_append(&mod_props, p) {
+ p->drmFormatModifier = I915_FORMAT_MOD_X_TILED;
+ p->maxRowPitch = 0;
+ p->rowPitchAlignment = 0;
+ p->imageFormatProperties = base_props->imageFormatProperties;
+ }
+ }
+
+ anv_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;
+
+ if (anv_outarray_is_incomple(&mod_props))
+ return VK_INCOMPLETE;
+
+ return VK_SUCCESS;
+}
+
VkResult anv_GetPhysicalDeviceImageFormatProperties2KHR(
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceImageFormatInfo2KHR* base_info,
@@ -693,6 +829,7 @@ VkResult anv_GetPhysicalDeviceImageFormatProperties2KHR(
ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice);
const VkPhysicalDeviceExternalImageFormatInfoKHX *external_info = NULL;
VkExternalImageFormatPropertiesKHX *external_props = NULL;
+ VkDmaBufImageFormatPropertiesMESAX *dma_buf_props = NULL;
VkResult result;
result = anv_get_image_format_properties(physical_device, base_info,
@@ -718,6 +855,9 @@ VkResult anv_GetPhysicalDeviceImageFormatProperties2KHR(
case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHX:
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;
@@ -736,7 +876,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 bca56a417aa..60b33fba2ae 100644
--- a/src/intel/vulkan/anv_image.c
+++ b/src/intel/vulkan/anv_image.c
@@ -106,11 +106,23 @@ 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) {
+ if (import_dma_buf_info) {
+ uint64_t mod = import_dma_buf_info->drmFormatModifier;
+ flags = 1 << isl_tiling_from_drm_format_mod(mod);
+ } else if (export_dma_buf_info) {
+ flags = 0;
+
+ for (uint32_t i = 0; i < export_dma_buf_info->drmFormatModifierCount; ++i) {
+ uint64_t mod = export_dma_buf_info->pDrmFormatModifiers[i];
+ flags |= 1 << isl_tiling_from_drm_format_mod(mod);
+ }
+ } else if (anv_info->vk_info->tiling == VK_IMAGE_TILING_LINEAR) {
flags = ISL_TILING_LINEAR_BIT;
} else {
flags = ISL_TILING_ANY_MASK;
@@ -119,9 +131,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,
+ VkExternalMemoryHandleTypeFlagsKHX 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)
{
@@ -231,8 +283,24 @@ static void
make_aux_surface_maybe(const struct anv_device *dev,
const VkImageCreateInfo *base_info,
VkImageAspectFlags aspect,
+ VkExternalMemoryHandleTypeFlagsKHX 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) {
@@ -251,7 +319,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,
+ VkExternalMemoryHandleTypeFlagsKHX handle_types,
struct anv_image *image)
{
const VkImageCreateInfo *base_info = anv_info->vk_info;
@@ -263,14 +334,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,
@@ -283,7 +361,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(image->usage, aspect),
.tiling_flags = tiling_flags);
@@ -292,7 +370,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);
}
@@ -304,10 +387,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;
+ VkExternalMemoryHandleTypeFlagsKHX 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_KHX:
+ handle_types =
+ ((const VkExternalMemoryImageCreateInfoKHX *) 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);
@@ -335,8 +444,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);
@@ -469,13 +579,56 @@ void anv_GetImageSubresourceLayout(
}
}
+static VkResult
+get_image_dma_buf_props(const struct anv_image *image,
+ VkImageDmaBufPropertiesMESAX* dma_buf_props)
+{
+ ANV_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);
+
+ anv_outarray_append(&planes, p) {
+ p->offset = image->color_surface.offset;
+ p->rowPitch = image->color_surface.isl.row_pitch;
+ }
+
+ if (anv_outarray_is_incomple(&planes))
+ return VK_INCOMPLETE;
+
+ return VK_SUCCESS;
+}
+
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 ac922e7cfc6..103a9d68a9e 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.12.0
More information about the mesa-dev
mailing list