gpu: add PrivateMemory to manage host memory import

This will be used when VulkanAllocateHostMemory is turned on
to work around kvm "Bad Address" bug on amd gpu and intel gpu.

It is different from SystemBlob which has originally
introduced for different purpose.

Bug: 225541819

Change-Id: Ie6868c646f2fa20630bef0639f680c16c5d43ff6
diff --git a/host/vulkan/VkDecoderGlobalState.cpp b/host/vulkan/VkDecoderGlobalState.cpp
index 28298ad..2536720 100644
--- a/host/vulkan/VkDecoderGlobalState.cpp
+++ b/host/vulkan/VkDecoderGlobalState.cpp
@@ -3868,6 +3868,7 @@
 
         VkImportMemoryHostPointerInfoEXT importHostInfo;
         std::optional<SharedMemory> sharedMemory = std::nullopt;
+        std::shared_ptr<PrivateMemory> privateMemory = {};
 
         // TODO(b/261222354): Make sure the feature exists when initializing sVkEmulation.
         if (hostVisible && feature_is_enabled(kFeature_SystemBlob)) {
@@ -3902,6 +3903,22 @@
             vk_append_struct(&structChainIter, &importHostInfo);
         }
 
+        VkImportMemoryHostPointerInfoEXT importHostInfoPrivate{};
+        if (hostVisible && feature_is_enabled(kFeature_VulkanAllocateHostMemory) &&
+            localAllocInfo.pNext == nullptr) {
+            VkDeviceSize alignedSize = __ALIGN(localAllocInfo.allocationSize, kPageSizeforBlob);
+            localAllocInfo.allocationSize = alignedSize;
+            privateMemory =
+                std::make_shared<PrivateMemory>(kPageSizeforBlob, localAllocInfo.allocationSize);
+            mappedPtr = privateMemory->getAddr();
+            importHostInfoPrivate = {
+                .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
+                .pNext = NULL,
+                .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
+                .pHostPointer = mappedPtr};
+            vk_append_struct(&structChainIter, &importHostInfoPrivate);
+        }
+
         VkResult result = vk->vkAllocateMemory(device, &localAllocInfo, pAllocator, pMemory);
 
         if (result != VK_SUCCESS) {
@@ -3992,6 +4009,8 @@
             // Always assign the shared memory into memoryInfo. If it was used, then it will have
             // ownership transferred.
             memoryInfo.sharedMemory = std::exchange(sharedMemory, std::nullopt);
+
+            memoryInfo.privateMemory = privateMemory;
         }
 
         *pMemory = new_boxed_non_dispatchable_VkDeviceMemory(*pMemory);
diff --git a/host/vulkan/VkDecoderInternalStructs.h b/host/vulkan/VkDecoderInternalStructs.h
index 6a90923..bf1e55f 100644
--- a/host/vulkan/VkDecoderInternalStructs.h
+++ b/host/vulkan/VkDecoderInternalStructs.h
@@ -16,6 +16,11 @@
 
 #include <vulkan/vulkan.h>
 
+#ifdef _WIN32
+#include <malloc.h>
+#endif
+
+#include <stdlib.h>
 #include <set>
 #include <string>
 
@@ -100,6 +105,32 @@
     int mMaxSize;
 };
 
+class PrivateMemory {
+public:
+    PrivateMemory(size_t alignment, size_t size) {
+#ifdef _WIN32
+        mAddr = _aligned_malloc(size, alignment);
+#else
+        mAddr = aligned_alloc(alignment, size);
+#endif
+    }
+    ~PrivateMemory() {
+        if (mAddr) {
+#ifdef _WIN32
+            _aligned_free(mAddr);
+#else
+            free(mAddr);
+#endif
+            mAddr = nullptr;
+        }
+    }
+    void* getAddr() {
+        return mAddr;
+    }
+private:
+    void* mAddr{nullptr};
+};
+
 // We always map the whole size on host.
 // This makes it much easier to implement
 // the memory map API.
@@ -126,6 +157,7 @@
     // Set if the memory is backed by shared memory.
     std::optional<android::base::SharedMemory> sharedMemory;
 
+    std::shared_ptr<PrivateMemory> privateMemory;
     // virtio-gpu blobs
     uint64_t blobId = 0;
 
@@ -307,4 +339,4 @@
     VkDevice device;
 };
 }  // namespace vk
-}  // namespace gfxstream
\ No newline at end of file
+}  // namespace gfxstream