Add derived class for every type of external memory

This CL removes the "external" member in vk::DeviceMemory
and instead uses derived classes for each type of external
memory, in order to achieve the same result without the
extra level of indirection.

Bug: b/199306480
Change-Id: I1cab3c94e5bb35f027b8fd242a060a511776f100
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/56930
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Commit-Queue: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index e3c8229..20fc6cd 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -15,102 +15,13 @@
 #include "VkDeviceMemory.hpp"
 #include "VkBuffer.hpp"
 #include "VkDevice.hpp"
-#include "VkDeviceMemoryExternalBase.hpp"
 #include "VkImage.hpp"
 #include "VkStringify.hpp"
 
 #include "VkConfig.hpp"
 
-namespace vk {
-
-// 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.
-// |instanceInit| is a function pointer used to initialize an instance inplace
-// according to a |pAllocateInfo| parameter.
-class ExternalMemoryTraits
-{
-public:
-	VkExternalMemoryHandleTypeFlagBits typeFlagBit;
-	size_t instanceSize;
-	void (*instanceInit)(void *external, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo);
-};
-
-// Template function that parses a |pAllocateInfo.pNext| chain to verify that
-// it asks for the creation or import of a memory type managed by implementation
-// class T. On success, return true and sets |pTraits| accordingly. Otherwise
-// return false.
-template<typename T>
-static bool parseCreateInfo(const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo,
-                            ExternalMemoryTraits *pTraits)
-{
-	if(T::SupportsAllocateInfo(extendedAllocationInfo))
-	{
-		pTraits->typeFlagBit = T::typeFlagBit;
-		pTraits->instanceSize = sizeof(T);
-		pTraits->instanceInit = [](void *external,
-		                           const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo) {
-			new(external) T(extendedAllocationInfo);
-		};
-		return true;
-	}
-	return false;
-}
-
-// DeviceMemory::ExternalBase implementation that uses host memory.
-// Not really external, but makes everything simpler.
-class DeviceMemoryHostExternalBase : public DeviceMemory::ExternalBase
-{
-public:
-	// Does not support any external memory type at all.
-	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0;
-
-	// Always return true as is used as a fallback in findTraits() below.
-	static bool SupportsAllocateInfo(const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
-	{
-		return true;
-	}
-
-	DeviceMemoryHostExternalBase(const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo) {}
-
-	VkResult allocate(size_t size, void **pBuffer) override
-	{
-		buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
-		if(!buffer)
-		{
-			return VK_ERROR_OUT_OF_DEVICE_MEMORY;
-		}
-
-		*pBuffer = buffer;
-		return VK_SUCCESS;
-	}
-
-	void deallocate(void * /* buffer */, size_t size) override
-	{
-		vk::deallocate(buffer, DEVICE_MEMORY);
-		buffer = nullptr;
-	}
-
-	VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
-	{
-		return typeFlagBit;
-	}
-
-#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
-	uint64_t getMemoryObjectId() const override
-	{
-		return (uint64_t)buffer;
-	}
-#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
-
-private:
-	void *buffer = nullptr;
-};
-
-}  // namespace vk
-
 // Host-allocated memory and host-mapped foreign memory
-class ExternalMemoryHost : public vk::DeviceMemory::ExternalBase
+class ExternalMemoryHost : public vk::DeviceMemory, public vk::ObjectBase<ExternalMemoryHost, VkDeviceMemory>
 {
 public:
 	struct AllocateInfo
@@ -127,7 +38,8 @@
 				if((extendedAllocationInfo.importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT) &&
 				   (extendedAllocationInfo.importMemoryHostPointerInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT))
 				{
-					UNSUPPORTED("extendedAllocationInfo.importMemoryHostPointerInfo->handleType");
+					UNSUPPORTED("extendedAllocationInfo.importMemoryHostPointerInfo->handleType, %d",
+					            int(extendedAllocationInfo.importMemoryHostPointerInfo->handleType));
 				}
 				hostPointer = extendedAllocationInfo.importMemoryHostPointerInfo->pHostPointer;
 				supported = true;
@@ -143,10 +55,10 @@
 		return info.supported;
 	}
 
-	explicit ExternalMemoryHost(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
-	    : allocateInfo(extendedAllocationInfo)
-	{
-	}
+	explicit ExternalMemoryHost(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice)
+	    : vk::DeviceMemory(pCreateInfo, pDevice)
+	    , allocateInfo(extendedAllocationInfo)
+	{}
 
 	VkResult allocate(size_t size, void **pBuffer) override
 	{
@@ -172,9 +84,9 @@
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
 
-// Helper struct to parse the VkMemoryAllocateInfo.pNext chain and
-// extract relevant information related to the handle type supported
-// by this DeviceMemory;:ExternalBase subclass.
+// Helper struct which reads the parsed allocation info and
+// extracts relevant information related to the handle type
+// supported by this DeviceMemory subclass.
 struct OpaqueFdAllocateInfo
 {
 	bool importFd = false;
@@ -183,7 +95,7 @@
 
 	OpaqueFdAllocateInfo() = default;
 
-	// Parse the VkMemoryAllocateInfo.pNext chain to initialize an OpaqueFdAllocateInfo.
+	// Read the parsed allocation info to initialize an OpaqueFdAllocateInfo.
 	OpaqueFdAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 	{
 		if(extendedAllocationInfo.importMemoryFdInfo)
@@ -230,69 +142,79 @@
 
 namespace vk {
 
-static void findTraits(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo,
-                       ExternalMemoryTraits *pTraits)
+VkResult DeviceMemory::Allocate(const VkAllocationCallbacks *pAllocator, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory, Device *device)
+{
+	*pMemory = VK_NULL_HANDLE;
+
+	vk::DeviceMemory::ExtendedAllocationInfo extendedAllocationInfo = {};
+	VkResult result = vk::DeviceMemory::ParseAllocationInfo(pAllocateInfo, &extendedAllocationInfo);
+	if(result != VK_SUCCESS)
+	{
+		return result;
+	}
+
+	result = Allocate(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, device);
+	if(result != VK_SUCCESS)
+	{
+		return result;
+	}
+
+	// Make sure the memory allocation is done now so that OOM errors can be checked now
+	return vk::Cast(*pMemory)->allocate();
+}
+
+VkResult DeviceMemory::Allocate(const VkAllocationCallbacks *pAllocator, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory,
+                                const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *device)
 {
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-	if(parseCreateInfo<AHardwareBufferExternalMemory>(extendedAllocationInfo, pTraits))
+	if(AHardwareBufferExternalMemory::SupportsAllocateInfo(extendedAllocationInfo))
 	{
-		return;
+		return AHardwareBufferExternalMemory::Create(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, device);
 	}
 #endif
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-	if(parseCreateInfo<OpaqueFdExternalMemory>(extendedAllocationInfo, pTraits))
+	if(OpaqueFdExternalMemory::SupportsAllocateInfo(extendedAllocationInfo))
 	{
-		return;
+		return OpaqueFdExternalMemory::Create(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, device);
 	}
 #endif
 #if VK_USE_PLATFORM_FUCHSIA
-	if(parseCreateInfo<zircon::VmoExternalMemory>(extendedAllocationInfo, pTraits))
+	if(zircon::VmoExternalMemory::SupportsAllocateInfo(extendedAllocationInfo))
 	{
-		return;
+		return zircon::VmoExternalMemory::Create(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, device);
 	}
 #endif
-	if(parseCreateInfo<ExternalMemoryHost>(extendedAllocationInfo, pTraits))
+	if(ExternalMemoryHost::SupportsAllocateInfo(extendedAllocationInfo))
 	{
-		return;
+		return ExternalMemoryHost::Create(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, device);
 	}
-	parseCreateInfo<DeviceMemoryHostExternalBase>(extendedAllocationInfo, pTraits);
+
+	return vk::DeviceMemoryInternal::Create(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, device);
 }
 
-DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *pDevice)
+DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, Device *pDevice)
     : size(pAllocateInfo->allocationSize)
     , memoryTypeIndex(pAllocateInfo->memoryTypeIndex)
     , device(pDevice)
 {
 	ASSERT(size);
-
-	ExternalMemoryTraits traits;
-	findTraits(extendedAllocationInfo, &traits);
-	traits.instanceInit(mem, extendedAllocationInfo);
-	external = reinterpret_cast<ExternalBase *>(mem);
-	external->setDevicePtr(device);
 }
 
 void DeviceMemory::destroy(const VkAllocationCallbacks *pAllocator)
 {
 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
-	device->emitDeviceMemoryReport(external->isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT, external->getMemoryObjectId(), 0 /* size */, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this));
+	device->emitDeviceMemoryReport(isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT, getMemoryObjectId(), 0 /* size */, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this));
 #endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 	if(buffer)
 	{
-		external->deallocate(buffer, size);
+		deallocate(buffer, size);
 		buffer = nullptr;
 	}
-	external->~ExternalBase();  // Call virtual destructor in place.
-	vk::deallocate(external, pAllocator);
 }
 
 size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pAllocateInfo)
 {
-	ExtendedAllocationInfo extendedAllocationInfo;
-	ParseAllocationInfo(pAllocateInfo, &extendedAllocationInfo);
-	ExternalMemoryTraits traits;
-	findTraits(extendedAllocationInfo, &traits);
-	return traits.instanceSize;
+	return 0;
 }
 
 VkResult DeviceMemory::ParseAllocationInfo(const VkMemoryAllocateInfo *pAllocateInfo, DeviceMemory::ExtendedAllocationInfo *extendedAllocationInfo)
@@ -393,12 +315,12 @@
 	VkResult result = VK_SUCCESS;
 	if(!buffer)
 	{
-		result = external->allocate(size, &buffer);
+		result = allocate(size, &buffer);
 	}
 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
 	if(result == VK_SUCCESS)
 	{
-		device->emitDeviceMemoryReport(external->isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT, external->getMemoryObjectId(), size, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this));
+		device->emitDeviceMemoryReport(isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT, getMemoryObjectId(), size, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this));
 	}
 	else
 	{
@@ -435,7 +357,7 @@
 		// memory, so this check should always pass.
 		return true;
 	}
-	VkExternalMemoryHandleTypeFlagBits handle_type_bit = external->getFlagBit();
+	VkExternalMemoryHandleTypeFlagBits handle_type_bit = getFlagBit();
 	if(!handle_type_bit)
 	{
 		// This device memory is not external and can accommodate
@@ -448,50 +370,47 @@
 	return (supportedHandleTypes & handle_type_bit) != 0;
 }
 
-bool DeviceMemory::hasExternalImageProperties() const
+// Allocate the memory according to |size|. On success return VK_SUCCESS
+// and sets |*pBuffer|.
+VkResult DeviceMemory::allocate(size_t size, void **pBuffer)
 {
-	return external && external->hasExternalImageProperties();
-}
-
-int DeviceMemory::externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const
-{
-	if(external)
+	buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
+	if(!buffer)
 	{
-		return external->externalImageRowPitchBytes(aspect);
+		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
 	}
 
-	// This function should never be called on non-external memory.
-	ASSERT(false);
-	return -1;
+	*pBuffer = buffer;
+	return VK_SUCCESS;
 }
 
-VkDeviceSize DeviceMemory::externalImageMemoryOffset(VkImageAspectFlagBits aspect) const
+// Deallocate previously allocated memory at |buffer|.
+void DeviceMemory::deallocate(void *buffer, size_t size)
 {
-	if(external)
-	{
-		return external->externalImageMemoryOffset(aspect);
-	}
+	vk::deallocate(buffer, DEVICE_MEMORY);
+	buffer = nullptr;
+}
 
-	// This function should never be called on non-external memory.
-	ASSERT(false);
-	return -1;
+// Return the handle type flag bit supported by this implementation.
+// A value of 0 corresponds to non-external memory.
+VkExternalMemoryHandleTypeFlagBits DeviceMemory::getFlagBit() const
+{
+	// Does not support any external memory type at all.
+	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0;
+	return typeFlagBit;
 }
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
 VkResult DeviceMemory::exportFd(int *pFd) const
 {
-	return external->exportFd(pFd);
+	return VK_ERROR_INVALID_EXTERNAL_HANDLE;
 }
 #endif
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
 VkResult DeviceMemory::exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const
 {
-	if(external->getFlagBit() != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
-	{
-		return VK_ERROR_OUT_OF_HOST_MEMORY;
-	}
-	return static_cast<AHardwareBufferExternalMemory *>(external)->exportAndroidHardwareBuffer(pAhb);
+	return VK_ERROR_OUT_OF_HOST_MEMORY;
 }
 
 VkResult DeviceMemory::GetAndroidHardwareBufferProperties(VkDevice &ahbDevice, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
@@ -503,7 +422,7 @@
 #if VK_USE_PLATFORM_FUCHSIA
 VkResult DeviceMemory::exportHandle(zx_handle_t *pHandle) const
 {
-	return external->exportHandle(pHandle);
+	return VK_ERROR_INVALID_EXTERNAL_HANDLE;
 }
 #endif
 
diff --git a/src/Vulkan/VkDeviceMemory.hpp b/src/Vulkan/VkDeviceMemory.hpp
index 098494c..77bf23a 100644
--- a/src/Vulkan/VkDeviceMemory.hpp
+++ b/src/Vulkan/VkDeviceMemory.hpp
@@ -22,11 +22,13 @@
 
 class Device;
 
-class DeviceMemory : public Object<DeviceMemory, VkDeviceMemory>
+class DeviceMemory
 {
 public:
 	struct ExtendedAllocationInfo
 	{
+		VkDeviceSize allocationSize = 0;
+		uint32_t memoryTypeIndex = 0;
 		const VkExportMemoryAllocateInfo *exportMemoryAllocateInfo = nullptr;
 		const VkImportMemoryHostPointerInfoEXT *importMemoryHostPointerInfo = nullptr;
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
@@ -41,22 +43,37 @@
 #endif
 	};
 
-	DeviceMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *pDevice);
+protected:
+	DeviceMemory(const VkMemoryAllocateInfo *pCreateInfo, Device *pDevice);
+
+public:
+	virtual ~DeviceMemory() {}
+
+	static VkResult Allocate(const VkAllocationCallbacks *pAllocator, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory, Device *device);
+
+	operator VkDeviceMemory()
+	{
+		return vk::TtoVkT<DeviceMemory, VkDeviceMemory>(this);
+	}
+
+	static inline DeviceMemory *Cast(VkDeviceMemory object)
+	{
+		return vk::VkTtoT<DeviceMemory, VkDeviceMemory>(object);
+	}
 
 	static size_t ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pCreateInfo);
-	static VkResult ParseAllocationInfo(const VkMemoryAllocateInfo *pAllocateInfo, DeviceMemory::ExtendedAllocationInfo *extendedAllocationInfo);
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
-	VkResult exportFd(int *pFd) const;
+	virtual VkResult exportFd(int *pFd) const;
 #endif
 
 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
-	VkResult exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const;
+	virtual VkResult exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const;
 	static VkResult GetAndroidHardwareBufferProperties(VkDevice &device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
 #endif
 
 #if VK_USE_PLATFORM_FUCHSIA
-	VkResult exportHandle(zx_handle_t *pHandle) const;
+	virtual VkResult exportHandle(zx_handle_t *pHandle) const;
 #endif
 
 	void destroy(const VkAllocationCallbacks *pAllocator);
@@ -71,21 +88,58 @@
 	bool checkExternalMemoryHandleType(
 	    VkExternalMemoryHandleTypeFlags supportedExternalMemoryHandleType) const;
 
-	// Internal implementation class for external memory. Platform-specific.
-	class ExternalBase;
+	// Some external device memories, such as Android hardware buffers, represent
+	// specific images with requirements.
+	virtual bool hasExternalImageProperties() const { return false; }
+	virtual int externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const { return 0; }
+	virtual VkDeviceSize externalImageMemoryOffset(VkImageAspectFlagBits aspect) const { return 0; }
 
-	bool hasExternalImageProperties() const;
-	int externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const;
-	VkDeviceSize externalImageMemoryOffset(VkImageAspectFlagBits aspect) const;
+protected:
+	// Allocate the memory according to |size|. On success return VK_SUCCESS
+	// and sets |*pBuffer|.
+	virtual VkResult allocate(size_t size, void **pBuffer);
+
+	// Deallocate previously allocated memory at |buffer|.
+	virtual void deallocate(void *buffer, size_t size);
+
+	// Return the handle type flag bit supported by this implementation.
+	// A value of 0 corresponds to non-external memory.
+	virtual VkExternalMemoryHandleTypeFlagBits getFlagBit() const;
+
+	virtual void setDevicePtr(Device *pDevice) {}
+
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+	virtual bool isImport() const
+	{
+		return false;
+	}
+
+	virtual uint64_t getMemoryObjectId() const
+	{
+		return (uint64_t)buffer;
+	}
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 
 private:
+	static VkResult ParseAllocationInfo(const VkMemoryAllocateInfo *pAllocateInfo, DeviceMemory::ExtendedAllocationInfo *extendedAllocationInfo);
+	static VkResult Allocate(const VkAllocationCallbacks *pAllocator, const VkMemoryAllocateInfo *pAllocateInfo, VkDeviceMemory *pMemory,
+	                         const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *device);
+
 	void *buffer = nullptr;
 	VkDeviceSize size = 0;
 	uint32_t memoryTypeIndex = 0;
-	ExternalBase *external = nullptr;
 	Device *device;
 };
 
+// This class represents a DeviceMemory object with no external memory
+class DeviceMemoryInternal : public DeviceMemory, public ObjectBase<DeviceMemoryInternal, VkDeviceMemory>
+{
+public:
+	DeviceMemoryInternal(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, Device *pDevice)
+	    : DeviceMemory(pCreateInfo, pDevice)
+	{}
+};
+
 static inline DeviceMemory *Cast(VkDeviceMemory object)
 {
 	return DeviceMemory::Cast(object);
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
index 1eab778..9085814 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
@@ -191,8 +191,9 @@
 	}
 }
 
-AHardwareBufferExternalMemory::AHardwareBufferExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
-    : allocateInfo(extendedAllocationInfo)
+AHardwareBufferExternalMemory::AHardwareBufferExternalMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice)
+    : vk::DeviceMemory(pCreateInfo, pDevice)
+    , allocateInfo(extendedAllocationInfo)
 {
 }
 
@@ -332,6 +333,11 @@
 
 VkResult AHardwareBufferExternalMemory::exportAndroidHardwareBuffer(AHardwareBuffer **pAhb) const
 {
+	if(getFlagBit() != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
+	{
+		return VK_ERROR_OUT_OF_HOST_MEMORY;
+	}
+
 	// 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.
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
index aa9f989..b8e5844 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
@@ -18,17 +18,16 @@
 #include "VkBuffer.hpp"
 #include "VkDevice.hpp"
 #include "VkDeviceMemory.hpp"
-#include "VkDeviceMemoryExternalBase.hpp"
 #include "VkImage.hpp"
 
 #include <vndk/hardware_buffer.h>
 
-class AHardwareBufferExternalMemory : public vk::DeviceMemory::ExternalBase
+class AHardwareBufferExternalMemory : public vk::DeviceMemory, public vk::ObjectBase<AHardwareBufferExternalMemory, VkDeviceMemory>
 {
 public:
-	// Helper struct to used the parse allocation info and extract
-	// relevant information related to the handle type supported
-	// by this DeviceMemory::ExternalBase subclass.
+	// Helper struct which reads the parsed allocation info and
+	// extracts relevant information related to the handle type
+	// supported by this DeviceMemory subclass.
 	struct AllocateInfo
 	{
 		bool importAhb = false;
@@ -39,7 +38,7 @@
 
 		AllocateInfo() = default;
 
-		// Used the parsed allocation info to initialize a AllocateInfo.
+		// Use the parsed allocation info to initialize a AllocateInfo.
 		AllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo);
 	};
 
@@ -51,7 +50,7 @@
 		return info.importAhb || info.exportAhb;
 	}
 
-	explicit AHardwareBufferExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo);
+	explicit AHardwareBufferExternalMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice);
 	~AHardwareBufferExternalMemory();
 
 	VkResult allocate(size_t size, void **pBuffer) override;
@@ -59,7 +58,7 @@
 
 	VkExternalMemoryHandleTypeFlagBits getFlagBit() const override { return typeFlagBit; }
 
-	VkResult exportAndroidHardwareBuffer(AHardwareBuffer **pAhb) const;
+	virtual VkResult exportAndroidHardwareBuffer(AHardwareBuffer **pAhb) const override final;
 
 	void setDevicePtr(vk::Device *pDevice) override { device = pDevice; }
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalBase.hpp b/src/Vulkan/VkDeviceMemoryExternalBase.hpp
deleted file mode 100644
index c8dc313..0000000
--- a/src/Vulkan/VkDeviceMemoryExternalBase.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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
-
-	// Some external device memories, such as Android hardware buffers, represent
-	// specific images with requirements.
-	virtual bool hasExternalImageProperties() const { return false; }
-	virtual int externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const { return 0; }
-	virtual VkDeviceSize externalImageMemoryOffset(VkImageAspectFlagBits aspect) const { return 0; }
-
-#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
-	virtual bool isImport() const
-	{
-		return false;
-	}
-
-	virtual uint64_t getMemoryObjectId() const
-	{
-		return 0;
-	}
-#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
-
-protected:
-	ExternalBase() = default;
-};
-
-}  // namespace vk
-
-#endif  // VK_DEVICE_MEMORY_EXTERNAL_BASE_HPP_
diff --git a/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp b/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
index 5c2c8f3..b7a4cef 100644
--- a/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "VkDeviceMemory.hpp"
 #include "VkStringify.hpp"
 
 #include "System/Debug.hpp"
@@ -21,12 +22,12 @@
 
 namespace zircon {
 
-class VmoExternalMemory : public vk::DeviceMemory::ExternalBase
+class VmoExternalMemory : public vk::DeviceMemory, public vk::ObjectBase<VmoExternalMemory, VkDeviceMemory>
 {
 public:
-	// Helper struct to parse the VkMemoryAllocateInfo.pNext chain and
-	// extract relevant information related to the handle type supported
-	// by this DeviceMemory::ExternalBase subclass.
+	// Helper struct which reads the parsed allocation info and
+	// extracts relevant information related to the handle type
+	// supported by this DeviceMemory subclass.
 	struct AllocateInfo
 	{
 		bool importHandle = false;
@@ -35,7 +36,7 @@
 
 		AllocateInfo() = default;
 
-		// Used the parsed allocation info to initialize a AllocateInfo.
+		// Use the parsed allocation info to initialize a AllocateInfo.
 		AllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
 		{
 			if(extendedAllocationInfo.importMemoryZirconHandleInfo)
@@ -67,8 +68,9 @@
 		return info.importHandle || info.exportHandle;
 	}
 
-	explicit VmoExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
-	    : allocateInfo(extendedAllocationInfo)
+	explicit VmoExternalMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice)
+	    : vk::DeviceMemory(pCreateInfo, pDevice)
+	    , allocateInfo(extendedAllocationInfo)
 	{
 	}
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
index 462dd7c..f4d7f66 100644
--- a/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalLinux.hpp
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "VkDeviceMemory.hpp"
+
 #include "System/Debug.hpp"
 #include "System/Linux/MemFd.hpp"
 
@@ -19,7 +21,7 @@
 #include <string.h>
 #include <sys/mman.h>
 
-class OpaqueFdExternalMemory : public vk::DeviceMemory::ExternalBase
+class OpaqueFdExternalMemory : public vk::DeviceMemory, public vk::ObjectBase<OpaqueFdExternalMemory, VkDeviceMemory>
 {
 public:
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
@@ -30,8 +32,9 @@
 		return info.importFd || info.exportFd;
 	}
 
-	explicit OpaqueFdExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
-	    : allocateInfo(extendedAllocationInfo)
+	explicit OpaqueFdExternalMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice)
+	    : vk::DeviceMemory(pCreateInfo, pDevice)
+	    , allocateInfo(extendedAllocationInfo)
 	{
 	}
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalMac.hpp b/src/Vulkan/VkDeviceMemoryExternalMac.hpp
index 4d35810..b68f618 100644
--- a/src/Vulkan/VkDeviceMemoryExternalMac.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalMac.hpp
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "VkDeviceMemory.hpp"
+
 #include "System/Debug.hpp"
 
 #include <errno.h>
@@ -55,7 +57,7 @@
 
 // An implementation of OpaqueFdExternalMemory that relies on shm_open().
 // Useful on OS X which do not have Linux memfd regions.
-class OpaqueFdExternalMemory : public vk::DeviceMemory::ExternalBase
+class OpaqueFdExternalMemory : public vk::DeviceMemory, public vk::ObjectBase<OpaqueFdExternalMemory, VkDeviceMemory>
 {
 public:
 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
@@ -66,8 +68,9 @@
 		return info.importFd || info.exportFd;
 	}
 
-	explicit OpaqueFdExternalMemory(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
-	    : allocateInfo(extendedAllocationInfo)
+	explicit OpaqueFdExternalMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice)
+	    : vk::DeviceMemory(pCreateInfo, pDevice)
+	    , allocateInfo(extendedAllocationInfo)
 	{
 	}
 
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index f2551d6..1dcb45e 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -1025,21 +1025,8 @@
 	TRACE("(VkDevice device = %p, const VkMemoryAllocateInfo* pAllocateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkDeviceMemory* pMemory = %p)",
 	      device, pAllocateInfo, pAllocator, pMemory);
 
-	vk::DeviceMemory::ExtendedAllocationInfo extendedAllocationInfo = {};
-	VkResult result = vk::DeviceMemory::ParseAllocationInfo(pAllocateInfo, &extendedAllocationInfo);
-	if(result != VK_SUCCESS)
-	{
-		return result;
-	}
+	VkResult result = vk::DeviceMemory::Allocate(pAllocator, pAllocateInfo, pMemory, vk::Cast(device));
 
-	result = vk::DeviceMemory::Create(pAllocator, pAllocateInfo, pMemory, extendedAllocationInfo, vk::Cast(device));
-	if(result != VK_SUCCESS)
-	{
-		return result;
-	}
-
-	// Make sure the memory allocation is done now so that OOM errors can be checked now
-	result = vk::Cast(*pMemory)->allocate();
 	if(result != VK_SUCCESS)
 	{
 		vk::destroy(*pMemory, pAllocator);