|  | /// Copyright (C) 2019 The Android Open Source Project | 
|  | // Copyright (C) 2019 Google Inc. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | // http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | #include "AndroidHardwareBuffer.h" | 
|  |  | 
|  | #include "gralloc_cb.h" | 
|  | #include "vk_format_info.h" | 
|  | #include "vk_util.h" | 
|  |  | 
|  | namespace goldfish_vk { | 
|  |  | 
|  | // From Intel ANV implementation. | 
|  | /* Construct ahw usage mask from image usage bits, see | 
|  | * 'AHardwareBuffer Usage Equivalence' in Vulkan spec. | 
|  | */ | 
|  | uint64_t | 
|  | getAndroidHardwareBufferUsageFromVkUsage(const VkImageCreateFlags vk_create, | 
|  | const VkImageUsageFlags vk_usage) | 
|  | { | 
|  | uint64_t ahw_usage = 0; | 
|  |  | 
|  | if (vk_usage & VK_IMAGE_USAGE_SAMPLED_BIT) | 
|  | ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; | 
|  |  | 
|  | if (vk_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) | 
|  | ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; | 
|  |  | 
|  | if (vk_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) | 
|  | ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; | 
|  |  | 
|  | if (vk_create & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) | 
|  | ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP; | 
|  |  | 
|  | if (vk_create & VK_IMAGE_CREATE_PROTECTED_BIT) | 
|  | ahw_usage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT; | 
|  |  | 
|  | /* No usage bits set - set at least one GPU usage. */ | 
|  | if (ahw_usage == 0) | 
|  | ahw_usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; | 
|  |  | 
|  | return ahw_usage; | 
|  | } | 
|  |  | 
|  | VkResult getAndroidHardwareBufferPropertiesANDROID( | 
|  | const HostVisibleMemoryVirtualizationInfo* hostMemVirtInfo, | 
|  | VkDevice, | 
|  | const AHardwareBuffer* buffer, | 
|  | VkAndroidHardwareBufferPropertiesANDROID* pProperties) { | 
|  |  | 
|  | VkAndroidHardwareBufferFormatPropertiesANDROID* ahbFormatProps = | 
|  | vk_find_struct<VkAndroidHardwareBufferFormatPropertiesANDROID>(pProperties); | 
|  |  | 
|  | if (ahbFormatProps) { | 
|  | AHardwareBuffer_Desc desc; | 
|  | AHardwareBuffer_describe(buffer, &desc); | 
|  |  | 
|  | const uint64_t gpu_usage = | 
|  | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | | 
|  | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | | 
|  | AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; | 
|  |  | 
|  | if (!(desc.usage & (gpu_usage))) { | 
|  | return VK_ERROR_INVALID_EXTERNAL_HANDLE; | 
|  | } | 
|  |  | 
|  | ahbFormatProps->format = vk_format_from_android(desc.format); | 
|  | ahbFormatProps->externalFormat = desc.format; | 
|  |  | 
|  | // The formatFeatures member must include | 
|  | // VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT and at least one of | 
|  | // VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or | 
|  | // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, and should include | 
|  | // VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT and | 
|  | // VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT. | 
|  |  | 
|  | ahbFormatProps->formatFeatures = | 
|  | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | | 
|  | VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT; | 
|  |  | 
|  | // "Implementations may not always be able to determine the color model, | 
|  | // numerical range, or chroma offsets of the image contents, so the values in | 
|  | // VkAndroidHardwareBufferFormatPropertiesANDROID are only suggestions. | 
|  | // Applications should treat these values as sensible defaults to use in the | 
|  | // absence of more reliable information obtained through some other means." | 
|  |  | 
|  | ahbFormatProps->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_IDENTITY; | 
|  | ahbFormatProps->samplerYcbcrConversionComponents.g = VK_COMPONENT_SWIZZLE_IDENTITY; | 
|  | ahbFormatProps->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY; | 
|  | ahbFormatProps->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY; | 
|  |  | 
|  | ahbFormatProps->suggestedYcbcrModel = | 
|  | android_format_is_yuv(desc.format) ? | 
|  | VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 : | 
|  | VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; | 
|  | ahbFormatProps->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; | 
|  |  | 
|  | ahbFormatProps->suggestedXChromaOffset = VK_CHROMA_LOCATION_MIDPOINT; | 
|  | ahbFormatProps->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT; | 
|  | } | 
|  |  | 
|  | const native_handle_t *handle = | 
|  | AHardwareBuffer_getNativeHandle(buffer); | 
|  | const cb_handle_t* cb_handle = cb_handle_t::from(handle); | 
|  | if (!cb_handle) { | 
|  | return VK_ERROR_INVALID_EXTERNAL_HANDLE; | 
|  | } | 
|  |  | 
|  | uint32_t colorBufferHandle = cb_handle->hostHandle; | 
|  | if (!colorBufferHandle) { | 
|  | return VK_ERROR_INVALID_EXTERNAL_HANDLE; | 
|  | } | 
|  |  | 
|  | // Disallow host visible and noflags heaps for now | 
|  | // (hard to make actual dedicated allocs) | 
|  | uint32_t memoryTypeBits = 0; | 
|  | for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) { | 
|  | if (isNoFlagsMemoryTypeIndexForGuest(hostMemVirtInfo, i)) continue; | 
|  | if (isHostVisibleMemoryTypeIndexForGuest(hostMemVirtInfo, i)) continue; | 
|  | memoryTypeBits |= (1 << i); | 
|  | } | 
|  |  | 
|  | pProperties->memoryTypeBits = memoryTypeBits; | 
|  | pProperties->allocationSize = cb_handle->allocatedSize(); | 
|  |  | 
|  | return VK_SUCCESS; | 
|  | } | 
|  |  | 
|  | // Based on Intel ANV implementation. | 
|  | VkResult getMemoryAndroidHardwareBufferANDROID(struct AHardwareBuffer **pBuffer) { | 
|  |  | 
|  | /* Some quotes from Vulkan spec: | 
|  | * | 
|  | * "If the device memory was created by importing an Android hardware | 
|  | * buffer, vkGetMemoryAndroidHardwareBufferANDROID must return that same | 
|  | * Android hardware buffer object." | 
|  | * | 
|  | * "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID must | 
|  | * have been included in VkExportMemoryAllocateInfo::handleTypes when | 
|  | * memory was created." | 
|  | */ | 
|  |  | 
|  | if (!pBuffer) return VK_ERROR_OUT_OF_HOST_MEMORY; | 
|  | if (!(*pBuffer)) return VK_ERROR_OUT_OF_HOST_MEMORY; | 
|  |  | 
|  | AHardwareBuffer_acquire(*pBuffer); | 
|  | return VK_SUCCESS; | 
|  | } | 
|  |  | 
|  | VkResult importAndroidHardwareBuffer( | 
|  | const VkImportAndroidHardwareBufferInfoANDROID* info, | 
|  | struct AHardwareBuffer **importOut) { | 
|  |  | 
|  | if (!info || !info->buffer) { | 
|  | return VK_ERROR_INVALID_EXTERNAL_HANDLE; | 
|  | } | 
|  |  | 
|  | const native_handle_t *handle = | 
|  | AHardwareBuffer_getNativeHandle(info->buffer); | 
|  | const cb_handle_t* cb_handle = cb_handle_t::from(handle); | 
|  | if (!cb_handle) { | 
|  | return VK_ERROR_INVALID_EXTERNAL_HANDLE; | 
|  | } | 
|  |  | 
|  | uint32_t colorBufferHandle = cb_handle->hostHandle; | 
|  | if (!colorBufferHandle) { | 
|  | return VK_ERROR_INVALID_EXTERNAL_HANDLE; | 
|  | } | 
|  |  | 
|  | auto ahb = info->buffer; | 
|  |  | 
|  | AHardwareBuffer_acquire(ahb); | 
|  |  | 
|  | if (importOut) *importOut = ahb; | 
|  |  | 
|  | return VK_SUCCESS; | 
|  | } | 
|  |  | 
|  | VkResult createAndroidHardwareBuffer( | 
|  | bool hasDedicatedImage, | 
|  | bool hasDedicatedBuffer, | 
|  | const VkExtent3D& imageExtent, | 
|  | uint32_t imageLayers, | 
|  | VkFormat imageFormat, | 
|  | VkImageUsageFlags imageUsage, | 
|  | VkImageCreateFlags imageCreateFlags, | 
|  | VkDeviceSize bufferSize, | 
|  | VkDeviceSize allocationInfoAllocSize, | 
|  | struct AHardwareBuffer **out) { | 
|  |  | 
|  | uint32_t w = 0; | 
|  | uint32_t h = 1; | 
|  | uint32_t layers = 1; | 
|  | uint32_t format = 0; | 
|  | uint64_t usage = 0; | 
|  |  | 
|  | /* If caller passed dedicated information. */ | 
|  | if (hasDedicatedImage) { | 
|  | w = imageExtent.width; | 
|  | h = imageExtent.height; | 
|  | layers = imageLayers; | 
|  | format = android_format_from_vk(imageFormat); | 
|  | usage = getAndroidHardwareBufferUsageFromVkUsage(imageCreateFlags, imageUsage); | 
|  | } else if (hasDedicatedBuffer) { | 
|  | w = bufferSize; | 
|  | format = AHARDWAREBUFFER_FORMAT_BLOB; | 
|  | usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | | 
|  | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | | 
|  | AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; | 
|  | } else { | 
|  | w = allocationInfoAllocSize; | 
|  | format = AHARDWAREBUFFER_FORMAT_BLOB; | 
|  | usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | | 
|  | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | | 
|  | AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; | 
|  | } | 
|  |  | 
|  | struct AHardwareBuffer *ahw = NULL; | 
|  | struct AHardwareBuffer_Desc desc = { | 
|  | .width = w, | 
|  | .height = h, | 
|  | .layers = layers, | 
|  | .format = format, | 
|  | .usage = usage, | 
|  | }; | 
|  |  | 
|  | if (AHardwareBuffer_allocate(&desc, &ahw) != 0) { | 
|  | return VK_ERROR_OUT_OF_HOST_MEMORY; | 
|  | } | 
|  |  | 
|  | *out = ahw; | 
|  |  | 
|  | return VK_SUCCESS; | 
|  | } | 
|  |  | 
|  | } // namespace goldfish_vk |