Added support for AndroidHardwareBuffer

Bug: b/141698760
Change-Id: I8d3895b2ee79a0ba71f20917ae1edc83dd19dab8
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/48508
Reviewed-by: Trevor Black <vantablack@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: Trevor Black <vantablack@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Presubmit-Ready: Trevor Black <vantablack@google.com>
Tested-by: Trevor Black <vantablack@google.com>
diff --git a/src/Android.bp b/src/Android.bp
index 332c51f..026e23c 100644
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -56,6 +56,7 @@
             shared_libs: [
                 "android.hardware.graphics.mapper@3.0",
                 "android.hardware.graphics.mapper@4.0",
+                "libdrm",
                 "libnativewindow",
                 "libhardware",
                 "libhidlbase",
@@ -590,6 +591,7 @@
             shared_libs: [
                 "android.hardware.graphics.mapper@3.0",
                 "android.hardware.graphics.mapper@4.0",
+                "libdrm",
                 "libnativewindow",
                 "libhardware",
                 "libhidlbase",
@@ -661,7 +663,9 @@
 
     include_dirs: [
         "external/swiftshader/third_party/SPIRV-Headers/include",
-        "external/swiftshader/include"
+        "external/swiftshader/include",
+        "external/minigbm",
+        "external/libdrm"
     ],
 }
 
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 4cdca03..cc0a359 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -146,6 +146,10 @@
 		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)
@@ -375,4 +379,60 @@
 	}
 }
 
+#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 7f67ffa..9fce601 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -193,6 +193,41 @@
 		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/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index 84a2a7e..fd47bf5 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -14,54 +14,13 @@
 
 #include "VkDeviceMemory.hpp"
 #include "VkBuffer.hpp"
+#include "VkDeviceMemoryExternalBase.hpp"
 #include "VkImage.hpp"
 
 #include "VkConfig.hpp"
 
 namespace vk {
 
-// Base abstract interface for a device memory implementation.
-class DeviceMemory::ExternalBase
-{
-public:
-	virtual ~ExternalBase() = default;
-
-	// Allocate the memory according to |size|. On success return VK_SUCCESS
-	// and sets |*pBuffer|.
-	virtual VkResult allocate(size_t size, void **pBuffer) = 0;
-
-	// Deallocate previously allocated memory at |buffer|.
-	virtual void deallocate(void *buffer, size_t size) = 0;
-
-	// Return the handle type flag bit supported by this implementation.
-	// A value of 0 corresponds to non-external memory.
-	virtual VkExternalMemoryHandleTypeFlagBits getFlagBit() const = 0;
-
-#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-	virtual VkResult exportFd(int *pFd) const
-	{
-		return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-	}
-#endif
-
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-	virtual VkResult exportAhb(struct AHardwareBuffer **pAhb) const
-	{
-		return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-	}
-#endif
-
-#if VK_USE_PLATFORM_FUCHSIA
-	virtual VkResult exportHandle(zx_handle_t *pHandle) const
-	{
-		return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-	}
-#endif
-
-protected:
-	ExternalBase() = default;
-};
-
 // Small class describing a given DeviceMemory::ExternalBase derived class.
 // |typeFlagBit| corresponds to the external memory handle type.
 // |instanceSize| is the size of each class instance in bytes.
@@ -83,7 +42,7 @@
 static bool parseCreateInfo(const VkMemoryAllocateInfo *pAllocateInfo,
                             ExternalMemoryTraits *pTraits)
 {
-	if(T::supportsAllocateInfo(pAllocateInfo))
+	if(T::SupportsAllocateInfo(pAllocateInfo))
 	{
 		pTraits->typeFlagBit = T::typeFlagBit;
 		pTraits->instanceSize = sizeof(T);
@@ -105,7 +64,7 @@
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0;
 
 	// Always return true as is used as a fallback in findTraits() below.
-	static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
 	{
 		return true;
 	}
@@ -177,7 +136,7 @@
 
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT);
 
-	static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
 	{
 		AllocateInfo info(pAllocateInfo);
 		return info.supported;
@@ -235,14 +194,14 @@
 static void findTraits(const VkMemoryAllocateInfo *pAllocateInfo,
                        ExternalMemoryTraits *pTraits)
 {
-#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-	if(parseCreateInfo<OpaqueFdExternalMemory>(pAllocateInfo, pTraits))
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+	if(parseCreateInfo<AHardwareBufferExternalMemory>(pAllocateInfo, pTraits))
 	{
 		return;
 	}
 #endif
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-	if(parseCreateInfo<AHardwareBufferExternalMemory>(pAllocateInfo, pTraits))
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+	if(parseCreateInfo<OpaqueFdExternalMemory>(pAllocateInfo, pTraits))
 	{
 		return;
 	}
@@ -260,9 +219,10 @@
 	parseCreateInfo<DeviceMemoryHostExternalBase>(pAllocateInfo, pTraits);
 }
 
-DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, void *mem)
+DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, void *mem, Device *pDevice)
     : size(pAllocateInfo->allocationSize)
     , memoryTypeIndex(pAllocateInfo->memoryTypeIndex)
+    , device(pDevice)
 {
 	ASSERT(size);
 
@@ -270,6 +230,7 @@
 	findTraits(pAllocateInfo, &traits);
 	traits.instanceInit(mem, pAllocateInfo);
 	external = reinterpret_cast<ExternalBase *>(mem);
+	external->setDevicePtr(device);
 }
 
 void DeviceMemory::destroy(const VkAllocationCallbacks *pAllocator)
@@ -320,7 +281,6 @@
 void *DeviceMemory::getOffsetPointer(VkDeviceSize pOffset) const
 {
 	ASSERT(buffer);
-
 	return reinterpret_cast<char *>(buffer) + pOffset;
 }
 
@@ -354,14 +314,14 @@
 #endif
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-VkResult DeviceMemory::exportAhb(struct AHardwareBuffer **pAhb) const
+VkResult DeviceMemory::exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const
 {
-	return external->exportAhb(pAhb);
+	return external->exportAndroidHardwareBuffer(pAhb);
 }
 
-VkResult DeviceMemory::getAhbProperties(const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
+VkResult DeviceMemory::GetAndroidHardwareBufferProperties(VkDevice &ahbDevice, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
 {
-	return AHardwareBufferExternalMemory::getAhbProperties(buffer, pProperties);
+	return AHardwareBufferExternalMemory::GetAndroidHardwareBufferProperties(ahbDevice, buffer, pProperties);
 }
 #endif
 
diff --git a/src/Vulkan/VkDeviceMemory.hpp b/src/Vulkan/VkDeviceMemory.hpp
index 6a388fb..fa04e6a 100644
--- a/src/Vulkan/VkDeviceMemory.hpp
+++ b/src/Vulkan/VkDeviceMemory.hpp
@@ -20,10 +20,12 @@
 
 namespace vk {
 
+class Device;
+
 class DeviceMemory : public Object<DeviceMemory, VkDeviceMemory>
 {
 public:
-	DeviceMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem);
+	DeviceMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, Device *pDevice);
 
 	static size_t ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pCreateInfo);
 
@@ -32,8 +34,8 @@
 #endif
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-	VkResult exportAhb(struct AHardwareBuffer **pAhb) const;
-	static VkResult getAhbProperties(const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
+	VkResult exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const;
+	static VkResult GetAndroidHardwareBufferProperties(VkDevice &device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
 #endif
 
 #if VK_USE_PLATFORM_FUCHSIA
@@ -60,6 +62,7 @@
 	VkDeviceSize size = 0;
 	uint32_t memoryTypeIndex = 0;
 	ExternalBase *external = nullptr;
+	Device *device;
 };
 
 static inline DeviceMemory *Cast(VkDeviceMemory object)
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
new file mode 100644
index 0000000..edeaf2a
--- /dev/null
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
@@ -0,0 +1,442 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// 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.
+
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+
+#	include "VkDeviceMemoryExternalAndroid.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 <android/hardware_buffer.h>
+#	include <cutils/native_handle.h>
+#	include <vndk/hardware_buffer.h>
+
+#	include <cros_gralloc/cros_gralloc_handle.h>
+#	include <unistd.h>
+#	include <virgl_hw.h>
+#	include <virtgpu_drm.h>
+#	include <xf86drm.h>
+
+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)
+{
+	switch(format)
+	{
+		case VK_FORMAT_D16_UNORM:
+			return AHARDWAREBUFFER_FORMAT_D16_UNORM;
+		case VK_FORMAT_X8_D24_UNORM_PACK32:
+			UNSUPPORTED("AHardwareBufferExternalMemory::VkFormat VK_FORMAT_X8_D24_UNORM_PACK32");
+			return AHARDWAREBUFFER_FORMAT_D24_UNORM;
+		case VK_FORMAT_D24_UNORM_S8_UINT:
+			UNSUPPORTED("AHardwareBufferExternalMemory::VkFormat VK_FORMAT_D24_UNORM_S8_UINT");
+			return AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT;
+		case VK_FORMAT_D32_SFLOAT:
+			return AHARDWAREBUFFER_FORMAT_D32_FLOAT;
+		case VK_FORMAT_D32_SFLOAT_S8_UINT:
+			return AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT;
+		case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+			return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
+		case VK_FORMAT_R16G16B16A16_SFLOAT:
+			return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
+		case VK_FORMAT_R5G6B5_UNORM_PACK16:
+			return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+		case VK_FORMAT_R8G8B8A8_UNORM:
+			return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+		case VK_FORMAT_R8G8B8_UNORM:
+			return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
+		case VK_FORMAT_S8_UINT:
+			return AHARDWAREBUFFER_FORMAT_S8_UINT;
+		case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+			return AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420;
+		default:
+			UNSUPPORTED("AHardwareBufferExternalMemory::VkFormat %d", int(format));
+			return 0;
+	}
+}
+
+VkFormat AHardwareBufferExternalMemory::GetVkFormat(uint32_t ahbFormat)
+{
+	switch(ahbFormat)
+	{
+		case AHARDWAREBUFFER_FORMAT_BLOB:
+			return VK_FORMAT_UNDEFINED;
+		case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+			return VK_FORMAT_D16_UNORM;
+		case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+			UNSUPPORTED("AHardwareBufferExternalMemory::AndroidHardwareBuffer_Format AHARDWAREBUFFER_FORMAT_D24_UNORM");
+			return VK_FORMAT_X8_D24_UNORM_PACK32;
+		case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+			UNSUPPORTED("AHardwareBufferExternalMemory::AndroidHardwareBuffer_Format AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT");
+			return VK_FORMAT_X8_D24_UNORM_PACK32;
+		case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+			return VK_FORMAT_D32_SFLOAT;
+		case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
+			return VK_FORMAT_D32_SFLOAT_S8_UINT;
+		case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+			return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
+		case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+			return VK_FORMAT_R16G16B16A16_SFLOAT;
+		case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+			return VK_FORMAT_R5G6B5_UNORM_PACK16;
+		case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+			return VK_FORMAT_R8G8B8A8_UNORM;
+		case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+			return VK_FORMAT_R8G8B8A8_UNORM;
+		case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+			return VK_FORMAT_R8G8B8_UNORM;
+		case AHARDWAREBUFFER_FORMAT_S8_UINT:
+			return VK_FORMAT_S8_UINT;
+		case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
+			return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
+		default:
+			UNSUPPORTED("AHardwareBufferExternalMemory::AHardwareBuffer_Format %d", int(ahbFormat));
+			return VK_FORMAT_UNDEFINED;
+	}
+}
+
+VkFormatFeatureFlags AHardwareBufferExternalMemory::GetVkFormatFeatures(VkFormat format)
+{
+	VkFormatProperties formatProperties;
+	vk::PhysicalDevice::GetFormatProperties(vk::Format(format), &formatProperties);
+
+	formatProperties.optimalTilingFeatures |= VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
+
+	// 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;
+}
+
+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;
+}
+
+AHardwareBufferExternalMemory::AllocateInfo::AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+{
+	const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
+	while(createInfo)
+	{
+		switch(createInfo->sType)
+		{
+			case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:
+			{
+				const auto *importInfo = reinterpret_cast<const VkImportAndroidHardwareBufferInfoANDROID *>(createInfo);
+				importAhb = true;
+				ahb = importInfo->buffer;
+			}
+			break;
+			case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
+			{
+				const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(createInfo);
+
+				if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+				{
+					UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(exportInfo->handleTypes));
+				}
+				exportAhb = true;
+			}
+			break;
+			case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
+			{
+				// AHB requires dedicated allocation -- for images, the gralloc gets to decide the image layout,
+				// not us.
+				const auto *dedicatedAllocateInfo = reinterpret_cast<const VkMemoryDedicatedAllocateInfo *>(createInfo);
+				imageHandle = vk::Cast(dedicatedAllocateInfo->image);
+				bufferHandle = vk::Cast(dedicatedAllocateInfo->buffer);
+			}
+			break;
+
+			default:
+				WARN("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(createInfo->sType).c_str());
+		}
+		createInfo = createInfo->pNext;
+	}
+}
+
+#endif  // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
index 9bfb381..6292af5 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
@@ -12,14 +12,33 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "VkStringify.hpp"
+#ifndef VK_DEVICE_MEMORY_EXTERNAL_ANDROID_HPP_
+#define VK_DEVICE_MEMORY_EXTERNAL_ANDROID_HPP_
 
-#include "System/Debug.hpp"
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
 
-#include <android/hardware_buffer.h>
+#	include "VkDevice.hpp"
+#	include "VkDeviceMemory.hpp"
+#	include "VkDeviceMemoryExternalBase.hpp"
 
-#include <errno.h>
-#include <string.h>
+#	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
 {
@@ -38,52 +57,12 @@
 		AllocateInfo() = default;
 
 		// Parse the VkMemoryAllocateInfo.pNext chain to initialize an AllocateInfo.
-		AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
-		{
-			const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
-			while(createInfo)
-			{
-				switch(createInfo->sType)
-				{
-					case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:
-					{
-						const auto *importInfo = reinterpret_cast<const VkImportAndroidHardwareBufferInfoANDROID *>(createInfo);
-						importAhb = true;
-						ahb = importInfo->buffer;
-					}
-					break;
-					case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
-					{
-						const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(createInfo);
-
-						if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
-						{
-							UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(exportInfo->handleTypes));
-						}
-						exportAhb = true;
-					}
-					break;
-					case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
-					{
-						// AHB requires dedicated allocation -- for images, the gralloc gets to decide the image layout,
-						// not us.
-						const auto *dedicatedAllocateInfo = reinterpret_cast<const VkMemoryDedicatedAllocateInfo *>(createInfo);
-						imageHandle = vk::Cast(dedicatedAllocateInfo->image);
-						bufferHandle = vk::Cast(dedicatedAllocateInfo->buffer);
-					}
-					break;
-
-					default:
-						WARN("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(createInfo->sType).c_str());
-				}
-				createInfo = createInfo->pNext;
-			}
-		}
+		AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo);
 	};
 
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
 
-	static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
 	{
 		AllocateInfo info(pAllocateInfo);
 		return (info.importAhb || info.exportAhb) && (info.bufferHandle || info.imageHandle);
@@ -94,67 +73,47 @@
 	{
 	}
 
-	~AHardwareBufferExternalMemory()
-	{
-		if(ahb)
-			AHardwareBuffer_release(ahb);
-	}
-
-	VkResult allocate(size_t size, void **pBuffer) override
-	{
-		if(allocateInfo.importAhb)
-		{
-			//ahb = allocateInfo.ahb;
-			//AHardwareBuffer_acquire(ahb);
-			// TODO: also allocate our internal shadow memory
-			return VK_ERROR_INVALID_EXTERNAL_HANDLE;
-		}
-		else
-		{
-			ASSERT(allocateInfo.exportAhb);
-			// TODO: create and import the AHB
-			return VK_ERROR_OUT_OF_DEVICE_MEMORY;
-		}
-
-		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
-		/*
-		void *addr = memfd.mapReadWrite(0, size);
-		if(!addr)
-		{
-			return VK_ERROR_MEMORY_MAP_FAILED;
-		}
-		*pBuffer = addr;
-		return VK_SUCCESS;
-		 */
-	}
-
-	void deallocate(void *buffer, size_t size) override
-	{
-		// FIXME
-	}
+	~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;
 	}
 
-	VkResult exportAhb(struct AHardwareBuffer **pAhb) const override
+	VkResult exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const override;
+
+	void setDevicePtr(vk::Device *pDevice) override
 	{
-		// 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;
+		device = pDevice;
 	}
 
-	static VkResult getAhbProperties(const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
+	bool isAndroidHardwareBuffer() override
 	{
-		UNIMPLEMENTED("b/141698760: getAhbProperties");  // FIXME(b/141698760)
-		return VK_SUCCESS;
+		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:
 	struct AHardwareBuffer *ahb = nullptr;
+	int rendernodeFD;
+	vk::Device *device = nullptr;
 	AllocateInfo allocateInfo;
 };
+
+#endif  // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+#endif  // VK_DEVICE_MEMORY_EXTERNAL_ANDROID_HPP_
diff --git a/src/Vulkan/VkDeviceMemoryExternalBase.hpp b/src/Vulkan/VkDeviceMemoryExternalBase.hpp
new file mode 100644
index 0000000..428678e
--- /dev/null
+++ b/src/Vulkan/VkDeviceMemoryExternalBase.hpp
@@ -0,0 +1,66 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// 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.
+
+#ifndef VK_DEVICE_MEMORY_EXTERNAL_BASE_HPP_
+#define VK_DEVICE_MEMORY_EXTERNAL_BASE_HPP_
+
+#include "VkDeviceMemory.hpp"
+
+namespace vk {
+
+// Base abstract interface for a device memory implementation.
+class DeviceMemory::ExternalBase
+{
+public:
+	virtual ~ExternalBase() = default;
+
+	// Allocate the memory according to |size|. On success return VK_SUCCESS
+	// and sets |*pBuffer|.
+	virtual VkResult allocate(size_t size, void **pBuffer) = 0;
+
+	// Deallocate previously allocated memory at |buffer|.
+	virtual void deallocate(void *buffer, size_t size) = 0;
+
+	// Return the handle type flag bit supported by this implementation.
+	// A value of 0 corresponds to non-external memory.
+	virtual VkExternalMemoryHandleTypeFlagBits getFlagBit() const = 0;
+
+	virtual void setDevicePtr(Device *pDevice) {}
+
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+	virtual VkResult exportFd(int *pFd) const
+	{
+		return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+	}
+#endif
+
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+	virtual VkResult exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const
+	{
+		return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+	}
+
+	virtual bool isAndroidHardwareBuffer()
+	{
+		return false;
+	}
+#endif
+
+protected:
+	ExternalBase() = default;
+};
+
+}  // namespace vk
+
+#endif  // VK_DEVICE_MEMORY_EXTERNAL_BASE_HPP_
diff --git a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
index 0763fd9..b4f22fc 100644
--- a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
@@ -82,7 +82,7 @@
 
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
 
-	static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
 	{
 		AllocateInfo info(pAllocateInfo);
 		return info.importFd || info.exportFd;
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 92979d7..6869d53 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -81,6 +81,7 @@
 	uint32_t getArrayLayers() const { return arrayLayers; }
 	uint32_t getMipLevels() const { return mipLevels; }
 	VkImageUsageFlags getUsage() const { return usage; }
+	VkImageCreateFlags getFlags() const { return flags; }
 	VkSampleCountFlagBits getSampleCountFlagBits() const { return samples; }
 	const VkExtent3D &getExtent() const { return extent; }
 	VkExtent3D getMipLevelExtent(VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
@@ -110,8 +111,11 @@
 	}
 	bool hasExternalMemory() const { return backingMemory.externalMemory; }
 	VkDeviceMemory getExternalMemory() const;
+	VkExternalMemoryHandleTypeFlags getSupportedExternalMemoryHandleTypes() const { return supportedExternalMemoryHandleTypes; }
 #endif
 
+	DeviceMemory *deviceMemory = nullptr;
+
 private:
 	void copy(Buffer *buffer, const VkBufferImageCopy &region, bool bufferIsSource);
 	VkDeviceSize getStorageSize(VkImageAspectFlags flags) const;
@@ -135,7 +139,6 @@
 	void decodeASTC(const VkImageSubresource &subresource);
 
 	const Device *const device = nullptr;
-	DeviceMemory *deviceMemory = nullptr;
 	VkDeviceSize memoryOffset = 0;
 	VkImageCreateFlags flags = 0;
 	VkImageType imageType = VK_IMAGE_TYPE_2D;
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 165db86..37ff223 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -22,41 +22,21 @@
 #include <cstring>
 #include <limits>
 
+#ifdef __ANDROID__
+#	include <android/hardware_buffer.h>
+#endif
+
 namespace vk {
 
-static void setExternalMemoryProperties(VkExternalMemoryHandleTypeFlagBits handleType, VkExternalMemoryProperties *properties)
-{
-#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-	if(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
-	{
-		properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
-		properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
-		properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
-		return;
-	}
-#endif
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-	if(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
-	{
-		properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
-		properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
-		properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
-		return;
-	}
-#endif
 #if VK_USE_PLATFORM_FUCHSIA
-	if(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
-	{
-		properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
-		properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
-		properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
-		return;
-	}
-#endif
-	properties->compatibleHandleTypes = 0;
-	properties->exportFromImportedHandleTypes = 0;
-	properties->externalMemoryFeatures = 0;
+if(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+{
+	properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+	properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+	properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+	return;
 }
+#endif
 
 PhysicalDevice::PhysicalDevice(const void *, void *mem)
 {
@@ -537,7 +517,72 @@
 
 void PhysicalDevice::getProperties(const VkExternalMemoryHandleTypeFlagBits *handleType, VkExternalImageFormatProperties *properties) const
 {
-	setExternalMemoryProperties(*handleType, &properties->externalMemoryProperties);
+	VkExternalMemoryProperties *extMemProperties = &properties->externalMemoryProperties;
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+	if(*handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
+	{
+		extMemProperties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+		extMemProperties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+		extMemProperties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+		return;
+	}
+#endif
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+	if(*handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+	{
+		extMemProperties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+		extMemProperties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+		extMemProperties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT;
+		return;
+	}
+#endif
+#if VK_USE_PLATFORM_FUCHSIA
+	if(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+	{
+		properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+		properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+		properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+		return;
+	}
+#endif
+	extMemProperties->compatibleHandleTypes = 0;
+	extMemProperties->exportFromImportedHandleTypes = 0;
+	extMemProperties->externalMemoryFeatures = 0;
+}
+
+void PhysicalDevice::getProperties(const VkExternalMemoryHandleTypeFlagBits *handleType, VkExternalBufferProperties *properties) const
+{
+	VkExternalMemoryProperties *extMemProperties = &properties->externalMemoryProperties;
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+	if(*handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
+	{
+		extMemProperties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+		extMemProperties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+		extMemProperties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+		return;
+	}
+#endif
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+	if(*handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+	{
+		extMemProperties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+		extMemProperties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+		extMemProperties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+		return;
+	}
+#endif
+#if VK_USE_PLATFORM_FUCHSIA
+	if(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+	{
+		properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+		properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+		properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+		return;
+	}
+#endif
+	extMemProperties->compatibleHandleTypes = 0;
+	extMemProperties->exportFromImportedHandleTypes = 0;
+	extMemProperties->externalMemoryFeatures = 0;
 }
 
 void PhysicalDevice::getProperties(VkSamplerYcbcrConversionImageFormatProperties *properties) const
@@ -550,11 +595,46 @@
 {
 	properties->sharedImage = VK_FALSE;
 }
+
+void PhysicalDevice::getProperties(VkAndroidHardwareBufferUsageANDROID *properties) const
+{
+	// TODO(b/169439421)
+	//   This AHB could be either a framebuffer, OR a sampled image
+	//     Here we just say it's both
+	//   Need to pass down info on the type of image in question
+	properties->androidHardwareBufferUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
+}
 #endif
 
 void PhysicalDevice::getProperties(const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) const
 {
-	setExternalMemoryProperties(pExternalBufferInfo->handleType, &pExternalBufferProperties->externalMemoryProperties);
+	VkExternalMemoryProperties *properties = &pExternalBufferProperties->externalMemoryProperties;
+
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD || SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+	const VkExternalMemoryHandleTypeFlagBits *handleType = &pExternalBufferInfo->handleType;
+#endif
+
+#if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+	if(*handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
+	{
+		properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+		properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+		properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+		return;
+	}
+#endif
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+	if(*handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+	{
+		properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+		properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+		properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+		return;
+	}
+#endif
+	properties->compatibleHandleTypes = 0;
+	properties->exportFromImportedHandleTypes = 0;
+	properties->externalMemoryFeatures = 0;
 }
 
 void PhysicalDevice::getProperties(const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) const
@@ -630,7 +710,7 @@
 	return true;
 }
 
-void PhysicalDevice::getFormatProperties(Format format, VkFormatProperties *pFormatProperties) const
+void PhysicalDevice::GetFormatProperties(Format format, VkFormatProperties *pFormatProperties)
 {
 	pFormatProperties->linearTilingFeatures = 0;   // Unsupported format
 	pFormatProperties->optimalTilingFeatures = 0;  // Unsupported format
@@ -1047,7 +1127,7 @@
 				pImageFormatProperties->maxExtent.height = 1 << (vk::MAX_IMAGE_LEVELS_2D - 1);
 
 				VkFormatProperties props;
-				getFormatProperties(format, &props);
+				GetFormatProperties(format, &props);
 				auto features = tiling == VK_IMAGE_TILING_LINEAR ? props.linearTilingFeatures : props.optimalTilingFeatures;
 				if(features & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
 				{
@@ -1122,7 +1202,7 @@
 	}
 }
 
-const VkPhysicalDeviceMemoryProperties &PhysicalDevice::getMemoryProperties() const
+const VkPhysicalDeviceMemoryProperties &PhysicalDevice::GetMemoryProperties()
 {
 	static const VkPhysicalDeviceMemoryProperties properties{
 		1,  // memoryTypeCount
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
index 4c8430b..2daeddc 100644
--- a/src/Vulkan/VkPhysicalDevice.hpp
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -46,9 +46,11 @@
 	void getProperties(VkPhysicalDeviceProtectedMemoryProperties *properties) const;
 	void getProperties(VkPhysicalDeviceSubgroupProperties *properties) const;
 	void getProperties(const VkExternalMemoryHandleTypeFlagBits *handleType, VkExternalImageFormatProperties *properties) const;
+	void getProperties(const VkExternalMemoryHandleTypeFlagBits *handleType, VkExternalBufferProperties *properties) const;
 	void getProperties(VkSamplerYcbcrConversionImageFormatProperties *properties) const;
 #ifdef __ANDROID__
 	void getProperties(VkPhysicalDevicePresentationPropertiesANDROID *properties) const;
+	void getProperties(VkAndroidHardwareBufferUsageANDROID *properties) const;
 #endif
 	void getProperties(const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) const;
 	void getProperties(const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) const;
@@ -58,7 +60,7 @@
 	void getProperties(VkPhysicalDeviceLineRasterizationPropertiesEXT *properties) const;
 	void getProperties(VkPhysicalDeviceProvokingVertexPropertiesEXT *properties) const;
 
-	void getFormatProperties(Format format, VkFormatProperties *pFormatProperties) const;
+	static void GetFormatProperties(Format format, VkFormatProperties *pFormatProperties);
 	void getImageFormatProperties(Format format, VkImageType type, VkImageTiling tiling,
 	                              VkImageUsageFlags usage, VkImageCreateFlags flags,
 	                              VkImageFormatProperties *pImageFormatProperties) const;
@@ -67,7 +69,7 @@
 	                              VkQueueFamilyProperties *pQueueFamilyProperties) const;
 	void getQueueFamilyProperties(uint32_t pQueueFamilyPropertyCount,
 	                              VkQueueFamilyProperties2 *pQueueFamilyProperties) const;
-	const VkPhysicalDeviceMemoryProperties &getMemoryProperties() const;
+	static const VkPhysicalDeviceMemoryProperties &GetMemoryProperties();
 
 private:
 	const VkPhysicalDeviceLimits &getLimits() const;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index b630658..09cd2b9 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -75,6 +75,9 @@
 #	include <android/log.h>
 #	include <hardware/gralloc1.h>
 #	include <sync/sync.h>
+#	ifdef SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+#		include "VkDeviceMemoryExternalAndroid.hpp"
+#	endif
 #endif
 
 #include "WSI/VkSwapchainKHR.hpp"
@@ -518,7 +521,7 @@
 	TRACE("GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice = %p, VkFormat format = %d, VkFormatProperties* pFormatProperties = %p)",
 	      physicalDevice, (int)format, pFormatProperties);
 
-	vk::Cast(physicalDevice)->getFormatProperties(format, pFormatProperties);
+	vk::PhysicalDevice::GetFormatProperties(format, pFormatProperties);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties)
@@ -531,7 +534,7 @@
 	memset(pImageFormatProperties, 0, sizeof(VkImageFormatProperties));
 
 	VkFormatProperties properties;
-	vk::Cast(physicalDevice)->getFormatProperties(format, &properties);
+	vk::PhysicalDevice::GetFormatProperties(format, &properties);
 
 	VkFormatFeatureFlags features;
 	switch(tiling)
@@ -656,7 +659,7 @@
 {
 	TRACE("(VkPhysicalDevice physicalDevice = %p, VkPhysicalDeviceMemoryProperties* pMemoryProperties = %p)", physicalDevice, pMemoryProperties);
 
-	*pMemoryProperties = vk::Cast(physicalDevice)->getMemoryProperties();
+	*pMemoryProperties = vk::PhysicalDevice::GetMemoryProperties();
 }
 
 VK_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *pName)
@@ -1085,7 +1088,7 @@
 		allocationInfo = allocationInfo->pNext;
 	}
 
-	VkResult result = vk::DeviceMemory::Create(pAllocator, pAllocateInfo, pMemory);
+	VkResult result = vk::DeviceMemory::Create(pAllocator, pAllocateInfo, pMemory, vk::Cast(device));
 	if(result != VK_SUCCESS)
 	{
 		return result;
@@ -1141,7 +1144,7 @@
 	}
 
 	const VkPhysicalDeviceMemoryProperties &memoryProperties =
-	    vk::Cast(device)->getPhysicalDevice()->getMemoryProperties();
+	    vk::PhysicalDevice::GetMemoryProperties();
 
 	// All SwiftShader memory types support this!
 	pMemoryFdProperties->memoryTypeBits = (1U << memoryProperties.memoryTypeCount) - 1U;
@@ -1180,7 +1183,7 @@
 	}
 
 	const VkPhysicalDeviceMemoryProperties &memoryProperties =
-	    vk::Cast(device)->getPhysicalDevice()->getMemoryProperties();
+	    vk::PhysicalDevice::GetMemoryProperties();
 
 	// All SwiftShader memory types support this!
 	pMemoryZirconHandleProperties->memoryTypeBits = (1U << memoryProperties.memoryTypeCount) - 1U;
@@ -1210,7 +1213,7 @@
 	TRACE("(VkDevice device = %p, const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo = %p, struct AHardwareBuffer **pBuffer = %p)",
 	      device, pInfo, pBuffer);
 
-	return vk::Cast(pInfo->memory)->exportAhb(pBuffer);
+	return vk::Cast(pInfo->memory)->exportAndroidHardwareBuffer(pBuffer);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
@@ -1218,7 +1221,7 @@
 	TRACE("(VkDevice device = %p, const struct AHardwareBuffer *buffer = %p, VkAndroidHardwareBufferPropertiesANDROID *pProperties = %p)",
 	      device, buffer, pProperties);
 
-	return vk::DeviceMemory::getAhbProperties(buffer, pProperties);
+	return vk::DeviceMemory::GetAndroidHardwareBufferProperties(device, buffer, pProperties);
 }
 #endif  // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
 
@@ -1271,7 +1274,7 @@
 	auto memory = vk::Cast(pMemory);
 
 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
-	const auto &memoryProperties = vk::Cast(pDevice)->getPhysicalDevice()->getMemoryProperties();
+	const auto &memoryProperties = vk::PhysicalDevice::GetMemoryProperties();
 	uint32_t typeIndex = memory->getMemoryTypeIndex();
 	ASSERT(typeIndex < memoryProperties.memoryTypeCount);
 	ASSERT(memoryProperties.memoryTypes[typeIndex].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT);
@@ -1669,6 +1672,8 @@
 				swapchainImage = true;
 			}
 			break;
+			case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID:
+				break;
 #endif
 			case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO:
 				// Do nothing. Should be handled by vk::Image::Create()
@@ -2862,6 +2867,12 @@
 			{
 				auto requirements = reinterpret_cast<VkMemoryDedicatedRequirements *>(extensionRequirements);
 				vk::Cast(device)->getRequirements(requirements);
+#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+				if(vk::Cast(pInfo->image)->getSupportedExternalMemoryHandleTypes() == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+				{
+					requirements->requiresDedicatedAllocation = VK_TRUE;
+				}
+#endif
 			}
 			break;
 			default:
@@ -3120,6 +3131,14 @@
 				ASSERT(!hasDeviceExtension(VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME));
 			}
 			break;
+#ifdef __ANDROID__
+			case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID:
+			{
+				auto properties = reinterpret_cast<VkAndroidHardwareBufferUsageANDROID *>(extensionProperties);
+				vk::Cast(physicalDevice)->getProperties(properties);
+			}
+			break;
+#endif
 			default:
 				LOG_TRAP("pImageFormatProperties->pNext sType = %s", vk::Stringify(extensionProperties->sType).c_str());
 				break;