Add baseline VK_EXT_device_memory_report support

This initial implementation will only emit device memory report
callbacks upon vkAllocateMemory and vkFreeMemory.

This extension will be enabled on API 31 and above.

VkDeviceMemoryExternalAndroid.hpp is not needed in CMakeLists.txt since
Android uses build blueprint.

Bug: b/158094132
Test: dEQP-VK.memory.device_memory_report.create_and_destroy_object.*
Test: dEQP-VK.memory.device_memory_report.vk_device_memory.*
Test: dEQP-VK.memory.device_memory_report.external_memory.*
Change-Id: I519b8c7efed15924e2ac8dbb8ab806d44f4fc1ed
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/50108
Tested-by: Yiwei Zhang <zzyiwei@google.com>
Presubmit-Ready: Yiwei Zhang <zzyiwei@google.com>
Reviewed-by: Jason Macnak <natsu@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Android.bp b/src/Android.bp
index 5ccc5b4..8888910 100644
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -634,6 +634,7 @@
         "-DLOG_TAG=\"swiftshader\"",
         "-DSWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER",
         "-DSWIFTSHADER_ENABLE_ASTC",  // TODO(b/150130101)
+        //"-DSWIFTSHADER_DEVICE_MEMORY_REPORT",
     ],
 
     srcs: [
diff --git a/src/Vulkan/CMakeLists.txt b/src/Vulkan/CMakeLists.txt
index 4652917..1eb2fd4 100644
--- a/src/Vulkan/CMakeLists.txt
+++ b/src/Vulkan/CMakeLists.txt
@@ -46,7 +46,6 @@
     VkDevice.hpp
     VkDeviceMemory.cpp
     VkDeviceMemory.hpp
-    VkDeviceMemoryExternalAndroid.hpp
     VkDeviceMemoryExternalLinux.hpp
     VkEvent.hpp
     VkFence.hpp
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 4cdca03..e673abe 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -146,6 +146,22 @@
 		debugger.server = vk::dbg::Server::create(debugger.context, atoi(port));
 	}
 #endif  // ENABLE_VK_DEBUGGER
+
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+	const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
+	while(extensionCreateInfo)
+	{
+		if(extensionCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT)
+		{
+			auto deviceMemoryReportCreateInfo = reinterpret_cast<const VkDeviceDeviceMemoryReportCreateInfoEXT *>(pCreateInfo->pNext);
+			if(deviceMemoryReportCreateInfo->pfnUserCallback != nullptr)
+			{
+				deviceMemoryReportCallbacks.emplace_back(deviceMemoryReportCreateInfo->pfnUserCallback, deviceMemoryReportCreateInfo->pUserData);
+			}
+		}
+		extensionCreateInfo = extensionCreateInfo->pNext;
+	}
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 }
 
 void Device::destroy(const VkAllocationCallbacks *pAllocator)
@@ -375,4 +391,27 @@
 	}
 }
 
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+void Device::emitDeviceMemoryReport(VkDeviceMemoryReportEventTypeEXT type, uint64_t memoryObjectId, VkDeviceSize size, VkObjectType objectType, uint64_t objectHandle, uint32_t heapIndex)
+{
+	if(deviceMemoryReportCallbacks.empty()) return;
+
+	const VkDeviceMemoryReportCallbackDataEXT callbackData = {
+		VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT,  // sType
+		nullptr,                                                   // pNext
+		0,                                                         // flags
+		type,                                                      // type
+		memoryObjectId,                                            // memoryObjectId
+		size,                                                      // size
+		objectType,                                                // objectType
+		objectHandle,                                              // objectHandle
+		heapIndex,                                                 // heapIndex
+	};
+	for(const auto &callback : deviceMemoryReportCallbacks)
+	{
+		callback.first(&callbackData, callback.second);
+	}
+}
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
+
 }  // namespace vk
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 7f67ffa..0129657 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -169,6 +169,10 @@
 	VkResult setDebugUtilsObjectName(const VkDebugUtilsObjectNameInfoEXT *pNameInfo);
 	VkResult setDebugUtilsObjectTag(const VkDebugUtilsObjectTagInfoEXT *pTagInfo);
 
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+	void emitDeviceMemoryReport(VkDeviceMemoryReportEventTypeEXT type, uint64_t memoryObjectId, VkDeviceSize size, VkObjectType objectType, uint64_t objectHandle, uint32_t heapIndex = 0);
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
+
 private:
 	PhysicalDevice *const physicalDevice = nullptr;
 	Queue *const queues = nullptr;
@@ -193,6 +197,10 @@
 		std::shared_ptr<vk::dbg::Server> server;
 	} debugger;
 #endif  // ENABLE_VK_DEBUGGER
+
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+	std::vector<std::pair<PFN_vkDeviceMemoryReportCallbackEXT, void *>> deviceMemoryReportCallbacks;
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 };
 
 using DispatchableDevice = DispatchableObject<Device, VkDevice>;
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index 32fad70..c84eb38 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -73,7 +73,7 @@
 
 	VkResult allocate(size_t size, void **pBuffer) override
 	{
-		void *buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
+		buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
 		if(!buffer)
 		{
 			return VK_ERROR_OUT_OF_DEVICE_MEMORY;
@@ -83,15 +83,26 @@
 		return VK_SUCCESS;
 	}
 
-	void deallocate(void *buffer, size_t size) override
+	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
@@ -235,6 +246,9 @@
 
 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));
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 	if(buffer)
 	{
 		external->deallocate(buffer, size);
@@ -255,6 +269,9 @@
 {
 	if(size > MAX_MEMORY_ALLOCATION_SIZE)
 	{
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+		device->emitDeviceMemoryReport(VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT, 0 /* memoryObjectId */, size, VK_OBJECT_TYPE_DEVICE_MEMORY, 0 /* objectHandle */);
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
 	}
 
@@ -263,6 +280,16 @@
 	{
 		result = external->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));
+	}
+	else
+	{
+		device->emitDeviceMemoryReport(VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT, 0 /* memoryObjectId */, size, VK_OBJECT_TYPE_DEVICE_MEMORY, 0 /* objectHandle */);
+	}
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 	return result;
 }
 
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
index 7daa09b..8030544 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.cpp
@@ -12,19 +12,14 @@
 // 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 "VkDeviceMemoryExternalAndroid.hpp"
-
-#	include "System/Debug.hpp"
-#	include "VkDestroy.hpp"
-#	include "VkFormat.hpp"
-#	include "VkObject.hpp"
-#	include "VkPhysicalDevice.hpp"
-#	include "VkStringify.hpp"
-
-#	include <android/hardware_buffer.h>
-#	include <vndk/hardware_buffer.h>
+#include "VkDestroy.hpp"
+#include "VkFormat.hpp"
+#include "VkObject.hpp"
+#include "VkPhysicalDevice.hpp"
+#include "VkStringify.hpp"
+#include "System/Debug.hpp"
 
 namespace {
 
@@ -323,7 +318,7 @@
 	}
 }
 
-VkResult AHardwareBufferExternalMemory::importAndroidHardwareBuffer(struct AHardwareBuffer *buffer, void **pBuffer)
+VkResult AHardwareBufferExternalMemory::importAndroidHardwareBuffer(AHardwareBuffer *buffer, void **pBuffer)
 {
 	ahb = buffer;
 
@@ -410,7 +405,7 @@
 	return VK_SUCCESS;
 }
 
-VkResult AHardwareBufferExternalMemory::exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const
+VkResult AHardwareBufferExternalMemory::exportAndroidHardwareBuffer(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*
@@ -436,7 +431,7 @@
 	return VK_SUCCESS;
 }
 
-VkResult AHardwareBufferExternalMemory::GetAndroidHardwareBufferProperties(VkDevice &device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
+VkResult AHardwareBufferExternalMemory::GetAndroidHardwareBufferProperties(VkDevice &device, const AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
 {
 	VkResult result = VK_SUCCESS;
 
@@ -496,4 +491,12 @@
 	return GetBytesFromAHBFormat(ahbDesc.format) * ahbDesc.stride;
 }
 
-#endif  // SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+uint64_t AHardwareBufferExternalMemory::getMemoryObjectId() const
+{
+	uint64_t id = 0;
+	int ret = AHardwareBuffer_getId(ahb, &id);
+	ASSERT(ret == 0);
+	return id;
+}
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
diff --git a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
index 73eb51a..7842a4c 100644
--- a/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalAndroid.hpp
@@ -15,15 +15,13 @@
 #ifndef VK_DEVICE_MEMORY_EXTERNAL_ANDROID_HPP_
 #define VK_DEVICE_MEMORY_EXTERNAL_ANDROID_HPP_
 
-#if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
+#include "VkBuffer.hpp"
+#include "VkDevice.hpp"
+#include "VkDeviceMemory.hpp"
+#include "VkDeviceMemoryExternalBase.hpp"
+#include "VkImage.hpp"
 
-#	include "VkBuffer.hpp"
-#	include "VkDevice.hpp"
-#	include "VkDeviceMemory.hpp"
-#	include "VkDeviceMemoryExternalBase.hpp"
-#	include "VkImage.hpp"
-
-#	include <android/hardware_buffer.h>
+#include <vndk/hardware_buffer.h>
 
 class AHardwareBufferExternalMemory : public vk::DeviceMemory::ExternalBase
 {
@@ -35,7 +33,7 @@
 	{
 		bool importAhb = false;
 		bool exportAhb = false;
-		struct AHardwareBuffer *ahb = nullptr;
+		AHardwareBuffer *ahb = nullptr;
 		vk::Image *imageHandle = nullptr;
 		vk::Buffer *bufferHandle = nullptr;
 
@@ -61,28 +59,35 @@
 
 	VkExternalMemoryHandleTypeFlagBits getFlagBit() const override { return typeFlagBit; }
 
-	VkResult exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const override;
+	VkResult exportAndroidHardwareBuffer(AHardwareBuffer **pAhb) const override;
 
 	void setDevicePtr(vk::Device *pDevice) override { device = pDevice; }
 	bool isAndroidHardwareBuffer() override { return true; }
 
 	static VkResult GetAndroidHardwareBufferFormatProperties(const AHardwareBuffer_Desc &ahbDesc, VkAndroidHardwareBufferFormatPropertiesANDROID *pFormat);
-	static VkResult GetAndroidHardwareBufferProperties(VkDevice &device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
+	static VkResult GetAndroidHardwareBufferProperties(VkDevice &device, const AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
 
 	bool hasExternalImageProperties() const override final { return true; }
 	int externalImageRowPitchBytes() const override final;
 
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+	bool isImport() const override
+	{
+		return allocateInfo.importAhb;
+	}
+	uint64_t getMemoryObjectId() const override;
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
+
 private:
-	VkResult importAndroidHardwareBuffer(struct AHardwareBuffer *buffer, void **pBuffer);
+	VkResult importAndroidHardwareBuffer(AHardwareBuffer *buffer, void **pBuffer);
 	VkResult allocateAndroidHardwareBuffer(void **pBuffer);
 	VkResult lockAndroidHardwareBuffer(void **pBuffer);
 	VkResult unlockAndroidHardwareBuffer();
 
-	struct AHardwareBuffer *ahb = nullptr;
+	AHardwareBuffer *ahb = nullptr;
 	AHardwareBuffer_Desc ahbDesc = {};
 	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
index 198945e..1eb4a6a 100644
--- a/src/Vulkan/VkDeviceMemoryExternalBase.hpp
+++ b/src/Vulkan/VkDeviceMemoryExternalBase.hpp
@@ -62,6 +62,18 @@
 	virtual bool hasExternalImageProperties() const { return false; }
 	virtual int externalImageRowPitchBytes() 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;
 };
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 2db39d7..225adf7 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -217,6 +217,14 @@
 	features->shaderSubgroupExtendedTypes = VK_TRUE;
 }
 
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+template<typename T>
+static void getPhysicalDeviceDeviceMemoryReportFeaturesEXT(T *features)
+{
+	features->deviceMemoryReport = VK_TRUE;
+}
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
+
 template<typename T>
 static void getPhysicalDeviceVulkan12Features(T *features)
 {
@@ -320,6 +328,11 @@
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR:
 				getPhysicalDeviceShaderSubgroupExtendedTypesFeatures(reinterpret_cast<VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *>(curExtension));
 				break;
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT:
+				getPhysicalDeviceDeviceMemoryReportFeaturesEXT(reinterpret_cast<VkPhysicalDeviceDeviceMemoryReportFeaturesEXT *>(curExtension));
+				break;
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 			default:
 				LOG_TRAP("curExtension->pNext->sType = %s", vk::Stringify(curExtension->sType).c_str());
 				break;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index efa8272..26b23c0 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -389,6 +389,9 @@
 	{ VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, VK_EXT_PROVOKING_VERTEX_SPEC_VERSION },
 	{ VK_GOOGLE_SAMPLER_FILTERING_PRECISION_EXTENSION_NAME, VK_GOOGLE_SAMPLER_FILTERING_PRECISION_SPEC_VERSION },
 	{ VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION },
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+	{ VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION },
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 	// Vulkan 1.2 promoted extensions
 	{ VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION },
 	{ VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME, VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION },
@@ -765,6 +768,14 @@
 				(void)imagelessFramebufferFeatures->imagelessFramebuffer;
 			}
 			break;
+#ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT:
+			{
+				const VkPhysicalDeviceDeviceMemoryReportFeaturesEXT *deviceMemoryReportFeatures = reinterpret_cast<const VkPhysicalDeviceDeviceMemoryReportFeaturesEXT *>(extensionCreateInfo);
+				(void)deviceMemoryReportFeatures->deviceMemoryReport;
+			}
+			break;
+#endif  // SWIFTSHADER_DEVICE_MEMORY_REPORT
 			default:
 				// "the [driver] must skip over, without processing (other than reading the sType and pNext members) any structures in the chain with sType values not defined by [supported extenions]"
 				LOG_TRAP("pCreateInfo->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());