+
+static int
+anv_hal_open(const struct hw_module_t* mod, const char* id,
+ struct hw_device_t** dev)
+{
+ assert(mod == &HAL_MODULE_INFO_SYM.common);
+ assert(strcmp(id, HWVULKAN_DEVICE_0) == 0);
+
+ hwvulkan_device_t *vkdev = malloc(sizeof(*vkdev));
+ if (!vkdev)
+ return -1;
+
+ *vkdev = (hwvulkan_device_t) {
+ .common = {
+ .tag = HARDWARE_DEVICE_TAG,
+ .version = HWVULKAN_DEVICE_API_VERSION_0_1,
+ .module = &HAL_MODULE_INFO_SYM.common,
+ .close = anv_hal_close,
+ },
+ .EnumerateInstanceExtensionProperties =
anv_EnumerateInstanceExtensionProperties,
+ .CreateInstance = anv_CreateInstance,
+ .GetInstanceProcAddr = anv_GetInstanceProcAddr,
+ };
+
+ *dev = &vkdev->common;
+ return 0;
+}
+
+static int
+anv_hal_close(struct hw_device_t *dev)
+{
+ /* hwvulkan.h claims that hw_device_t::close() is never called. */
+ return -1;
+}
+
+VkResult anv_GetSwapchainGrallocUsageANDROID(
+ VkDevice device_h,
+ VkFormat format,
+ VkImageUsageFlags imageUsage,
+ int* grallocUsage)
+{
+ ANV_FROM_HANDLE(anv_device, device, device_h);
+ struct anv_physical_device *phys_dev = &device->instance->physicalDevice;
+ VkPhysicalDevice phys_dev_h = anv_physical_device_to_handle(phys_dev);
+ VkFormatProperties props;
+
+ static const VkFormat fb_formats[] = {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B5G6R5_UNORM_PACK16,
+ };
+
+ *grallocUsage = 0;
+ anv_GetPhysicalDeviceFormatProperties(phys_dev_h, format, &props);
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(fb_formats); ++i) {
+ if (format == fb_formats[i]) {
+ /* TODO(chadv): Query these properties from isl. */
+ *grallocUsage |= GRALLOC_USAGE_HW_FB |
+ GRALLOC_USAGE_HW_COMPOSER |
+ GRALLOC_USAGE_EXTERNAL_DISP;
+ break;
+ }
+ }
+
+ if ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
+ *grallocUsage |= GRALLOC_USAGE_HW_TEXTURE;
+
+ if ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
+ *grallocUsage |= GRALLOC_USAGE_HW_RENDER;
+
+ if ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
+ *grallocUsage |= GRALLOC_USAGE_HW_TEXTURE;
+
+ if (*grallocUsage == 0)
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+
+ return VK_SUCCESS;
+}
+
+VkResult
+anv_AcquireImageANDROID(
+ VkDevice device_h,
+ VkImage image_h,
+ int nativeFenceFd,
+ VkSemaphore semaphore_h,
+ VkFence fence_h)
+{
+ ANV_FROM_HANDLE(anv_semaphore, semaphore, semaphore_h);
+ ANV_FROM_HANDLE(anv_fence, fence, fence_h);
+ VkResult result = VK_SUCCESS;
+
+ if (nativeFenceFd != -1) {
+ /* As a simple, firstpass implementation of VK_ANDROID_native_buffer, we
+ * block on the nativeFenceFd. This may introduce latency and is
+ * definitiely inefficient, yet it's correct.
+ *
+ * FINISHME(chadv): Import the nativeFenceFd into the VkSemaphore and
+ * VkFence.
+ */
+ if (sync_wait(nativeFenceFd, /*timeout*/ -1) < 0) {
+ result = vk_errorf(VK_ERROR_DEVICE_LOST,
+ "%s: failed to wait on nativeFenceFd=%d",
+ __func__, nativeFenceFd);
+ goto done;
+ }
+ }
+
+ if (semaphore) {
+ /* It's illegal to import into an existing import. */
+ assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
+
+ /* It's also illegal here to import into an in-flight semaphore.
+ * Therefore, thanks to implicit sync, there's nothing to do here
+ * because we have already blocked on the nativeFenceFd.
+ */
+ }
+
+ if (fence) {
+ /* It's illegal to import into an existing import. */
+ assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
+
+
+ /* We can transition the fence's state from reset to signalled because
+ * we blocked on the sync fd. Since the fence had no waiters, there's no
+ * need to broadcast the state transition.
+ */
+ switch (fence->permanent.type) {
+ case ANV_FENCE_TYPE_NONE:
+ unreachable("anv_fence::permanent::type is NONE");
+ case ANV_FENCE_TYPE_BO:
+ /* It's illegal to import into a fence in the non-resting state. */
+ assert(fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET);
+ fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
+ break;
+ case ANV_FENCE_TYPE_SYNCOBJ:
+ break;
+ }
+ }
+
+ done:
+ if (nativeFenceFd != -1) {
+ /* From VK_ANDROID_native_buffer's pseudo spec
+ * (https://source.android.com/devices/graphics/implement-vulkan):
+ *
+ * The driver takes ownership of the fence fd and is responsible for
+ * closing it [...] even if vkAcquireImageANDROID fails and returns
+ * an error.
+ */
+ close(nativeFenceFd);
+ }
+
+ return result;
+}
+
+VkResult
+anv_QueueSignalReleaseImageANDROID(
+ VkQueue queue,
+ uint32_t waitSemaphoreCount,
+ const VkSemaphore* pWaitSemaphores,
+ VkImage image,
+ int* pNativeFenceFd)
+{
+ VkResult result;
+
+ if (waitSemaphoreCount == 0)
+ goto done;
+
+ result = anv_QueueSubmit(queue,
+ 1, (VkSubmitInfo[]) {
+ {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .waitSemaphoreCount = 1,
+ .pWaitSemaphores = pWaitSemaphores,
+ },
+ },
+ (VkFence) VK_NULL_HANDLE);
+ if (result != VK_SUCCESS)
+ return result;
+
+ done:
+ if (pNativeFenceFd) {
+ /* We can rely implicit on sync because above we submitted all
+ * semaphores to the queue.
+ */
+ *pNativeFenceFd = -1;
+ }
+
+ return VK_SUCCESS;
+}
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 8cc760c3721..d221ba46645 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -1440,10 +1440,20 @@ VkResult anv_AllocateMemory(
struct anv_device_memory *mem;
VkResult result = VK_SUCCESS;
+ /* VK_ANDROID_native_buffer defines VkNativeBufferANDROID as an extension
+ * of VkImageCreateInfo. We abuse the struct by chaining it to
+ * VkMemoryAllocateInfo in the implementation of vkCreateImage.
+ */
+ const VkNativeBufferANDROID *gralloc_info = NULL;
+#ifdef ANDROID
+ gralloc_info = vk_find_struct_const(pAllocateInfo->pNext,
NATIVE_BUFFER_ANDROID);
+#endif
+
assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
/* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
- assert(pAllocateInfo->allocationSize > 0);
+ assert(gralloc_info || pAllocateInfo->allocationSize > 0);
+ assert(!gralloc_info || pAllocateInfo->allocationSize == 0);
/* The kernel relocation API has a limitation of a 32-bit delta value
* applied to the address before it is written which, in spite of it being
@@ -1495,7 +1505,31 @@ VkResult anv_AllocateMemory(
0, &mem->bo);
if (result != VK_SUCCESS)
goto fail;
- } else {
+ }
+#ifdef ANDROID
+ else if (gralloc_info) {
+ if (gralloc_info->handle->numFds != 1) {
+ result = vk_errorf(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR,
+ "VkNativeBufferANDROID::handle::numFds is %d, "
+ "expected 1", gralloc_info->handle->numFds);
+ goto fail;
+ }
+
+ int dma_buf = gralloc_info->handle->data[0];
+
+ /* Do not close the gralloc handle's dma_buf fd. The lifetime of the
+ * dma_buf fd must exceed that of the gralloc handle, and we do not own
+ * the gralloc handle.
+ */
+ result = anv_bo_cache_import(device, &device->bo_cache, dma_buf, -1,
+ ANV_BO_CACHE_IMPORT_NO_CLOSE_FD
+ | ANV_BO_CACHE_IMPORT_IGNORE_SIZE_PARAM,
+ &mem->bo);
+ if (result != VK_SUCCESS)
+ goto fail;
+ }
+#endif
+ else {
result = anv_bo_cache_alloc(device, &device->bo_cache,
pAllocateInfo->allocationSize,
&mem->bo);
diff --git a/src/intel/vulkan/anv_entrypoints_gen.py
b/src/intel/vulkan/anv_entrypoints_gen.py
index 983be09a39b..dcdde31cdd7 100644
--- a/src/intel/vulkan/anv_entrypoints_gen.py
+++ b/src/intel/vulkan/anv_entrypoints_gen.py
@@ -271,7 +271,15 @@ def get_entrypoints(doc, entrypoints_to_defines,
start_index):
if extension.attrib['name'] not in supported:
continue
- assert extension.attrib['supported'] == 'vulkan'
+ # Workaround VK_ANDROID_native_buffer. In vk.xml, it's listed as
+ # supported="disabled", but we patch it to supported="vulkan" in our
+ # custom vk_android_native_buffer.xml.
+ assert (extension.attrib['supported'] == 'vulkan' or
+ extension.attrib['name'] == 'VK_ANDROID_native_buffer')
+
+ if extension.attrib['supported'] != 'vulkan':
+ continue
+
for command in extension.findall('./require/command'):
enabled_commands.add(command.attrib['name'])
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 6cd0c3692b6..18062359d31 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -50,6 +50,7 @@ class Extension:
# the those extension strings, then tests dEQP-VK.api.info.instance.extensions
# and dEQP-VK.api.info.device fail due to the duplicated strings.
EXTENSIONS = [
+ Extension('VK_ANDROID_native_buffer', 5, 'ANDROID'),
Extension('VK_KHR_dedicated_allocation', 1, True),
Extension('VK_KHR_descriptor_update_template', 1, True),
Extension('VK_KHR_external_fence', 1,
diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c
index 1cc3adae5ee..1b8bb363a17 100644
--- a/src/intel/vulkan/anv_image.c
+++ b/src/intel/vulkan/anv_image.c
@@ -32,6 +32,11 @@
#include "util/debug.h"
#include "vk_format_info.h"
+#include "vk_util.h"
+
+static void
+add_fast_clear_state_buffer(struct anv_image *image,
+ const struct anv_device *device);
static void
add_fast_clear_state_buffer(struct anv_image *image,
@@ -111,7 +116,9 @@ get_surface(struct anv_image *image, VkImageAspectFlags
aspect)
}
static VkResult
-choose_isl_tiling_flags(const struct anv_image_create_info *anv_info,
+choose_isl_tiling_flags(struct anv_device *device,
+ const struct anv_image_create_info *anv_info,
+ const VkNativeBufferANDROID *gralloc_info,
isl_tiling_flags_t *restrict flags)
{
*flags = ISL_TILING_ANY_MASK;
@@ -122,6 +129,41 @@ choose_isl_tiling_flags(const struct anv_image_create_info
*anv_info,
if (anv_info->isl_tiling_flags)
*flags &= anv_info->isl_tiling_flags;
+#if defined(ANDROID)
+ if (gralloc_info) {
+ int dma_buf = gralloc_info->handle->data[0];
+
+ uint32_t gem_handle = anv_gem_fd_to_handle(device, dma_buf);
+ if (gem_handle == 0) {
+ return vk_errorf(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR,
+ "DRM_IOCTL_PRIME_FD_TO_HANDLE failed for "
+ "VkNativeBufferANDROID");
+ }
+
+ int i915_tiling = anv_gem_get_tiling(device, gem_handle);
+ switch (i915_tiling) {
+ case I915_TILING_NONE:
+ *flags &= ISL_TILING_LINEAR_BIT;
+ break;
+ case I915_TILING_X:
+ *flags &= ISL_TILING_X_BIT;
+ break;
+ case I915_TILING_Y:
+ *flags &= ISL_TILING_Y0_BIT;
+ break;
+ case -1:
+ return vk_errorf(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR,
+ "DRM_IOCTL_I915_GEM_GET_TILING failed for "
+ "VkNativeBufferANDROID");
+ default:
+ return vk_errorf(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR,
+ "DRM_IOCTL_I915_GEM_GET_TILING returned unknown "
+ "tiling %d for VkNativeBufferANDROID", i915_tiling);
+
+ }
+ }
+#endif
+
return VK_SUCCESS;
}
@@ -245,9 +287,13 @@ try_make_mcs_surface(const struct anv_device *dev,
static VkResult
try_make_aux_surface(const struct anv_device *dev,
const VkImageCreateInfo *base_info,
+ const VkNativeBufferANDROID *gralloc_info,
VkImageAspectFlags aspect,
struct anv_image *image)
{
+ if (gralloc_info)
+ return VK_SUCCESS;
+
if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
try_make_hiz_surface(dev, base_info, image);
} else if (aspect == VK_IMAGE_ASPECT_COLOR_BIT &&
@@ -344,8 +390,9 @@ add_fast_clear_state_buffer(struct anv_image *image,
* Exactly one bit must be set in \a aspect.
*/
static VkResult
-make_main_surface(const struct anv_device *dev,
+make_main_surface(struct anv_device *dev,
const struct anv_image_create_info *anv_info,
+ const VkNativeBufferANDROID *gralloc_info,
VkImageAspectFlags aspect,
struct anv_image *image)
{
@@ -360,7 +407,8 @@ make_main_surface(const struct anv_device *dev,
};
isl_tiling_flags_t tiling_flags;
- result = choose_isl_tiling_flags(anv_info, &tiling_flags);
+ result = choose_isl_tiling_flags(dev, anv_info, gralloc_info,
+ &tiling_flags);
if (result != VK_SUCCESS)
return result;
@@ -373,6 +421,19 @@ make_main_surface(const struct anv_device *dev,
aspect, base_info->tiling);
assert(format != ISL_FORMAT_UNSUPPORTED);
+ uint32_t row_pitch = anv_info->stride;
+#ifdef ANDROID
+ if (gralloc_info) {
+ row_pitch = gralloc_info->stride *
+ (isl_format_get_layout(format)->bpb / 8);
+ }
+#endif
+
+ isl_surf_usage_flags_t usage =
+ choose_isl_surf_usage(base_info->flags, image->usage, aspect);
+ if (gralloc_info)
+ usage |= ISL_SURF_USAGE_DISABLE_AUX_BIT;
+
ok = isl_surf_init(&dev->isl_dev, &anv_surf->isl,
.dim = vk_to_isl_surf_dim[base_info->imageType],
.format = format,
@@ -383,8 +444,8 @@ 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,
- .usage = choose_isl_surf_usage(base_info->flags, image->usage, aspect),
+ .row_pitch = row_pitch,
+ .usage = usage,
.tiling_flags = tiling_flags);
/* isl_surf_init() will fail only if provided invalid input. Invalid input
@@ -393,9 +454,50 @@ make_main_surface(const struct anv_device *dev,
assert(ok);
add_surface(image, anv_surf);
+
+ if (gralloc_info)
+ assert(anv_surf->offset == 0);
+
return VK_SUCCESS;
}
+#ifdef ANDROID
+static VkResult
+import_gralloc(struct anv_device *device,
+ struct anv_image *image,
+ const VkNativeBufferANDROID *gralloc_info,
+ const VkAllocationCallbacks *alloc)
+{
+ VkDevice device_h = anv_device_to_handle(device);
+ VkDeviceMemory mem_h = VK_NULL_HANDLE;
+ VkResult result;
+
+ /* VK_ANDROID_native_buffer defines VkNativeBufferANDROID as an extension
+ * of VkImageCreateInfo. We abuse the struct by chaining it to
+ * VkMemoryAllocateInfo.
+ */
+ result = anv_AllocateMemory(device_h,
+ &(VkMemoryAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .pNext = gralloc_info,
+ .allocationSize = 0,
+ .memoryTypeIndex = 0, /* XXX: Arbitrary memory type */
+ },
+ alloc,
+ &mem_h);
+
+ if (result != VK_SUCCESS)
+ return result;
+
+ ANV_FROM_HANDLE(anv_device_memory, mem, mem_h);
+ image->mem = mem;
+ image->mem_offset = 0;
+ image->mem_is_owned = true;
+
+ return VK_SUCCESS;
+}
+#endif
+
VkResult
anv_image_create(VkDevice _device,
const struct anv_image_create_info *anv_info,
@@ -404,6 +506,8 @@ anv_image_create(VkDevice _device,
{
ANV_FROM_HANDLE(anv_device, device, _device);
const VkImageCreateInfo *base_info = anv_info->vk_info;
+ const VkNativeBufferANDROID *gralloc_info =
+ vk_find_struct_const(base_info->pNext, NATIVE_BUFFER_ANDROID);
struct anv_image *image = NULL;
VkResult r;
@@ -432,21 +536,30 @@ anv_image_create(VkDevice _device,
image->tiling = base_info->tiling;
image->aux_usage = ISL_AUX_USAGE_NONE;
+#ifdef ANDROID
+ if (gralloc_info) {
+ r = import_gralloc(device, image, gralloc_info, alloc);
+ if (r != VK_SUCCESS)
+ goto fail;
+ }
+#endif
+
uint32_t b;
for_each_bit(b, image->aspects) {
VkImageAspectFlagBits aspect = 1 << b;
- r = make_main_surface(device, anv_info, aspect, image);
+ r = make_main_surface(device, anv_info, gralloc_info, aspect, image);
if (r != VK_SUCCESS)
goto fail;
- r = try_make_aux_surface(device, base_info, aspect, image);
+ r = try_make_aux_surface(device, base_info, gralloc_info, aspect, image);
if (r != VK_SUCCESS)
goto fail;
}
- *pImage = anv_image_to_handle(image);
+ VkImage image_h = anv_image_to_handle(image);
+ *pImage = image_h;
return VK_SUCCESS;
fail:
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index d11a2363d9b..dafc37247f5 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -71,6 +71,7 @@ struct gen_l3_config;
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_intel.h>
#include <vulkan/vk_icd.h>
+#include <vulkan/vk_android_native_buffer.h>
#include "anv_entrypoints.h"
#include "isl/isl.h"