[vulkan] host coherent: Integrate VK_GOOGLE_address_space
bug: 111137294
bug: 121377497
This CL replaces the aligned_buf_alloc mechanism with a call to
vkMapMemoryIntoAddressSpaceGOOGLE, which is implemented as follows:
- Use GoldfishAddressSpaceBlock to obtain a reservation of guest physical memory
- Through the encoder, we obtain a host-side gpu pointer
- mmap() method of GoldfishAddressSpaceBlock is used to get a guest
userspace pointer
Change-Id: I643351e2c8cd8528c4f0aa1e9b10166b736aea51
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 916a817..7f361cc 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -23,6 +23,7 @@
#include "android/base/synchronization/AndroidLock.h"
#include "gralloc_cb.h"
+#include "goldfish_address_space.h"
#include "goldfish_vk_private_defs.h"
#include <unordered_map>
@@ -120,6 +121,9 @@
VkDeviceSize mappedSize = 0;
uint8_t* mappedPtr = nullptr;
uint32_t memoryTypeIndex = 0;
+ bool directMapped = false;
+ std::unique_ptr<GoldfishAddressSpaceBlock>
+ goldfishAddressSpaceBlock = {};
};
#define HANDLE_REGISTER_IMPL_IMPL(type) \
@@ -145,13 +149,19 @@
void unregister_VkDeviceMemory(VkDeviceMemory mem) {
AutoLock lock(mLock);
+
auto it = info_VkDeviceMemory.find(mem);
if (it == info_VkDeviceMemory.end()) return;
auto& memInfo = it->second;
- if (memInfo.mappedPtr) {
+
+ if (memInfo.mappedPtr && !memInfo.directMapped) {
aligned_buf_free(memInfo.mappedPtr);
}
+
+ // Direct mapping is erased by GoldfishAddressSpaceBlock's
+ // dtor
+ info_VkDeviceMemory.erase(mem);
}
void setDeviceInfo(VkDevice device,
@@ -242,6 +252,15 @@
if (!features || mFeatureInfo) return;
mFeatureInfo.reset(new EmulatorFeatureInfo);
*mFeatureInfo = *features;
+
+ if (mFeatureInfo->hasDirectMem) {
+ mGoldfishAddressSpaceBlockProvider.reset(
+ new GoldfishAddressSpaceBlockProvider);
+ }
+ }
+
+ bool usingDirectMapping() const {
+ return mFeatureInfo->hasDirectMem;
}
VkResult on_vkEnumerateInstanceVersion(
@@ -295,7 +314,7 @@
}
VkResult on_vkAllocateMemory(
- void*,
+ void* context,
VkResult input_result,
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
@@ -307,18 +326,53 @@
VkDeviceSize allocationSize = pAllocateInfo->allocationSize;
VkDeviceSize mappedSize = getNonCoherentExtendedSize(device, allocationSize);
uint8_t* mappedPtr = nullptr;
-
- if (isMemoryTypeHostVisible(device, pAllocateInfo->memoryTypeIndex)) {
+ bool hostVisible =
+ isMemoryTypeHostVisible(device, pAllocateInfo->memoryTypeIndex);
+ if (hostVisible && !mGoldfishAddressSpaceBlockProvider) {
mappedPtr = (uint8_t*)aligned_buf_alloc(4096, mappedSize);
- D("host visible alloc: size 0x%llx host ptr %p mapped size 0x%llx",
- (unsigned long long)size, mem->ptr,
- (unsigned long long)mem->mappedSize);
+ D("host visible alloc (non-direct): "
+ "size 0x%llx host ptr %p mapped size 0x%llx",
+ (unsigned long long)allocationSize, mappedPtr,
+ (unsigned long long)mappedSize);
}
setDeviceMemoryInfo(
*pMemory, allocationSize, mappedSize, mappedPtr,
pAllocateInfo->memoryTypeIndex);
+ bool doDirectMap =
+ hostVisible && mGoldfishAddressSpaceBlockProvider;
+
+ if (doDirectMap) {
+ VkEncoder* enc = (VkEncoder*)context;
+
+ uint64_t directMappedAddr = 0;
+
+ VkResult directMapResult =
+ enc->vkMapMemoryIntoAddressSpaceGOOGLE(
+ device, *pMemory, &directMappedAddr);
+
+ if (directMapResult != VK_SUCCESS) {
+ return directMapResult;
+ }
+
+ AutoLock lock(mLock);
+
+ auto it = info_VkDeviceMemory.find(*pMemory);
+ if (it == info_VkDeviceMemory.end()) {
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ auto& info = it->second;
+ info.mappedPtr = (uint8_t*)(uintptr_t)directMappedAddr;
+ info.directMapped = true;
+
+ D("host visible alloc (direct): "
+ "size 0x%llx host ptr %p mapped size 0x%llx",
+ (unsigned long long)allocationSize, info.mappedPtr,
+ (unsigned long long)mappedSize);
+ }
+
return input_result;
}
@@ -397,9 +451,82 @@
}
}
+ // Action of vkMapMemoryIntoAddressSpaceGOOGLE:
+ // 1. preprocess (on_vkMapMemoryIntoAddressSpaceGOOGLE_pre):
+ // uses address space device to reserve the right size of
+ // memory.
+ // 2. the reservation results in a physical address. the physical
+ // address is set as |*pAddress|.
+ // 3. after pre, the API call is encoded to the host, where the
+ // value of pAddress is also sent (the physical address).
+ // 4. the host will obtain the actual gpu pointer and send it
+ // back out in |*pAddress|.
+ // 5. postprocess (on_vkMapMemoryIntoAddressSpaceGOOGLE) will run,
+ // using the mmap() method of GoldfishAddressSpaceBlock to obtain
+ // a pointer in guest userspace corresponding to the host pointer.
+ VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
+ void*,
+ VkResult,
+ VkDevice,
+ VkDeviceMemory memory,
+ uint64_t* pAddress) {
+
+ AutoLock lock(mLock);
+
+ auto it = info_VkDeviceMemory.find(memory);
+ if (it == info_VkDeviceMemory.end()) {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ auto& memInfo = it->second;
+ memInfo.goldfishAddressSpaceBlock.reset(
+ new GoldfishAddressSpaceBlock);
+ auto& block = *(memInfo.goldfishAddressSpaceBlock);
+
+ block.allocate(
+ mGoldfishAddressSpaceBlockProvider.get(),
+ memInfo.mappedSize);
+
+ *pAddress = block.physAddr();
+
+ return VK_SUCCESS;
+ }
+
+ VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE(
+ void*,
+ VkResult input_result,
+ VkDevice,
+ VkDeviceMemory memory,
+ uint64_t* pAddress) {
+
+ if (input_result != VK_SUCCESS) {
+ return input_result;
+ }
+
+ // Now pAddress points to the gpu addr from host.
+ AutoLock lock(mLock);
+
+ auto it = info_VkDeviceMemory.find(memory);
+ if (it == info_VkDeviceMemory.end()) {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ auto& memInfo = it->second;
+ auto& block = *(memInfo.goldfishAddressSpaceBlock);
+
+ uint64_t gpuAddr = *pAddress;
+
+ void* userPtr = block.mmap(gpuAddr);
+
+ *pAddress = (uint64_t)(uintptr_t)userPtr;
+
+ return input_result;
+ }
+
private:
mutable Lock mLock;
std::unique_ptr<EmulatorFeatureInfo> mFeatureInfo;
+ std::unique_ptr<GoldfishAddressSpaceBlockProvider> mGoldfishAddressSpaceBlockProvider;
};
ResourceTracker::ResourceTracker() : mImpl(new ResourceTracker::Impl()) { }
ResourceTracker::~ResourceTracker() { }
@@ -468,6 +595,10 @@
mImpl->setupFeatures(features);
}
+bool ResourceTracker::usingDirectMapping() const {
+ return mImpl->usingDirectMapping();
+}
+
VkResult ResourceTracker::on_vkEnumerateInstanceVersion(
void* context,
VkResult input_result,
@@ -545,4 +676,24 @@
mImpl->unwrap_vkAcquireImageANDROID_nativeFenceFd(fd, fd_out);
}
+VkResult ResourceTracker::on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
+ void* context,
+ VkResult input_result,
+ VkDevice device,
+ VkDeviceMemory memory,
+ uint64_t* pAddress) {
+ return mImpl->on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
+ context, input_result, device, memory, pAddress);
+}
+
+VkResult ResourceTracker::on_vkMapMemoryIntoAddressSpaceGOOGLE(
+ void* context,
+ VkResult input_result,
+ VkDevice device,
+ VkDeviceMemory memory,
+ uint64_t* pAddress) {
+ return mImpl->on_vkMapMemoryIntoAddressSpaceGOOGLE(
+ context, input_result, device, memory, pAddress);
+}
+
} // namespace goldfish_vk