Merge "Hint buffer creations for VulkanAllocateHostMemory" into main
diff --git a/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp b/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp
index f7a612c..7bd14a9 100644
--- a/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp
+++ b/common/end2end/GfxstreamEnd2EndVkSnapshotPipelineTests.cpp
@@ -526,6 +526,7 @@
     commandBuffer->reset();
 
     SnapshotSaveAndLoad();
+    ASSERT_THAT(device->getFenceStatus(*fence), IsVkSuccess());
     // TODO(b/332763326): fix validation layer complain about unreleased pipeline layout
 
     // Try to draw something.
diff --git a/guest/platform/kumquat/VirtGpuKumquat.h b/guest/platform/kumquat/VirtGpuKumquat.h
index d940ffd..d22f210 100644
--- a/guest/platform/kumquat/VirtGpuKumquat.h
+++ b/guest/platform/kumquat/VirtGpuKumquat.h
@@ -17,7 +17,13 @@
 #pragma once
 
 #include "VirtGpu.h"
+
+// Blueprint and Meson builds place things differently
+#if defined(ANDROID)
+#include "virtgpu_kumquat_ffi.h"
+#else
 #include "virtgpu_kumquat/virtgpu_kumquat_ffi.h"
+#endif
 
 class VirtGpuKumquatResource : public std::enable_shared_from_this<VirtGpuKumquatResource>,
                                public VirtGpuResource {
diff --git a/guest/platform/kumquat/VirtGpuKumquatBlob.cpp b/guest/platform/kumquat/VirtGpuKumquatBlob.cpp
index cd0e3e0..991d53d 100644
--- a/guest/platform/kumquat/VirtGpuKumquatBlob.cpp
+++ b/guest/platform/kumquat/VirtGpuKumquatBlob.cpp
@@ -23,7 +23,6 @@
 #include <cstring>
 
 #include "VirtGpuKumquat.h"
-#include "virtgpu_kumquat/virtgpu_kumquat_ffi.h"
 
 VirtGpuKumquatResource::VirtGpuKumquatResource(struct virtgpu_kumquat* virtGpu, uint32_t blobHandle,
                                                uint32_t resourceHandle, uint64_t size)
@@ -53,7 +52,8 @@
 
     ret = virtgpu_kumquat_resource_map(mVirtGpu, &map);
     if (ret < 0) {
-        ALOGE("Mapping failed with %s", strerror(errno));
+        ALOGE("Mapping failed with %s for resource %u blob %u", strerror(errno), mResourceHandle,
+              mBlobHandle);
         return nullptr;
     }
 
diff --git a/guest/platform/kumquat/VirtGpuKumquatDevice.cpp b/guest/platform/kumquat/VirtGpuKumquatDevice.cpp
index 6101cc1..774c9dc 100644
--- a/guest/platform/kumquat/VirtGpuKumquatDevice.cpp
+++ b/guest/platform/kumquat/VirtGpuKumquatDevice.cpp
@@ -26,15 +26,13 @@
 
 #include "VirtGpuKumquat.h"
 #include "virtgpu_gfxstream_protocol.h"
-#include "virtgpu_kumquat/virtgpu_kumquat_ffi.h"
 
 #define PARAM(x) \
     (struct VirtGpuParam) { x, #x, 0 }
 
 static inline uint32_t align_up(uint32_t n, uint32_t a) { return ((n + a - 1) / a) * a; }
 
-VirtGpuKumquatDevice::VirtGpuKumquatDevice(enum VirtGpuCapset capset, int fd)
-    : VirtGpuDevice(capset) {
+VirtGpuKumquatDevice::VirtGpuKumquatDevice(enum VirtGpuCapset capset, int) : VirtGpuDevice(capset) {
     struct VirtGpuParam params[] = {
         PARAM(VIRTGPU_KUMQUAT_PARAM_3D_FEATURES),
         PARAM(VIRTGPU_KUMQUAT_PARAM_CAPSET_QUERY_FIX),
@@ -60,7 +58,7 @@
     processName = getprogname();
 #endif
 
-    ret = virtgpu_kumquat_init(&mVirtGpu);
+    ret = virtgpu_kumquat_init(&mVirtGpu, nullptr);
     if (ret) {
         ALOGV("Failed to init virtgpu kumquat");
         return;
diff --git a/guest/platform/kumquat/VirtGpuKumquatSync.cpp b/guest/platform/kumquat/VirtGpuKumquatSync.cpp
index d152bff..47884fc 100644
--- a/guest/platform/kumquat/VirtGpuKumquatSync.cpp
+++ b/guest/platform/kumquat/VirtGpuKumquatSync.cpp
@@ -23,9 +23,24 @@
 VirtGpuKumquatSyncHelper::VirtGpuKumquatSyncHelper() {}
 
 int VirtGpuKumquatSyncHelper::wait(int syncFd, int timeoutMilliseconds) {
-    (void)syncFd;
     (void)timeoutMilliseconds;
-    return -1;
+    // So far, syncfds are EventFd in the Kumquat layer. This may change
+    uint64_t count = 1;
+    ssize_t bytes_read = read(syncFd, &count, sizeof(count));
+
+    if (bytes_read < 0) {
+        return bytes_read;
+    }
+
+    // A successful read decrements the eventfd's counter to zero.  In
+    // case the eventfd is waited on again, or a dup is waited on, we
+    // have to write to the eventfd for the next read.
+    ssize_t bytes_written = write(syncFd, &count, sizeof(count));
+    if (bytes_written < 0) {
+        return bytes_written;
+    }
+
+    return 0;
 }
 
 int VirtGpuKumquatSyncHelper::dup(int syncFd) { return ::dup(syncFd); }
diff --git a/host/vulkan/VkCommonOperations.cpp b/host/vulkan/VkCommonOperations.cpp
index 21b1ff7..529dd1b 100644
--- a/host/vulkan/VkCommonOperations.cpp
+++ b/host/vulkan/VkCommonOperations.cpp
@@ -826,16 +826,20 @@
             deviceInfos[i].supportsDriverProperties =
                 extensionsSupported(deviceExts, {VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME}) ||
                 (deviceInfos[i].physdevProps.apiVersion >= VK_API_VERSION_1_2);
+            deviceInfos[i].supportsExternalMemoryHostProps = extensionsSupported(deviceExts, {VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME});
 
             if (!sVkEmulation->getPhysicalDeviceProperties2Func) {
                 ERR("Warning: device claims to support ID properties "
                     "but vkGetPhysicalDeviceProperties2 could not be found");
             }
         }
-
         if (sVkEmulation->getPhysicalDeviceProperties2Func) {
+            VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProps = {
+                .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT,
+            };
             VkPhysicalDeviceProperties2 deviceProps = {
-                VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
+                .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
+
             };
             VkPhysicalDeviceIDProperties idProps = {
                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR,
@@ -854,9 +858,12 @@
                 vk_append_struct(&devicePropsChain, &driverProps);
             }
 
+            if(deviceInfos[i].supportsExternalMemoryHostProps) {
+                vk_append_struct(&devicePropsChain, &externalMemoryHostProps);
+            }
             sVkEmulation->getPhysicalDeviceProperties2Func(physdevs[i], &deviceProps);
-
             deviceInfos[i].idProps = vk_make_orphan_copy(idProps);
+            deviceInfos[i].externalMemoryHostProps = vk_make_orphan_copy(externalMemoryHostProps);
 
             std::stringstream driverVendorBuilder;
             driverVendorBuilder << "Vendor " << std::hex << std::setfill('0') << std::showbase
@@ -990,7 +997,6 @@
     // in use cases that make sense, if/when they come up.
 
     std::vector<uint32_t> deviceScores(physdevCount, 0);
-
     for (uint32_t i = 0; i < physdevCount; ++i) {
         uint32_t deviceScore = 0;
         if (deviceInfos[i].hasGraphicsQueueFamily) deviceScore += 10000;
diff --git a/host/vulkan/VkCommonOperations.h b/host/vulkan/VkCommonOperations.h
index 43ebc91..a896a2a 100644
--- a/host/vulkan/VkCommonOperations.h
+++ b/host/vulkan/VkCommonOperations.h
@@ -206,6 +206,7 @@
         bool supportsDmaBuf = false;
         bool supportsIdProperties = false;
         bool supportsDriverProperties = false;
+        bool supportsExternalMemoryHostProps = false;
         bool hasSamplerYcbcrConversionExtension = false;
         bool supportsSamplerYcbcrConversion = false;
         bool glInteropSupported = false;
@@ -220,6 +221,7 @@
         VkPhysicalDeviceProperties physdevProps;
         VkPhysicalDeviceMemoryProperties memProps;
         VkPhysicalDeviceIDPropertiesKHR idProps;
+        VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProps;
 
         std::string driverVendor;
         std::string driverVersion;
diff --git a/host/vulkan/VkDecoderGlobalState.cpp b/host/vulkan/VkDecoderGlobalState.cpp
index 2d2ea2b..013acb4 100644
--- a/host/vulkan/VkDecoderGlobalState.cpp
+++ b/host/vulkan/VkDecoderGlobalState.cpp
@@ -194,6 +194,7 @@
 static uint32_t kTemporaryContextIdForSnapshotLoading = 1;
 
 static std::unordered_set<std::string> kSnapshotAppAllowList = {"Chromium"};
+static std::unordered_set<std::string> kSnapshotEngineAllowList = {"ANGLE"};
 
 #define DEFINE_BOXED_HANDLE_TYPE_TAG(type) Tag_##type,
 
@@ -676,6 +677,22 @@
                 }
             }
         }
+
+        // Fences
+        std::vector<VkFence> unsignaledFencesBoxed;
+        for (const auto& fence : mFenceInfo) {
+            if (!fence.second.boxed) {
+                continue;
+            }
+            const auto& device = fence.second.device;
+            const auto& deviceInfo = android::base::find(mDeviceInfo, device);
+            VulkanDispatch* dvk = dispatch_VkDevice(deviceInfo->boxed);
+            if (VK_NOT_READY == dvk->vkGetFenceStatus(device, fence.first)) {
+                unsignaledFencesBoxed.push_back(fence.second.boxed);
+            }
+        }
+        stream->putBe64(unsignaledFencesBoxed.size());
+        stream->write(unsignaledFencesBoxed.data(), unsignaledFencesBoxed.size() * sizeof(VkFence));
         mSnapshotState = SnapshotState::Normal;
     }
 
@@ -857,7 +874,22 @@
                 poolIds.data(), whichPool.data(), pendingAlloc.data(), writeStartingIndices.data(),
                 writeDescriptorSets.size(), writeDescriptorSets.data());
         }
-
+        // Fences
+        uint64_t fenceCount = stream->getBe64();
+        std::vector<VkFence> unsignaledFencesBoxed(fenceCount);
+        stream->read(unsignaledFencesBoxed.data(), fenceCount * sizeof(VkFence));
+        for (VkFence boxedFence : unsignaledFencesBoxed) {
+            VkFence unboxedFence = unbox_VkFence(boxedFence);
+            auto it = mFenceInfo.find(unboxedFence);
+            if (it == mFenceInfo.end()) {
+                GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+                    << "Snapshot load failure: unrecognized VkFence";
+            }
+            const auto& device = it->second.device;
+            const auto& deviceInfo = android::base::find(mDeviceInfo, device);
+            VulkanDispatch* dvk = dispatch_VkDevice(deviceInfo->boxed);
+            dvk->vkResetFences(device, 1, &unboxedFence);
+        }
 #ifdef GFXSTREAM_ENABLE_HOST_VK_SNAPSHOT
         if (!mInstanceInfo.empty()) {
             get_emugl_vm_operations().setStatSnapshotUseVulkan();
@@ -1009,9 +1041,9 @@
 
 #ifdef GFXSTREAM_ENABLE_HOST_VK_SNAPSHOT
         // TODO: bug 129484301
-        if (!m_emu->features.VulkanSnapshots.enabled
-                || kSnapshotAppAllowList.find(info.applicationName)
-                        == kSnapshotAppAllowList.end()) {
+        if (!m_emu->features.VulkanSnapshots.enabled ||
+            (kSnapshotAppAllowList.find(info.applicationName) == kSnapshotAppAllowList.end() &&
+             kSnapshotEngineAllowList.find(info.engineName) == kSnapshotEngineAllowList.end())) {
             get_emugl_vm_operations().setSkipSnapshotSave(true);
             get_emugl_vm_operations().setSkipSnapshotSaveReason(SNAPSHOT_SKIP_UNSUPPORTED_VK_APP);
         }
@@ -2696,6 +2728,13 @@
     VkResult on_vkCreateFence(android::base::BumpPool* pool, VkDevice boxed_device,
                               const VkFenceCreateInfo* pCreateInfo,
                               const VkAllocationCallbacks* pAllocator, VkFence* pFence) {
+        VkFenceCreateInfo localCreateInfo;
+        if (mSnapshotState == SnapshotState::Loading) {
+            // On snapshot load we create all fences as signaled then reset those that are not.
+            localCreateInfo = *pCreateInfo;
+            pCreateInfo = &localCreateInfo;
+            localCreateInfo.flags |= VK_FENCE_CREATE_SIGNALED_BIT;
+        }
         auto device = unbox_VkDevice(boxed_device);
         auto vk = dispatch_VkDevice(boxed_device);
 
@@ -4820,10 +4859,16 @@
         VkImportMemoryHostPointerInfoEXT importHostInfoPrivate{};
         if (hostVisible && m_emu->features.VulkanAllocateHostMemory.enabled &&
             localAllocInfo.pNext == nullptr) {
-            VkDeviceSize alignedSize = __ALIGN(localAllocInfo.allocationSize, kPageSizeforBlob);
+            if (!m_emu || !m_emu->deviceInfo.supportsExternalMemoryHostProps) {
+                ERR("VK_EXT_EXTERNAL_MEMORY_HOST is not supported, cannot use "
+                    "VulkanAllocateHostMemory");
+                return VK_ERROR_INCOMPATIBLE_DRIVER;
+            }
+            VkDeviceSize alignmentSize = m_emu->deviceInfo.externalMemoryHostProps.minImportedHostPointerAlignment;
+            VkDeviceSize alignedSize = __ALIGN(localAllocInfo.allocationSize, alignmentSize);
             localAllocInfo.allocationSize = alignedSize;
             privateMemory =
-                std::make_shared<PrivateMemory>(kPageSizeforBlob, localAllocInfo.allocationSize);
+                std::make_shared<PrivateMemory>(alignmentSize, localAllocInfo.allocationSize);
             mappedPtr = privateMemory->getAddr();
             importHostInfoPrivate = {
                 .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
@@ -4831,25 +4876,28 @@
                 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
                 .pHostPointer = mappedPtr};
 
-            VkMemoryHostPointerPropertiesEXT pMemoryHostPointerProperties = {
+            VkMemoryHostPointerPropertiesEXT memoryHostPointerProperties = {
                 .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
                 .pNext = NULL,
                 .memoryTypeBits = 0,
             };
-            vk->vkGetMemoryHostPointerPropertiesEXT(device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, mappedPtr, &pMemoryHostPointerProperties);
 
-            if (pMemoryHostPointerProperties.memoryTypeBits == 0) {
-                // Memory import operation not supported by the driver.
+            vk->vkGetMemoryHostPointerPropertiesEXT(
+                device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, mappedPtr,
+                &memoryHostPointerProperties);
+
+            if (memoryHostPointerProperties.memoryTypeBits == 0) {
+                ERR("Cannot find suitable memory type for VulkanAllocateHostMemory");
                 return VK_ERROR_INCOMPATIBLE_DRIVER;
             }
 
-            if (((1u << localAllocInfo.memoryTypeIndex) & pMemoryHostPointerProperties.memoryTypeBits) == 0) {
+            if (((1u << localAllocInfo.memoryTypeIndex) & memoryHostPointerProperties.memoryTypeBits) == 0) {
 
                 // TODO Consider assigning the correct memory index earlier, instead of switching right before allocation.
 
                 // Look for the first available supported memory index and assign it.
                 for(uint32_t i =0; i<= 31; ++i) {
-                    if ((pMemoryHostPointerProperties.memoryTypeBits & (1u << i)) == 0) {
+                    if ((memoryHostPointerProperties.memoryTypeBits & (1u << i)) == 0) {
                         continue;
                     }
                     localAllocInfo.memoryTypeIndex = i;
diff --git a/host/vulkan/cereal/common/vk_struct_id.h b/host/vulkan/cereal/common/vk_struct_id.h
index c526dc1..54641fc 100644
--- a/host/vulkan/cereal/common/vk_struct_id.h
+++ b/host/vulkan/cereal/common/vk_struct_id.h
@@ -99,6 +99,8 @@
                       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT)
 REGISTER_VK_STRUCT_ID(VkPhysicalDeviceProtectedMemoryFeatures,
                       VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES);
+REGISTER_VK_STRUCT_ID(VkPhysicalDeviceExternalMemoryHostPropertiesEXT,
+                      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT);
 
 #if defined(VK_USE_PLATFORM_SCREEN_QNX)
 REGISTER_VK_STRUCT_ID(VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX,