Update SwiftShader VK AHB to support generic gralloc
... by only using the AHardwareBuffer_* functions which will
use the device's gralloc implementation.
Note: this change does not fix the 5 existing deqp failures
in the suballocated.* tests that are mentioned in b/169796031.
Note: ANGLE doesn't seem to have support for
VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM yet: b/171302758.
Bug: b/141698760
Bug: b/147316305
Test: launch_cvd && cts -m CtsDeqpTestCases
dEQP-VK.api.external.memory.android_hardware_buffer.*
Change-Id: Ia551e78198c20d6c40ffa9448418f73829da1880
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/49248
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Jason Macnak <natsu@google.com>
Reviewed-by: Trevor Black <vantablack@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Android.bp b/src/Android.bp
index 026e23c..1f9f5fa 100644
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -56,7 +56,6 @@
shared_libs: [
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
- "libdrm",
"libnativewindow",
"libhardware",
"libhidlbase",
@@ -591,7 +590,6 @@
shared_libs: [
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
- "libdrm",
"libnativewindow",
"libhardware",
"libhidlbase",
@@ -664,8 +662,6 @@
include_dirs: [
"external/swiftshader/third_party/SPIRV-Headers/include",
"external/swiftshader/include",
- "external/minigbm",
- "external/libdrm"
],
}
diff --git a/src/Vulkan/VkBuffer.hpp b/src/Vulkan/VkBuffer.hpp
index 2aa59fc..fd95fe2 100644
--- a/src/Vulkan/VkBuffer.hpp
+++ b/src/Vulkan/VkBuffer.hpp
@@ -41,6 +41,9 @@
uint8_t *end() const;
bool canBindToMemory(DeviceMemory *pDeviceMemory) const;
+ VkBufferUsageFlags getUsage() const { return usage; }
+ VkBufferCreateFlags getFlags() const { return flags; }
+
private:
void *memory = nullptr;
VkBufferCreateFlags flags = 0;
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index cc0a359..4cdca03 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -146,10 +146,6 @@
debugger.server = vk::dbg::Server::create(debugger.context, atoi(port));
}
#endif // ENABLE_VK_DEBUGGER
-
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
- ahbAddressMap.reset(new AHBAddressMap());
-#endif
}
void Device::destroy(const VkAllocationCallbacks *pAllocator)
@@ -379,60 +375,4 @@
}
}
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-Device::AHBAddressMap *Device::getAHBAddressMap() const
-{
- return ahbAddressMap.get();
-}
-
-void *Device::AHBAddressMap::query(const uint32_t key)
-{
- std::unique_lock<std::mutex> lock(addressMapMutex);
- if(addressMap.find(key) == addressMap.end())
- return nullptr;
-
- return addressMap[key].address;
-}
-
-void Device::AHBAddressMap::add(const uint32_t key, void *value)
-{
- std::unique_lock<std::mutex> lock(addressMapMutex);
- auto it = addressMap.find(key);
- if(it == addressMap.end())
- {
- MapValue mv;
- mv.refCount = 1;
- mv.address = value;
- addressMap[key] = mv;
- }
- else
- {
- it->second.address = value;
- it->second.refCount++;
- }
-}
-
-int Device::AHBAddressMap::incrementReference(const uint32_t key)
-{
- std::unique_lock<std::mutex> lock(addressMapMutex);
- auto it = addressMap.find(key);
- if(it == addressMap.end())
- return -1;
-
- it->second.refCount++;
- return it->second.refCount;
-}
-
-int Device::AHBAddressMap::decrementReference(const uint32_t key)
-{
- std::unique_lock<std::mutex> lock(addressMapMutex);
- auto it = addressMap.find(key);
- if(it == addressMap.end())
- return -1;
-
- it->second.refCount--;
- return it->second.refCount;
-}
-#endif // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-
} // namespace vk
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 9fce601..7f67ffa 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -193,41 +193,6 @@
std::shared_ptr<vk::dbg::Server> server;
} debugger;
#endif // ENABLE_VK_DEBUGGER
-
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-public:
- class AHBAddressMap
- {
- public:
- AHBAddressMap() {}
- ~AHBAddressMap() {}
-
- struct MapValue
- {
- MapValue()
- : refCount(0)
- , address(nullptr)
- {
- }
- int refCount;
- void *address;
- };
-
- void *query(const uint32_t key);
- int incrementReference(const uint32_t key);
- int decrementReference(const uint32_t key);
- void add(const uint32_t key, void *value);
-
- private:
- std::map<uint32_t, MapValue> addressMap;
- std::mutex addressMapMutex;
- };
-
- AHBAddressMap *getAHBAddressMap() const;
-
-private:
- std::unique_ptr<AHBAddressMap> ahbAddressMap;
-#endif
};
using DispatchableDevice = DispatchableObject<Device, VkDevice>;
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
index 8890829..80e3250 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
@@ -16,159 +16,19 @@
# include "VkDeviceMemoryExternalAndroid.hpp"
+# include "System/Debug.hpp"
# include "VkDestroy.hpp"
-# include "VkDevice.hpp"
# include "VkFormat.hpp"
# include "VkObject.hpp"
# include "VkPhysicalDevice.hpp"
-
-# include "System/Debug.hpp"
-# include "System/Linux/MemFd.hpp"
-# include <sys/mman.h>
+# include "VkStringify.hpp"
# include <android/hardware_buffer.h>
-# include <cutils/native_handle.h>
# include <vndk/hardware_buffer.h>
-# include <cros_gralloc/cros_gralloc_handle.h>
-# include <external/virgl_hw.h>
-# include <unistd.h>
-# include <virtgpu_drm.h>
-# include <xf86drm.h>
+namespace {
-AHardwareBufferExternalMemory::~AHardwareBufferExternalMemory()
-{
- // correct deallocation of AHB does not require a pointer or size
- deallocate(nullptr, 0);
-}
-
-VkResult AHardwareBufferExternalMemory::allocate(size_t size, void **pBuffer)
-{
- if(allocateInfo.importAhb)
- {
- ahb = allocateInfo.ahb;
- AHardwareBuffer_acquire(ahb);
- return allocateAndroidHardwareBuffer(size, pBuffer);
- }
- else
- {
- ASSERT(allocateInfo.exportAhb);
-
- // Outline ahbDesc
- AHardwareBuffer_Desc ahbDesc;
- if(allocateInfo.imageHandle)
- {
- ahbDesc.format = GetAndroidHardwareBufferDescFormat(VkFormat(allocateInfo.imageHandle->getFormat()));
- VkExtent3D extent = allocateInfo.imageHandle->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
- ahbDesc.width = extent.width;
- ahbDesc.height = extent.height;
- ahbDesc.layers = allocateInfo.imageHandle->getArrayLayers();
- ahbDesc.stride = allocateInfo.imageHandle->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
-
- VkImageCreateFlags createFlags = allocateInfo.imageHandle->getFlags();
- VkImageUsageFlags usageFlags = allocateInfo.imageHandle->getUsage();
- GetAndroidHardwareBufferUsageFromVkUsage(createFlags, usageFlags, ahbDesc.usage);
- }
- else
- {
- ASSERT(allocateInfo.bufferHandle);
- ahbDesc.format = AHARDWAREBUFFER_FORMAT_BLOB;
- ahbDesc.width = uint32_t(allocateInfo.bufferHandle->getSize());
- ahbDesc.height = 1;
- ahbDesc.layers = 1;
- ahbDesc.stride = uint32_t(allocateInfo.bufferHandle->getSize());
- // TODO(b/141698760)
- // This will be fairly specific, needs fleshing out
- ahbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
- }
-
- // create a new ahb from desc
- if(AHardwareBuffer_allocate(&ahbDesc, &ahb) != 0)
- {
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
-
- return allocateAndroidHardwareBuffer(size, pBuffer);
- }
-}
-
-VkResult AHardwareBufferExternalMemory::allocateAndroidHardwareBuffer(size_t size, void **pBuffer)
-{
- // get native_handle_t from ahb
- const native_handle_t *h = AHardwareBuffer_getNativeHandle(ahb);
- if(h == nullptr)
- {
- return VK_ERROR_INVALID_EXTERNAL_HANDLE;
- }
-
- // get rendernodeFD and primeHandle from native_handle_t.data
- uint32_t primeHandle;
- createRenderNodeFD();
- VkResult result = getPrimeHandle(h, primeHandle);
- if(result != VK_SUCCESS)
- {
- return result;
- }
-
- // get memory pointer from store or mmap it
- vk::Device::AHBAddressMap *pDeviceHandleMap = device->getAHBAddressMap();
- void *pAddress = pDeviceHandleMap->query(primeHandle);
- if(pAddress != nullptr)
- {
- *pBuffer = pAddress;
- pDeviceHandleMap->incrementReference(primeHandle);
- }
- else
- {
- // map memory
- void *ptr;
- VkResult result = mapMemory(primeHandle, &ptr);
- if(result != VK_SUCCESS)
- {
- return result;
- }
-
- // Add primeHandle and ptr to deviceHandleMap
- pDeviceHandleMap->add(primeHandle, ptr);
- *pBuffer = pDeviceHandleMap->query(primeHandle);
- }
-
- return VK_SUCCESS;
-}
-
-void AHardwareBufferExternalMemory::deallocate(void *buffer, size_t size)
-{
- if(ahb != nullptr)
- {
- const native_handle_t *h = AHardwareBuffer_getNativeHandle(ahb);
- uint32_t primeHandle;
- VkResult result = getPrimeHandle(h, primeHandle);
- ASSERT(result == VK_SUCCESS);
-
- // close gpu memory and rendernodeFD
- vk::Device::AHBAddressMap *pDeviceHandleMap = device->getAHBAddressMap();
- if(pDeviceHandleMap->decrementReference(primeHandle) == 0)
- {
- closeMemory(primeHandle);
- }
- close(rendernodeFD);
-
- AHardwareBuffer_release(ahb);
- ahb = nullptr;
- }
-}
-
-VkResult AHardwareBufferExternalMemory::exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const
-{
- // Each call to vkGetMemoryAndroidHardwareBufferANDROID *must* return an Android hardware buffer with a new reference
- // acquired in addition to the reference held by the VkDeviceMemory. To avoid leaking resources, the application *must*
- // release the reference by calling AHardwareBuffer_release when it is no longer needed.
- AHardwareBuffer_acquire(ahb);
- *pAhb = ahb;
- return VK_SUCCESS;
-}
-
-uint32_t AHardwareBufferExternalMemory::GetAndroidHardwareBufferDescFormat(VkFormat format)
+uint32_t GetAHBFormatFromVkFormat(VkFormat format)
{
switch(format)
{
@@ -204,7 +64,7 @@
}
}
-VkFormat AHardwareBufferExternalMemory::GetVkFormat(uint32_t ahbFormat)
+VkFormat GetVkFormatFromAHBFormat(uint32_t ahbFormat)
{
switch(ahbFormat)
{
@@ -244,8 +104,94 @@
}
}
-VkFormatFeatureFlags AHardwareBufferExternalMemory::GetVkFormatFeatures(VkFormat format)
+uint64_t GetAHBLockUsageFromVkImageUsageFlags(VkImageUsageFlags flags)
{
+ uint64_t usage = 0;
+
+ if(flags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT ||
+ flags & VK_IMAGE_USAGE_SAMPLED_BIT ||
+ flags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
+ {
+ usage |= AHARDWAREBUFFER_USAGE_CPU_READ_MASK;
+ }
+
+ if(flags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ||
+ flags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
+ {
+ usage |= AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK;
+ }
+
+ return usage;
+}
+
+uint64_t GetAHBLockUsageFromVkBufferUsageFlags(VkBufferUsageFlags flags)
+{
+ uint64_t usage = 0;
+
+ if(flags & VK_BUFFER_USAGE_TRANSFER_SRC_BIT)
+ {
+ usage |= AHARDWAREBUFFER_USAGE_CPU_READ_MASK;
+ }
+
+ if(flags & VK_BUFFER_USAGE_TRANSFER_DST_BIT)
+ {
+ usage |= AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK;
+ }
+
+ return usage;
+}
+
+uint64_t GetAHBUsageFromVkImageFlags(VkImageCreateFlags createFlags, VkImageUsageFlags usageFlags)
+{
+ uint64_t ahbUsage = 0;
+
+ if(usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT)
+ {
+ ahbUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
+ }
+ if(usageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)
+ {
+ ahbUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
+ }
+ if(usageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+ {
+ ahbUsage |= AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ }
+
+ if(createFlags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
+ {
+ ahbUsage |= AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
+ }
+ if(createFlags & VK_IMAGE_CREATE_PROTECTED_BIT)
+ {
+ ahbUsage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
+ }
+
+ // No usage bits set - set at least one GPU usage
+ if(ahbUsage == 0)
+ {
+ ahbUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ }
+
+ return ahbUsage;
+}
+
+uint64_t GetAHBUsageFromVkBufferFlags(VkBufferCreateFlags /*createFlags*/, VkBufferUsageFlags /*usageFlags*/)
+{
+ uint64_t ahbUsage = 0;
+
+ // TODO(b/141698760): needs fleshing out.
+ ahbUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+
+ return ahbUsage;
+}
+
+VkFormatFeatureFlags GetVkFormatFeaturesFromAHBFormat(uint32_t ahbFormat)
+{
+ VkFormatFeatureFlags features = 0;
+
+ VkFormat format = GetVkFormatFromAHBFormat(ahbFormat);
VkFormatProperties formatProperties;
vk::PhysicalDevice::GetFormatProperties(vk::Format(format), &formatProperties);
@@ -254,148 +200,14 @@
// TODO: b/167896057
// The correct formatFeatureFlags depends on consumer and format
// So this solution is incomplete without more information
- return formatProperties.linearTilingFeatures | formatProperties.optimalTilingFeatures | formatProperties.bufferFeatures;
+ features |= formatProperties.linearTilingFeatures |
+ formatProperties.optimalTilingFeatures |
+ formatProperties.bufferFeatures;
+
+ return features;
}
-VkResult AHardwareBufferExternalMemory::GetAndroidHardwareBufferFormatProperties(const AHardwareBuffer_Desc &ahbDesc, VkAndroidHardwareBufferFormatPropertiesANDROID *pFormat)
-{
-
- pFormat->sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
- pFormat->pNext = nullptr;
-
- pFormat->format = GetVkFormat(ahbDesc.format);
- pFormat->externalFormat = ahbDesc.format;
- pFormat->formatFeatures = GetVkFormatFeatures(pFormat->format);
-
- pFormat->samplerYcbcrConversionComponents = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
- pFormat->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
- pFormat->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
- pFormat->suggestedXChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
- pFormat->suggestedYChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
-
- return VK_SUCCESS;
-}
-
-VkResult AHardwareBufferExternalMemory::GetAndroidHardwareBufferProperties(VkDevice &device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
-{
- AHardwareBuffer_Desc ahbDesc;
- AHardwareBuffer_describe(buffer, &ahbDesc);
-
- GetAndroidHardwareBufferFormatProperties(ahbDesc, (VkAndroidHardwareBufferFormatPropertiesANDROID *)pProperties->pNext);
-
- const VkPhysicalDeviceMemoryProperties phyDeviceMemProps = vk::PhysicalDevice::GetMemoryProperties();
- pProperties->memoryTypeBits = phyDeviceMemProps.memoryTypes[0].propertyFlags;
-
- if(ahbDesc.format == AHARDWAREBUFFER_FORMAT_BLOB)
- {
- pProperties->allocationSize = ahbDesc.width;
- }
- else
- {
- VkImageCreateInfo info = {};
- info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
- info.pNext = nullptr;
- info.flags = 0;
- info.imageType = VK_IMAGE_TYPE_2D;
- info.format = GetVkFormat(ahbDesc.format);
- info.extent.width = ahbDesc.width;
- info.extent.height = ahbDesc.height;
- info.extent.depth = 1;
- info.mipLevels = 1;
- info.arrayLayers = 1;
- info.samples = VK_SAMPLE_COUNT_1_BIT;
- info.tiling = VK_IMAGE_TILING_OPTIMAL;
- info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-
- VkImage Image;
- VkResult result = vk::Image::Create(vk::DEVICE_MEMORY, &info, &Image, vk::Cast(device));
-
- pProperties->allocationSize = vk::Cast(Image)->getMemoryRequirements().size;
- vk::destroy(Image, vk::DEVICE_MEMORY);
- }
-
- return VK_SUCCESS;
-}
-
-VkResult AHardwareBufferExternalMemory::GetAndroidHardwareBufferUsageFromVkUsage(const VkImageCreateFlags createFlags, const VkImageUsageFlags usageFlags, uint64_t &ahbDescUsage)
-{
- if(usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT)
- ahbDescUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
- if(usageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)
- ahbDescUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
- if(usageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
- ahbDescUsage |= AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
-
- if(createFlags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
- ahbDescUsage |= AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
- if(createFlags & VK_IMAGE_CREATE_PROTECTED_BIT)
- ahbDescUsage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
-
- // No usage bits set - set at least one GPU usage
- if(ahbDescUsage == 0)
- ahbDescUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
-
- return VK_SUCCESS;
-}
-
-// Call into the native gralloc implementation to request a handle for the
-// rendernodeFD
-VkResult AHardwareBufferExternalMemory::getPrimeHandle(const native_handle_t *h, uint32_t &primeHandle)
-{
- cros_gralloc_handle const *crosHandle = reinterpret_cast<cros_gralloc_handle const *>(h);
- int ret = drmPrimeFDToHandle(rendernodeFD, crosHandle->fds[0], &primeHandle);
- if(ret != 0)
- {
- return VK_ERROR_INVALID_EXTERNAL_HANDLE;
- }
-
- return VK_SUCCESS;
-}
-
-// Create a rendernodeFD
-void AHardwareBufferExternalMemory::createRenderNodeFD()
-{
- rendernodeFD = drmOpenRender(128);
-}
-
-// using a primeHandle associated with a specific rendernodeFD, map a new block
-// of memory
-VkResult AHardwareBufferExternalMemory::mapMemory(uint32_t &primeHandle, void **ptr)
-{
- drm_virtgpu_map map;
- memset(&map, 0, sizeof(drm_virtgpu_map));
- map.handle = primeHandle;
- int ret = drmIoctl(rendernodeFD, DRM_IOCTL_VIRTGPU_MAP, &map);
- if(ret != 0)
- {
- return VK_ERROR_INVALID_EXTERNAL_HANDLE;
- }
-
- // mmap it
- *ptr = static_cast<unsigned char *>(
- mmap64(nullptr, 4096, PROT_WRITE, MAP_SHARED, rendernodeFD, map.offset));
- if(ptr == MAP_FAILED)
- {
- return VK_ERROR_MEMORY_MAP_FAILED;
- }
-
- return VK_SUCCESS;
-}
-
-// Close out the memory block associated with rendernodeFD
-VkResult AHardwareBufferExternalMemory::closeMemory(uint32_t &primeHandle)
-{
- struct drm_gem_close gem_close;
- memset(&gem_close, 0x0, sizeof(gem_close));
- gem_close.handle = primeHandle;
- int ret = drmIoctl(rendernodeFD, DRM_IOCTL_GEM_CLOSE, &gem_close);
- if(ret != 0)
- {
- return VK_ERROR_INVALID_EXTERNAL_HANDLE;
- }
-
- return VK_SUCCESS;
-}
+} // namespace
AHardwareBufferExternalMemory::AllocateInfo::AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
{
@@ -415,11 +227,14 @@
{
const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(createInfo);
- if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+ if(exportInfo->handleTypes == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+ {
+ exportAhb = true;
+ }
+ else
{
UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(exportInfo->handleTypes));
}
- exportAhb = true;
}
break;
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
@@ -439,4 +254,208 @@
}
}
+AHardwareBufferExternalMemory::AHardwareBufferExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
+ : allocateInfo(pAllocateInfo)
+{
+}
+
+AHardwareBufferExternalMemory::~AHardwareBufferExternalMemory()
+{
+ // correct deallocation of AHB does not require a pointer or size
+ deallocate(nullptr, 0);
+}
+
+// VkAllocateMemory
+VkResult AHardwareBufferExternalMemory::allocate(size_t /*size*/, void **pBuffer)
+{
+ if(allocateInfo.importAhb)
+ {
+ return importAndroidHardwareBuffer(allocateInfo.ahb, pBuffer);
+ }
+ else
+ {
+ ASSERT(allocateInfo.exportAhb);
+ return allocateAndroidHardwareBuffer(pBuffer);
+ }
+}
+
+void AHardwareBufferExternalMemory::deallocate(void *buffer, size_t size)
+{
+ if(ahb != nullptr)
+ {
+ unlockAndroidHardwareBuffer();
+
+ AHardwareBuffer_release(ahb);
+ ahb = nullptr;
+ }
+}
+
+VkResult AHardwareBufferExternalMemory::importAndroidHardwareBuffer(struct AHardwareBuffer *buffer, void **pBuffer)
+{
+ ahb = buffer;
+
+ AHardwareBuffer_acquire(ahb);
+
+ return lockAndroidHardwareBuffer(pBuffer);
+}
+
+VkResult AHardwareBufferExternalMemory::allocateAndroidHardwareBuffer(void **pBuffer)
+{
+ AHardwareBuffer_Desc desc = {};
+
+ if(allocateInfo.imageHandle)
+ {
+ vk::Image *image = allocateInfo.imageHandle;
+ ASSERT(image != nullptr);
+ ASSERT(image->getArrayLayers() == 1);
+
+ VkExtent3D extent = image->getExtent();
+
+ desc.width = extent.width;
+ desc.height = extent.height;
+ desc.layers = image->getArrayLayers();
+ desc.format = GetAHBFormatFromVkFormat(image->getFormat());
+ desc.usage = GetAHBUsageFromVkImageFlags(image->getFlags(), image->getUsage());
+ }
+ else
+ {
+ vk::Buffer *buffer = allocateInfo.bufferHandle;
+ ASSERT(buffer != nullptr);
+
+ desc.width = static_cast<uint32_t>(buffer->getSize());
+ desc.height = 1;
+ desc.layers = 1;
+ desc.format = AHARDWAREBUFFER_FORMAT_BLOB;
+ desc.usage = GetAHBUsageFromVkBufferFlags(buffer->getFlags(), buffer->getUsage());
+ }
+
+ // create a new ahb from desc
+ int ret = AHardwareBuffer_allocate(&desc, &ahb);
+ if(ret != 0)
+ {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ return lockAndroidHardwareBuffer(pBuffer);
+}
+
+VkResult AHardwareBufferExternalMemory::lockAndroidHardwareBuffer(void **pBuffer)
+{
+ uint64_t usage = 0;
+ if(allocateInfo.imageHandle)
+ {
+ usage = GetAHBLockUsageFromVkImageUsageFlags(allocateInfo.imageHandle->getUsage());
+ }
+ else
+ {
+ usage = GetAHBLockUsageFromVkBufferUsageFlags(allocateInfo.bufferHandle->getUsage());
+ }
+
+ // Empty fence, lock immedietly.
+ int32_t fence = -1;
+
+ // Empty rect, lock entire buffer.
+ ARect *rect = nullptr;
+
+ int ret = AHardwareBuffer_lock(ahb, usage, fence, rect, pBuffer);
+ if(ret != 0)
+ {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult AHardwareBufferExternalMemory::unlockAndroidHardwareBuffer()
+{
+ int ret = AHardwareBuffer_unlock(ahb, /*fence=*/nullptr);
+ if(ret != 0)
+ {
+ return VK_ERROR_UNKNOWN;
+ }
+
+ return VK_SUCCESS;
+}
+
+VkResult AHardwareBufferExternalMemory::exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const
+{
+ // Each call to vkGetMemoryAndroidHardwareBufferANDROID *must* return an Android hardware buffer with a new reference
+ // acquired in addition to the reference held by the VkDeviceMemory. To avoid leaking resources, the application *must*
+ // release the reference by calling AHardwareBuffer_release when it is no longer needed.
+ AHardwareBuffer_acquire(ahb);
+ *pAhb = ahb;
+ return VK_SUCCESS;
+}
+
+VkResult AHardwareBufferExternalMemory::GetAndroidHardwareBufferFormatProperties(const AHardwareBuffer_Desc &ahbDesc, VkAndroidHardwareBufferFormatPropertiesANDROID *pFormat)
+{
+ pFormat->sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
+ pFormat->pNext = nullptr;
+ pFormat->format = GetVkFormatFromAHBFormat(ahbDesc.format);
+ pFormat->externalFormat = ahbDesc.format;
+ pFormat->formatFeatures = GetVkFormatFeaturesFromAHBFormat(ahbDesc.format);
+ pFormat->samplerYcbcrConversionComponents = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+ pFormat->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+ pFormat->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+ pFormat->suggestedXChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
+ pFormat->suggestedYChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
+
+ return VK_SUCCESS;
+}
+
+VkResult AHardwareBufferExternalMemory::GetAndroidHardwareBufferProperties(VkDevice &device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
+{
+ VkResult result = VK_SUCCESS;
+
+ AHardwareBuffer_Desc ahbDesc;
+ AHardwareBuffer_describe(buffer, &ahbDesc);
+
+ if(pProperties->pNext != nullptr)
+ {
+ result = GetAndroidHardwareBufferFormatProperties(ahbDesc, (VkAndroidHardwareBufferFormatPropertiesANDROID *)pProperties->pNext);
+ if(result != VK_SUCCESS)
+ {
+ return result;
+ }
+ }
+
+ const VkPhysicalDeviceMemoryProperties phyDeviceMemProps = vk::PhysicalDevice::GetMemoryProperties();
+ pProperties->memoryTypeBits = phyDeviceMemProps.memoryTypes[0].propertyFlags;
+
+ if(ahbDesc.format == AHARDWAREBUFFER_FORMAT_BLOB)
+ {
+ pProperties->allocationSize = ahbDesc.width;
+ }
+ else
+ {
+ VkImageCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.imageType = VK_IMAGE_TYPE_2D;
+ info.format = GetVkFormatFromAHBFormat(ahbDesc.format);
+ info.extent.width = ahbDesc.width;
+ info.extent.height = ahbDesc.height;
+ info.extent.depth = 1;
+ info.mipLevels = 1;
+ info.arrayLayers = 1;
+ info.samples = VK_SAMPLE_COUNT_1_BIT;
+ info.tiling = VK_IMAGE_TILING_OPTIMAL;
+ info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ VkImage Image;
+
+ result = vk::Image::Create(vk::DEVICE_MEMORY, &info, &Image, vk::Cast(device));
+ if(result != VK_SUCCESS)
+ {
+ return result;
+ }
+
+ pProperties->allocationSize = vk::Cast(Image)->getMemoryRequirements().size;
+ vk::destroy(Image, vk::DEVICE_MEMORY);
+ }
+
+ return result;
+}
+
#endif // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
index 6292af5..9931daf 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
@@ -17,29 +17,14 @@
#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+# include "VkBuffer.hpp"
# include "VkDevice.hpp"
# include "VkDeviceMemory.hpp"
# include "VkDeviceMemoryExternalBase.hpp"
-
-# include "VkBuffer.hpp"
-# include "VkDeviceMemory.hpp"
# include "VkImage.hpp"
-# include "VkStringify.hpp"
-
-# include "System/Debug.hpp"
-# include "System/Linux/MemFd.hpp"
# include <android/hardware_buffer.h>
-# include <cros_gralloc/cros_gralloc_handle.h>
-# include <unistd.h>
-# include <virtgpu_drm.h>
-# include <xf86drm.h>
-
-# include <errno.h>
-# include <string.h>
-# include <map>
-
class AHardwareBufferExternalMemory : public vk::DeviceMemory::ExternalBase
{
public:
@@ -68,49 +53,29 @@
return (info.importAhb || info.exportAhb) && (info.bufferHandle || info.imageHandle);
}
- explicit AHardwareBufferExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
- : allocateInfo(pAllocateInfo)
- {
- }
-
+ explicit AHardwareBufferExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo);
~AHardwareBufferExternalMemory();
+
VkResult allocate(size_t size, void **pBuffer) override;
void deallocate(void *buffer, size_t size) override;
- VkResult allocateAndroidHardwareBuffer(size_t size, void **pBuffer);
- VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
- {
- return typeFlagBit;
- }
+ VkExternalMemoryHandleTypeFlagBits getFlagBit() const override { return typeFlagBit; }
VkResult exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const override;
- void setDevicePtr(vk::Device *pDevice) override
- {
- device = pDevice;
- }
+ void setDevicePtr(vk::Device *pDevice) override { device = pDevice; }
+ bool isAndroidHardwareBuffer() override { return true; }
- bool isAndroidHardwareBuffer() override
- {
- return true;
- }
-
- static uint32_t GetAndroidHardwareBufferDescFormat(VkFormat format);
- static VkFormat GetVkFormat(uint32_t ahbFormat);
- static VkFormatFeatureFlags GetVkFormatFeatures(VkFormat format);
static VkResult GetAndroidHardwareBufferFormatProperties(const AHardwareBuffer_Desc &ahbDesc, VkAndroidHardwareBufferFormatPropertiesANDROID *pFormat);
static VkResult GetAndroidHardwareBufferProperties(VkDevice &device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
- static VkResult GetAndroidHardwareBufferUsageFromVkUsage(const VkImageCreateFlags createFlags, const VkImageUsageFlags usageFlags, uint64_t &ahbDescUsage);
-
- // All reliance on minigbm and DRM is contained in these functions
- VkResult getPrimeHandle(const native_handle_t *h, uint32_t &primeHandle);
- void createRenderNodeFD();
- VkResult mapMemory(uint32_t &primeHandle, void **ptr);
- VkResult closeMemory(uint32_t &primeHandle);
private:
+ VkResult importAndroidHardwareBuffer(struct AHardwareBuffer *buffer, void **pBuffer);
+ VkResult allocateAndroidHardwareBuffer(void **pBuffer);
+ VkResult lockAndroidHardwareBuffer(void **pBuffer);
+ VkResult unlockAndroidHardwareBuffer();
+
struct AHardwareBuffer *ahb = nullptr;
- int rendernodeFD;
vk::Device *device = nullptr;
AllocateInfo allocateInfo;
};
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 97abeab..41977fd 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -529,108 +529,24 @@
TRACE("(VkPhysicalDevice physicalDevice = %p, VkFormat format = %d, VkImageType type = %d, VkImageTiling tiling = %d, VkImageUsageFlags usage = %d, VkImageCreateFlags flags = %d, VkImageFormatProperties* pImageFormatProperties = %p)",
physicalDevice, (int)format, (int)type, (int)tiling, usage, flags, pImageFormatProperties);
- // "If the combination of parameters to vkGetPhysicalDeviceImageFormatProperties is not supported by the implementation
- // for use in vkCreateImage, then all members of VkImageFormatProperties will be filled with zero."
- memset(pImageFormatProperties, 0, sizeof(VkImageFormatProperties));
+ VkPhysicalDeviceImageFormatInfo2 info2 = {};
+ info2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+ info2.pNext = nullptr;
+ info2.format = format;
+ info2.type = type;
+ info2.tiling = tiling;
+ info2.usage = usage;
+ info2.flags = flags;
- VkFormatProperties properties;
- vk::PhysicalDevice::GetFormatProperties(format, &properties);
+ VkImageFormatProperties2 properties2 = {};
+ properties2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+ properties2.pNext = nullptr;
- VkFormatFeatureFlags features;
- switch(tiling)
- {
- case VK_IMAGE_TILING_LINEAR:
- features = properties.linearTilingFeatures;
- break;
+ VkResult result = vkGetPhysicalDeviceImageFormatProperties2(physicalDevice, &info2, &properties2);
- case VK_IMAGE_TILING_OPTIMAL:
- features = properties.optimalTilingFeatures;
- break;
+ *pImageFormatProperties = properties2.imageFormatProperties;
- default:
- UNSUPPORTED("VkImageTiling %d", int(tiling));
- features = 0;
- }
-
- if(features == 0)
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- // Check for usage conflict with features
- if((usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- if((usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- if((usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && !(features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- if((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- if((usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) && !(features & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)))
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- if((usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) && !(features & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT))
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- if((usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) && !(features & VK_FORMAT_FEATURE_TRANSFER_DST_BIT))
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- auto allRecognizedUsageBits = VK_IMAGE_USAGE_SAMPLED_BIT |
- VK_IMAGE_USAGE_STORAGE_BIT |
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
- ASSERT(!(usage & ~(allRecognizedUsageBits)));
-
- // "Images created with tiling equal to VK_IMAGE_TILING_LINEAR have further restrictions on their limits and capabilities
- // compared to images created with tiling equal to VK_IMAGE_TILING_OPTIMAL."
- if(tiling == VK_IMAGE_TILING_LINEAR)
- {
- if(type != VK_IMAGE_TYPE_2D)
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
-
- if(vk::Format(format).isDepth() || vk::Format(format).isStencil())
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
- }
-
- // "Images created with a format from one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
- // have further restrictions on their limits and capabilities compared to images created with other formats."
- if(vk::Format(format).isYcbcrFormat())
- {
- if(type != VK_IMAGE_TYPE_2D)
- {
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
- }
- }
-
- vk::Cast(physicalDevice)->getImageFormatProperties(format, type, tiling, usage, flags, pImageFormatProperties);
-
- return VK_SUCCESS;
+ return result;
}
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties)
@@ -3044,6 +2960,10 @@
TRACE("(VkPhysicalDevice physicalDevice = %p, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo = %p, VkImageFormatProperties2* pImageFormatProperties = %p)",
physicalDevice, pImageFormatInfo, pImageFormatProperties);
+ // "If the combination of parameters to vkGetPhysicalDeviceImageFormatProperties is not supported by the implementation
+ // for use in vkCreateImage, then all members of VkImageFormatProperties will be filled with zero."
+ memset(&pImageFormatProperties->imageFormatProperties, 0, sizeof(VkImageFormatProperties));
+
const VkBaseInStructure *extensionFormatInfo = reinterpret_cast<const VkBaseInStructure *>(pImageFormatInfo->pNext);
const VkExternalMemoryHandleTypeFlagBits *handleType = nullptr;
@@ -3085,6 +3005,10 @@
VkBaseOutStructure *extensionProperties = reinterpret_cast<VkBaseOutStructure *>(pImageFormatProperties->pNext);
+#ifdef __ANDROID__
+ bool hasAHBUsage = false;
+#endif
+
while(extensionProperties)
{
switch(extensionProperties->sType)
@@ -3112,6 +3036,7 @@
{
auto properties = reinterpret_cast<VkAndroidHardwareBufferUsageANDROID *>(extensionProperties);
vk::Cast(physicalDevice)->getProperties(properties);
+ hasAHBUsage = true;
}
break;
#endif
@@ -3123,13 +3048,119 @@
extensionProperties = extensionProperties->pNext;
}
- return vkGetPhysicalDeviceImageFormatProperties(physicalDevice,
- pImageFormatInfo->format,
- pImageFormatInfo->type,
- pImageFormatInfo->tiling,
- pImageFormatInfo->usage,
- pImageFormatInfo->flags,
- &(pImageFormatProperties->imageFormatProperties));
+ VkFormat format = pImageFormatInfo->format;
+ VkImageType type = pImageFormatInfo->type;
+ VkImageTiling tiling = pImageFormatInfo->tiling;
+ VkImageUsageFlags usage = pImageFormatInfo->usage;
+ VkImageCreateFlags flags = pImageFormatInfo->flags;
+
+ VkFormatProperties properties;
+ vk::PhysicalDevice::GetFormatProperties(format, &properties);
+
+ VkFormatFeatureFlags features;
+ switch(tiling)
+ {
+ case VK_IMAGE_TILING_LINEAR:
+ features = properties.linearTilingFeatures;
+ break;
+
+ case VK_IMAGE_TILING_OPTIMAL:
+ features = properties.optimalTilingFeatures;
+ break;
+
+ default:
+ UNSUPPORTED("VkImageTiling %d", int(tiling));
+ features = 0;
+ }
+
+ if(features == 0)
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ // Check for usage conflict with features
+ if((usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if((usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if((usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && !(features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if((usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) && !(features & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)))
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if((usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) && !(features & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT))
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if((usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) && !(features & VK_FORMAT_FEATURE_TRANSFER_DST_BIT))
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ auto allRecognizedUsageBits = VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_STORAGE_BIT |
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+ VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
+ ASSERT(!(usage & ~(allRecognizedUsageBits)));
+
+ // "Images created with tiling equal to VK_IMAGE_TILING_LINEAR have further restrictions on their limits and capabilities
+ // compared to images created with tiling equal to VK_IMAGE_TILING_OPTIMAL."
+ if(tiling == VK_IMAGE_TILING_LINEAR)
+ {
+ if(type != VK_IMAGE_TYPE_2D)
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+
+ if(vk::Format(format).isDepth() || vk::Format(format).isStencil())
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+ }
+
+ // "Images created with a format from one of those listed in Formats requiring sampler Y'CBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
+ // have further restrictions on their limits and capabilities compared to images created with other formats."
+ if(vk::Format(format).isYcbcrFormat())
+ {
+ if(type != VK_IMAGE_TYPE_2D)
+ {
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+ }
+
+ vk::Cast(physicalDevice)->getImageFormatProperties(format, type, tiling, usage, flags, &pImageFormatProperties->imageFormatProperties);
+
+#ifdef __ANDROID__
+ if(hasAHBUsage)
+ {
+ // AHardwareBuffer_lock may only be called with a single layer.
+ pImageFormatProperties->imageFormatProperties.maxArrayLayers = 1;
+ pImageFormatProperties->imageFormatProperties.maxMipLevels = 1;
+ }
+#endif
+
+ return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties)