#include "utils/vk_layer_utils.h"
#include <vulkan/vk_enum_string_helper.h>
#include "core_validation.h"
#include "state_tracker/image_state.h"
#include "state_tracker/sampler_state.h"
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
std::map<uint32_t, VkFormat> ahb_format_map_a2v = {
{ (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, VK_FORMAT_R8G8B8A8_UNORM },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM, VK_FORMAT_R8G8B8_UNORM },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16 },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, VK_FORMAT_R16G16B16A16_SFLOAT },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_D16_UNORM, VK_FORMAT_D16_UNORM },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_D24_UNORM, VK_FORMAT_X8_D24_UNORM_PACK32 },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_D32_FLOAT, VK_FORMAT_D32_SFLOAT },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT },
{ (uint32_t)AHARDWAREBUFFER_FORMAT_S8_UINT, VK_FORMAT_S8_UINT }
};
std::map<uint64_t, VkImageUsageFlags> ahb_usage_map_a2v = {
{ (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) },
{ (uint64_t)AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) },
{ (uint64_t)AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE, 0 },
{ (uint64_t)AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER, VK_IMAGE_USAGE_STORAGE_BIT },
};
std::map<uint64_t, VkImageCreateFlags> ahb_create_map_a2v = {
{ (uint64_t)AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT },
{ (uint64_t)AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT, VK_IMAGE_CREATE_PROTECTED_BIT },
{ (uint64_t)AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE, 0 },
};
std::map<VkImageUsageFlags, uint64_t> ahb_usage_map_v2a = {
{ VK_IMAGE_USAGE_SAMPLED_BIT, (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE },
{ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE },
{ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, (uint64_t)AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER },
{ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, (uint64_t)AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER },
{ VK_IMAGE_USAGE_STORAGE_BIT, (uint64_t)AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER },
};
std::map<VkImageCreateFlags, uint64_t> ahb_create_map_v2a = {
{ VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, (uint64_t)AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP },
{ VK_IMAGE_CREATE_PROTECTED_BIT, (uint64_t)AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT },
};
bool CoreChecks::PreCallValidateGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer *buffer,
VkAndroidHardwareBufferPropertiesANDROID *pProperties,
const ErrorObject &error_obj) const {
bool skip = false;
AHardwareBuffer_Desc ahb_desc;
AHardwareBuffer_describe(buffer, &ahb_desc);
uint32_t required_flags = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
if (0 == (ahb_desc.usage & required_flags)) {
skip |= LogError(
"VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884", device, error_obj.location.dot(Field::buffer),
"AHardwareBuffer_Desc.usage (0x%" PRIx64 ") does not have any AHARDWAREBUFFER_USAGE_GPU_* flags set. (AHB = %p).",
ahb_desc.usage, buffer);
}
return skip;
}
bool CoreChecks::PreCallValidateGetMemoryAndroidHardwareBufferANDROID(VkDevice device,
const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo,
struct AHardwareBuffer **pBuffer,
const ErrorObject &error_obj) const {
bool skip = false;
auto mem_info = Get<vvl::DeviceMemory>(pInfo->memory);
ASSERT_AND_RETURN_SKIP(mem_info);
if (!mem_info->IsExport() ||
(0 == (mem_info->export_handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID))) {
skip |= LogError("VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-handleTypes-01882", device,
error_obj.location.dot(Field::pInfo).dot(Field::memory),
"(%s) was not allocated for export, or the "
"export handleTypes (0x%" PRIx32
") did not contain VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
FormatHandle(pInfo->memory).c_str(), mem_info->export_handle_types);
}
const VkImage dedicated_image = mem_info->GetDedicatedImage();
if (dedicated_image != VK_NULL_HANDLE) {
auto image_state = Get<vvl::Image>(dedicated_image);
if (!image_state || (0 == (image_state->CountDeviceMemory(mem_info->VkHandle())))) {
const LogObjectList objlist(device, pInfo->memory, dedicated_image);
skip |= LogError("VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-01883", objlist,
error_obj.location.dot(Field::pInfo).dot(Field::memory),
"(%s) was allocated using a dedicated "
"%s, but that image is not bound to the VkDeviceMemory object.",
FormatHandle(pInfo->memory).c_str(), FormatHandle(dedicated_image).c_str());
}
}
return skip;
}
bool CoreChecks::ValidateAllocateMemoryANDROID(const VkMemoryAllocateInfo &allocate_info, const Location &allocate_info_loc) const {
bool skip = false;
auto import_ahb_info = vku::FindStructInPNextChain<VkImportAndroidHardwareBufferInfoANDROID>(allocate_info.pNext);
auto exp_mem_alloc_info = vku::FindStructInPNextChain<VkExportMemoryAllocateInfo>(allocate_info.pNext);
auto mem_ded_alloc_info = vku::FindStructInPNextChain<VkMemoryDedicatedAllocateInfo>(allocate_info.pNext);
if ((import_ahb_info) && (NULL != import_ahb_info->buffer)) {
const Location ahb_loc = allocate_info_loc.dot(Struct::VkImportAndroidHardwareBufferInfoANDROID, Field::buffer);
AHardwareBuffer_Desc ahb_desc = {};
AHardwareBuffer_describe(import_ahb_info->buffer, &ahb_desc);
if ((AHARDWAREBUFFER_FORMAT_BLOB != ahb_desc.format) || (0 == (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER))) {
uint64_t ahb_equiv_usage_bits = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
if (0 == (ahb_desc.usage & ahb_equiv_usage_bits)) {
skip |= LogError("VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881", device, ahb_loc,
"AHardwareBuffer_Desc's usage (0x%" PRIx64 ") is not compatible with Vulkan. (AHB = %p).",
ahb_desc.usage, import_ahb_info->buffer);
}
}
VkPhysicalDeviceExternalBufferInfo pdebi = vku::InitStructHelper();
pdebi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
if (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE & ahb_desc.usage) {
pdebi.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE];
}
if (AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER & ahb_desc.usage) {
pdebi.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER];
}
VkExternalBufferProperties ext_buf_props = vku::InitStructHelper();
DispatchGetPhysicalDeviceExternalBufferProperties(physical_device, &pdebi, &ext_buf_props);
if (0 == (ext_buf_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) {
VkPhysicalDeviceExternalImageFormatInfo pdeifi = vku::InitStructHelper();
pdeifi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
VkPhysicalDeviceImageFormatInfo2 pdifi2 = vku::InitStructHelper(&pdeifi);
if (0 < ahb_format_map_a2v.count(ahb_desc.format)) pdifi2.format = ahb_format_map_a2v[ahb_desc.format];
pdifi2.type = VK_IMAGE_TYPE_2D;
pdifi2.tiling = VK_IMAGE_TILING_OPTIMAL;
if (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE & ahb_desc.usage) {
pdifi2.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE];
}
if (AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER & ahb_desc.usage) {
pdifi2.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER];
}
if (AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP & ahb_desc.usage) {
pdifi2.flags |= ahb_create_map_a2v[AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP];
}
if (AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT & ahb_desc.usage) {
pdifi2.flags |= ahb_create_map_a2v[AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT];
}
VkExternalImageFormatProperties ext_img_fmt_props = vku::InitStructHelper();
VkImageFormatProperties2 ifp2 = vku::InitStructHelper(&ext_img_fmt_props);
VkResult fmt_lookup_result = DispatchGetPhysicalDeviceImageFormatProperties2Helper(physical_device, &pdifi2, &ifp2);
if ((VK_SUCCESS != fmt_lookup_result) || (0 == (ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures &
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT))) {
skip |= LogError(
"VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01880", device, allocate_info_loc,
"Neither the VkExternalImageFormatProperties nor the VkExternalBufferProperties "
"structs for the AHardwareBuffer include the VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT flag. (AHB = %p).",
import_ahb_info->buffer);
}
}
VkAndroidHardwareBufferPropertiesANDROID ahb_props = vku::InitStructHelper();
DispatchGetAndroidHardwareBufferPropertiesANDROID(device, import_ahb_info->buffer, &ahb_props);
if (allocate_info.allocationSize != ahb_props.allocationSize) {
skip |=
LogError("VUID-VkMemoryAllocateInfo-allocationSize-02383", device, allocate_info_loc.dot(Field::allocationSize),
"(%" PRIu64 ") does not match the %s AHardwareBuffer's allocationSize (%" PRIu64 "). (AHB = %p).",
allocate_info.allocationSize, ahb_loc.Fields().c_str(), ahb_props.allocationSize, import_ahb_info->buffer);
}
uint32_t mem_type_bitmask = 1 << allocate_info.memoryTypeIndex;
if (0 == (mem_type_bitmask & ahb_props.memoryTypeBits)) {
skip |= LogError(
"VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385", device, allocate_info_loc.dot(Field::memoryTypeIndex),
"(%" PRIu32
") does not correspond to a bit set in %s "
"AHardwareBuffer's memoryTypeBits bitmask (0x%" PRIx32 "). (AHB = %p).",
allocate_info.memoryTypeIndex, ahb_loc.Fields().c_str(), ahb_props.memoryTypeBits, import_ahb_info->buffer);
}
if ((nullptr == mem_ded_alloc_info) || (VK_NULL_HANDLE == mem_ded_alloc_info->image)) {
if (((uint64_t)AHARDWAREBUFFER_FORMAT_BLOB != ahb_desc.format) ||
(0 == (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER))) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-02384", device, ahb_loc,
"AHardwareBuffer_Desc's format ( %u ) is not "
"AHARDWAREBUFFER_FORMAT_BLOB or usage (0x%" PRIx64
") does not include AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER. (AHB = %p).",
ahb_desc.format, ahb_desc.usage, import_ahb_info->buffer);
}
} else {
if (0 == (ahb_desc.usage & (AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER))) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-02386", device, ahb_loc,
"AHardwareBuffer's usage is 0x%" PRIx64 ". (AHB = %p).", ahb_desc.usage, import_ahb_info->buffer);
}
auto image_state = Get<vvl::Image>(mem_ded_alloc_info->image);
ASSERT_AND_RETURN_SKIP(image_state);
const auto *ici = &image_state->create_info;
const Location &dedicated_image_loc = allocate_info_loc.dot(Struct::VkMemoryDedicatedAllocateInfo, Field::image);
if (VK_FORMAT_UNDEFINED != ici->format) {
VkAndroidHardwareBufferFormatPropertiesANDROID ahb_format_props = vku::InitStructHelper();
VkAndroidHardwareBufferPropertiesANDROID dummy_ahb_props = vku::InitStructHelper(&ahb_format_props);
DispatchGetAndroidHardwareBufferPropertiesANDROID(device, import_ahb_info->buffer, &dummy_ahb_props);
if (ici->format != ahb_format_props.format) {
skip |= LogError(
"VUID-VkMemoryAllocateInfo-pNext-02387", mem_ded_alloc_info->image, dedicated_image_loc,
"was created with format (%s) which does not match the %s AHardwareBuffer's format (%s). (AHB = %p).",
string_VkFormat(ici->format), ahb_loc.Fields().c_str(), string_VkFormat(ahb_format_props.format),
import_ahb_info->buffer);
}
}
if ((ici->extent.width != ahb_desc.width) || (ici->extent.height != ahb_desc.height) ||
(ici->arrayLayers != ahb_desc.layers)) {
skip |=
LogError("VUID-VkMemoryAllocateInfo-pNext-02388", mem_ded_alloc_info->image, dedicated_image_loc,
"was created with width (%" PRId32 "), height (%" PRId32 "), and arrayLayers (%" PRId32
") which not match those of the %s AHardwareBuffer (%" PRId32 " %" PRId32 " %" PRId32 "). (AHB = %p).",
ici->extent.width, ici->extent.height, ici->arrayLayers, ahb_loc.Fields().c_str(), ahb_desc.width,
ahb_desc.height, ahb_desc.layers, import_ahb_info->buffer);
}
if ((ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE) != 0) {
if ((ici->mipLevels != 1) && (ici->mipLevels != FullMipChainLevels(ici->extent))) {
skip |= LogError(
"VUID-VkMemoryAllocateInfo-pNext-02389", mem_ded_alloc_info->image, ahb_loc,
"AHardwareBuffer_Desc's usage includes AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE but %s mipLevels (%" PRIu32
") is neither 1 nor full mip "
"chain levels (%" PRIu32 "). (AHB = %p).",
dedicated_image_loc.Fields().c_str(), ici->mipLevels, FullMipChainLevels(ici->extent),
import_ahb_info->buffer);
}
} else {
if (ici->mipLevels != 1) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-02586", mem_ded_alloc_info->image, ahb_loc,
"AHardwareBuffer_Desc's usage is 0x%" PRIx64 " but %s mipLevels is %" PRIu32 ". (AHB = %p).",
ahb_desc.usage, dedicated_image_loc.Fields().c_str(), ici->mipLevels, import_ahb_info->buffer);
}
}
if (ici->usage & ~(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
skip |= LogError(
"VUID-VkMemoryAllocateInfo-pNext-02390", mem_ded_alloc_info->image, dedicated_image_loc,
"usage bits (%s) include an issue not listed in the AHardwareBuffer Usage Equivalence table. (AHB = %p).",
string_VkImageUsageFlags(ici->usage).c_str(), import_ahb_info->buffer);
}
std::vector<VkImageUsageFlags> usages = {VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT};
for (VkImageUsageFlags ubit : usages) {
if (ici->usage & ubit) {
uint64_t ahb_usage = ahb_usage_map_v2a[ubit];
if (0 == (ahb_usage & ahb_desc.usage)) {
skip |=
LogError("VUID-VkMemoryAllocateInfo-pNext-02390", mem_ded_alloc_info->image, dedicated_image_loc,
" usage bit %s equivalent is not in AHardwareBuffer_Desc.usage (0x%" PRIx64 "). (AHB = %p).",
string_VkImageUsageFlags(ubit).c_str(), ahb_desc.usage, import_ahb_info->buffer);
}
}
}
}
} else {
if (exp_mem_alloc_info &&
(VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID & exp_mem_alloc_info->handleTypes)) {
if (mem_ded_alloc_info) {
if (mem_ded_alloc_info->image != VK_NULL_HANDLE && allocate_info.allocationSize != 0) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-01874", mem_ded_alloc_info->image,
allocate_info_loc.pNext(Struct::VkMemoryDedicatedAllocateInfo, Field::image),
"is %s but allocationSize is %" PRIu64 ".", FormatHandle(mem_ded_alloc_info->image).c_str(),
allocate_info.allocationSize);
}
if (mem_ded_alloc_info->buffer != VK_NULL_HANDLE && allocate_info.allocationSize == 0) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-07901", mem_ded_alloc_info->buffer,
allocate_info_loc.pNext(Struct::VkMemoryDedicatedAllocateInfo, Field::buffer),
"is %s but allocationSize is 0.", FormatHandle(mem_ded_alloc_info->buffer).c_str());
}
} else if (0 == allocate_info.allocationSize) {
skip |= LogError("VUID-VkMemoryAllocateInfo-pNext-07900", device, allocate_info_loc,
"pNext chain does not include VkMemoryDedicatedAllocateInfo, but allocationSize is 0.");
}
}
}
return skip;
}
bool CoreChecks::ValidateGetImageMemoryRequirementsANDROID(const VkImage image, const Location &loc) const {
bool skip = false;
if (auto image_state = Get<vvl::Image>(image)) {
if (image_state->IsExternalBuffer() && (0 == image_state->GetBoundMemoryStates().size())) {
const char *vuid = loc.function == Func::vkGetImageMemoryRequirements
? "VUID-vkGetImageMemoryRequirements-image-04004"
: "VUID-VkImageMemoryRequirementsInfo2-image-01897";
skip |= LogError(vuid, image, loc,
"was created with a VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType, "
"which has not yet been "
"bound to memory, so image memory requirements can't yet be queried.");
}
}
return skip;
}
bool CoreChecks::ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
const VkImageFormatProperties2 *pImageFormatProperties,
const ErrorObject &error_obj) const {
bool skip = false;
const auto *ahb_usage = vku::FindStructInPNextChain<VkAndroidHardwareBufferUsageANDROID>(pImageFormatProperties->pNext);
if (ahb_usage) {
const auto *pdeifi = vku::FindStructInPNextChain<VkPhysicalDeviceExternalImageFormatInfo>(pImageFormatInfo->pNext);
if ((!pdeifi) || (VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID != pdeifi->handleType)) {
skip |= LogError("VUID-vkGetPhysicalDeviceImageFormatProperties2-pNext-01868", physical_device,
error_obj.location.dot(Field::pImageFormatProperties),
"includes a chained "
"VkAndroidHardwareBufferUsageANDROID struct, but pImageFormatInfo does not include a chained "
"VkPhysicalDeviceExternalImageFormatInfo struct with handleType "
"VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.");
}
}
return skip;
}
bool CoreChecks::ValidateBufferImportedHandleANDROID(VkExternalMemoryHandleTypeFlags handle_types, VkDeviceMemory memory,
VkBuffer buffer, const Location &loc) const {
bool skip = false;
if ((handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) == 0) {
const char *vuid = loc.function == Func::vkBindBufferMemory ? "VUID-vkBindBufferMemory-memory-02986"
: "VUID-VkBindBufferMemoryInfo-memory-02986";
const LogObjectList objlist(buffer, memory);
skip |= LogError(vuid, objlist, loc.dot(Field::memory),
"(%s) was created with an AHB import operation which is not set "
"VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID in the VkBuffer (%s) "
"VkExternalMemoryBufferCreateInfo::handleTypes (%s)",
FormatHandle(memory).c_str(), FormatHandle(buffer).c_str(),
string_VkExternalMemoryHandleTypeFlags(handle_types).c_str());
}
return skip;
}
bool CoreChecks::ValidateImageImportedHandleANDROID(VkExternalMemoryHandleTypeFlags handle_types, VkDeviceMemory memory,
VkImage image, const Location &loc) const {
bool skip = false;
if ((handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) == 0) {
const char *vuid = loc.function == Func::vkBindImageMemory ? "VUID-vkBindImageMemory-memory-02990"
: "VUID-VkBindImageMemoryInfo-memory-02990";
const LogObjectList objlist(image, memory);
skip |= LogError(vuid, objlist, loc.dot(Field::memory),
"(%s) was created with an AHB import operation which is not set "
"VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID in the VkImage (%s) "
"VkExternalMemoryImageCreateInfo::handleTypes (%s)",
FormatHandle(memory).c_str(), FormatHandle(image).c_str(),
string_VkExternalMemoryHandleTypeFlags(handle_types).c_str());
}
return skip;
}
bool CoreChecks::ValidateCreateImageANDROID(const VkImageCreateInfo &create_info, const Location &create_info_loc) const {
bool skip = false;
const VkExternalFormatANDROID *ext_fmt_android = vku::FindStructInPNextChain<VkExternalFormatANDROID>(create_info.pNext);
if (ext_fmt_android && (0 != ext_fmt_android->externalFormat)) {
if (VK_FORMAT_UNDEFINED != create_info.format) {
skip |= LogError("VUID-VkImageCreateInfo-pNext-01974", device,
create_info_loc.pNext(Struct::VkExternalFormatANDROID, Field::externalFormat),
"(%" PRIu64 ") is non-zero, format is %s.", ext_fmt_android->externalFormat,
string_VkFormat(create_info.format));
}
if (0 != (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT & create_info.flags)) {
skip |= LogError("VUID-VkImageCreateInfo-pNext-02396", device,
create_info_loc.pNext(Struct::VkExternalFormatANDROID, Field::externalFormat),
"(%" PRIu64 ") is non-zero, but flags is %s.", ext_fmt_android->externalFormat,
string_VkImageCreateFlags(create_info.flags).c_str());
}
if (0 != (~(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &
create_info.usage)) {
skip |= LogError("VUID-VkImageCreateInfo-pNext-02397", device,
create_info_loc.pNext(Struct::VkExternalFormatANDROID, Field::externalFormat),
"(%" PRIu64 ") is non-zero, but usage is %s.", ext_fmt_android->externalFormat,
string_VkImageUsageFlags(create_info.usage).c_str());
} else if (!enabled_features.externalFormatResolve &&
((VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) & create_info.usage)) {
skip |= LogError(
"VUID-VkImageCreateInfo-pNext-09457", device,
create_info_loc.pNext(Struct::VkExternalFormatANDROID, Field::externalFormat),
"(%" PRIu64
") is non-zero, but usage is %s (without externalFormatResolve, only VK_IMAGE_USAGE_SAMPLED_BIT is allowed).",
ext_fmt_android->externalFormat, string_VkImageUsageFlags(create_info.usage).c_str());
}
if (VK_IMAGE_TILING_OPTIMAL != create_info.tiling) {
skip |= LogError("VUID-VkImageCreateInfo-pNext-02398", device,
create_info_loc.pNext(Struct::VkExternalFormatANDROID, Field::externalFormat),
"(%" PRIu64 ") is non-zero, but layout is %s.", ext_fmt_android->externalFormat,
string_VkImageTiling(create_info.tiling));
}
if (ahb_ext_formats_map.find(ext_fmt_android->externalFormat) == ahb_ext_formats_map.end()) {
skip |= LogError("VUID-VkExternalFormatANDROID-externalFormat-01894", device,
create_info_loc.pNext(Struct::VkExternalFormatANDROID, Field::externalFormat),
"(%" PRIu64 ") has not been previously retrieved by vkGetAndroidHardwareBufferPropertiesANDROID().",
ext_fmt_android->externalFormat);
}
}
if ((nullptr == ext_fmt_android) || (0 == ext_fmt_android->externalFormat)) {
if (VK_FORMAT_UNDEFINED == create_info.format) {
if (ext_fmt_android) {
skip |= LogError("VUID-VkImageCreateInfo-pNext-01975", device, create_info_loc.dot(Field::format),
"is VK_FORMAT_UNDEFINED, but the chained VkExternalFormatANDROID has an externalFormat of 0.");
} else {
skip |= LogError("VUID-VkImageCreateInfo-pNext-01975", device, create_info_loc.dot(Field::format),
"is VK_FORMAT_UNDEFINED, but does not have a chained VkExternalFormatANDROID struct.");
}
}
}
const VkExternalMemoryImageCreateInfo *emici = vku::FindStructInPNextChain<VkExternalMemoryImageCreateInfo>(create_info.pNext);
if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
if (create_info.imageType != VK_IMAGE_TYPE_2D) {
skip |= LogError("VUID-VkImageCreateInfo-pNext-02393", device,
create_info_loc.pNext(Struct::VkExternalMemoryImageCreateInfo, Field::handleTypes),
"includes VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, but imageType is %s.",
string_VkImageType(create_info.imageType));
}
if ((create_info.mipLevels != 1) && (create_info.mipLevels != FullMipChainLevels(create_info.extent))) {
skip |= LogError("VUID-VkImageCreateInfo-pNext-02394", device,
create_info_loc.pNext(Struct::VkExternalMemoryImageCreateInfo, Field::handleTypes),
"includes VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, "
"but mipLevels is %" PRIu32 " (full chain mipLevels are %" PRIu32 ").",
create_info.mipLevels, FullMipChainLevels(create_info.extent));
}
}
return skip;
}
bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo &create_info, const Location &create_info_loc) const {
bool skip = false;
auto image_state = Get<vvl::Image>(create_info.image);
ASSERT_AND_RETURN_SKIP(image_state);
if (image_state->HasAHBFormat()) {
if (VK_FORMAT_UNDEFINED != create_info.format) {
skip |= LogError("VUID-VkImageViewCreateInfo-image-02399", create_info.image, create_info_loc.dot(Field::format),
"is %s (not VK_FORMAT_UNDEFINED) but the VkImageViewCreateInfo struct has a chained "
"VkExternalFormatANDROID struct.",
string_VkFormat(create_info.format));
}
bool conv_found = false;
uint64_t external_format = 0;
const VkSamplerYcbcrConversionInfo *ycbcr_conv_info =
vku::FindStructInPNextChain<VkSamplerYcbcrConversionInfo>(create_info.pNext);
if (ycbcr_conv_info != nullptr) {
if (auto ycbcr_state = Get<vvl::SamplerYcbcrConversion>(ycbcr_conv_info->conversion)) {
conv_found = true;
external_format = ycbcr_state->external_format;
}
}
if (!conv_found) {
const LogObjectList objlist(create_info.image);
skip |= LogError("VUID-VkImageViewCreateInfo-image-02400", objlist,
create_info_loc.pNext(Struct::VkSamplerYcbcrConversionInfo, Field::conversion),
"is not valid (or forgot to add VkSamplerYcbcrConversionInfo).");
} else if ((external_format != image_state->ahb_format)) {
const LogObjectList objlist(create_info.image, ycbcr_conv_info->conversion);
skip |= LogError("VUID-VkImageViewCreateInfo-image-02400", objlist,
create_info_loc.pNext(Struct::VkSamplerYcbcrConversionInfo, Field::conversion),
"(%s) was created with externalFormat (%" PRIu64
") which is different then image chain VkExternalFormatANDROID::externalFormat (%" PRIu64 ").",
FormatHandle(ycbcr_conv_info->conversion).c_str(), external_format, image_state->ahb_format);
}
if (IsIdentitySwizzle(create_info.components) == false) {
skip |= LogError(
"VUID-VkImageViewCreateInfo-image-02401", create_info.image, create_info_loc.dot(Field::image),
"was chained with a VkExternalFormatANDROID struct, but "
"includes one or more non-identity component swizzles, r swizzle = %s, g swizzle = %s, b swizzle = %s, a swizzle "
"= %s.",
string_VkComponentSwizzle(create_info.components.r), string_VkComponentSwizzle(create_info.components.g),
string_VkComponentSwizzle(create_info.components.b), string_VkComponentSwizzle(create_info.components.a));
}
}
return skip;
}
#else
bool CoreChecks::ValidateAllocateMemoryANDROID(const VkMemoryAllocateInfo &allocate_info, const Location &allocate_info_loc) const { … }
bool CoreChecks::ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
const VkImageFormatProperties2 *pImageFormatProperties,
const ErrorObject &error_obj) const { … }
bool CoreChecks::ValidateGetImageMemoryRequirementsANDROID(const VkImage image, const Location &loc) const { … }
bool CoreChecks::ValidateBufferImportedHandleANDROID(VkExternalMemoryHandleTypeFlags handle_types, VkDeviceMemory memory,
VkBuffer buffer, const Location &loc) const { … }
bool CoreChecks::ValidateImageImportedHandleANDROID(VkExternalMemoryHandleTypeFlags handle_types, VkDeviceMemory memory,
VkImage image, const Location &loc) const { … }
bool CoreChecks::ValidateCreateImageANDROID(const VkImageCreateInfo &create_info, const Location &create_info_loc) const { … }
bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo &create_info, const Location &create_info_loc) const { … }
#endif