(8/8) vulkan_enc: Support sysmem VkBuffer allocation in Fuchsia.
Now goldfish Vulkan clients can allocate VkBuffer using sysmem
BufferCollection in Fuchsia, for example:
```
vk::StructureChain<vk::BufferCreateInfo,
vk::BufferCollectionBufferCreateInfoFUCHSIA> chain = {
vk::BufferCreateInfo({}, size, bufferUsage),
vk::BufferCollectionBufferCreateInfoFUCHSIA(vk_collection, 0),
};
auto vkBuffer = device.createBuffer(chain.get<vk::BufferCreateInfo>());
```
Then clients can import BufferCollection info to
VkDeviceMemory by calling vkAllocateMemory().
These buffer will have host renderControl buffer backing,
and can be exported to other processes.
Change-Id: Iaa7d326e75c1c97ef0320612d4f9da46cf0182d7
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 91be62b..c364b32 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -15,6 +15,7 @@
#include "ResourceTracker.h"
+#include "android/base/Optional.h"
#include "android/base/threads/AndroidWorkPool.h"
#include "goldfish_vk_private_defs.h"
@@ -160,6 +161,7 @@
using android::aligned_buf_alloc;
using android::aligned_buf_free;
+using android::base::Optional;
using android::base::guest::AutoLock;
using android::base::guest::Lock;
using android::base::guest::WorkPool;
@@ -299,6 +301,9 @@
VkDeviceSize currentBackingSize = 0;
bool baseRequirementsKnown = false;
VkMemoryRequirements baseRequirements;
+#ifdef VK_USE_PLATFORM_FUCHSIA
+ bool isSysmemBackedMemory = false;
+#endif
};
struct VkSemaphore_Info {
@@ -1694,56 +1699,66 @@
buffer_constraints.heap_permitted_count = 1;
buffer_constraints.heap_permitted[0] =
fuchsia::sysmem::HeapType::GOLDFISH_DEVICE_LOCAL;
- std::vector<VkFormat> formats{pImageInfo->format};
- if (pImageInfo->format == VK_FORMAT_UNDEFINED) {
- // This is a hack to allow the client to say it supports every vulkan format the driver
- // does. TODO(fxb/13247): Modify this function to take a list of vulkan formats to use.
- formats = std::vector<VkFormat>{
- VK_FORMAT_B8G8R8A8_UNORM,
- VK_FORMAT_R8G8B8A8_UNORM,
- };
- }
- constraints.image_format_constraints_count = formats.size();
- uint32_t format_index = 0;
- for (VkFormat format : formats) {
- fuchsia::sysmem::ImageFormatConstraints& image_constraints =
- constraints.image_format_constraints[format_index++];
- switch (format) {
- case VK_FORMAT_B8G8R8A8_SINT:
- case VK_FORMAT_B8G8R8A8_UNORM:
- case VK_FORMAT_B8G8R8A8_SRGB:
- case VK_FORMAT_B8G8R8A8_SNORM:
- case VK_FORMAT_B8G8R8A8_SSCALED:
- case VK_FORMAT_B8G8R8A8_USCALED:
- image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::BGRA32;
- break;
- case VK_FORMAT_R8G8B8A8_SINT:
- case VK_FORMAT_R8G8B8A8_UNORM:
- case VK_FORMAT_R8G8B8A8_SRGB:
- case VK_FORMAT_R8G8B8A8_SNORM:
- case VK_FORMAT_R8G8B8A8_SSCALED:
- case VK_FORMAT_R8G8B8A8_USCALED:
- image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::R8G8B8A8;
- break;
- default:
- return VK_ERROR_FORMAT_NOT_SUPPORTED;
+
+ // Set image format constraints for VkImage allocation.
+ if (pImageInfo) {
+ std::vector<VkFormat> formats{pImageInfo->format};
+ if (pImageInfo->format == VK_FORMAT_UNDEFINED) {
+ // This is a hack to allow the client to say it supports every
+ // vulkan format the driver does. TODO(fxb/13247): Modify this
+ // function to take a list of vulkan formats to use.
+ formats = std::vector<VkFormat>{
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_UNORM,
+ };
}
- image_constraints.color_spaces_count = 1;
- image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::SRGB;
- image_constraints.min_coded_width = pImageInfo->extent.width;
- image_constraints.max_coded_width = 0xfffffff;
- image_constraints.min_coded_height = pImageInfo->extent.height;
- image_constraints.max_coded_height = 0xffffffff;
- image_constraints.min_bytes_per_row = pImageInfo->extent.width * 4;
- image_constraints.max_bytes_per_row = 0xffffffff;
- image_constraints.max_coded_width_times_coded_height = 0xffffffff;
- image_constraints.layers = 1;
- image_constraints.coded_width_divisor = 1;
- image_constraints.coded_height_divisor = 1;
- image_constraints.bytes_per_row_divisor = 1;
- image_constraints.start_offset_divisor = 1;
- image_constraints.display_width_divisor = 1;
- image_constraints.display_height_divisor = 1;
+ constraints.image_format_constraints_count = formats.size();
+ uint32_t format_index = 0;
+ for (VkFormat format : formats) {
+ fuchsia::sysmem::ImageFormatConstraints& image_constraints =
+ constraints.image_format_constraints[format_index++];
+ switch (format) {
+ case VK_FORMAT_B8G8R8A8_SINT:
+ case VK_FORMAT_B8G8R8A8_UNORM:
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ case VK_FORMAT_B8G8R8A8_SNORM:
+ case VK_FORMAT_B8G8R8A8_SSCALED:
+ case VK_FORMAT_B8G8R8A8_USCALED:
+ image_constraints.pixel_format.type =
+ fuchsia::sysmem::PixelFormatType::BGRA32;
+ break;
+ case VK_FORMAT_R8G8B8A8_SINT:
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ case VK_FORMAT_R8G8B8A8_SNORM:
+ case VK_FORMAT_R8G8B8A8_SSCALED:
+ case VK_FORMAT_R8G8B8A8_USCALED:
+ image_constraints.pixel_format.type =
+ fuchsia::sysmem::PixelFormatType::R8G8B8A8;
+ break;
+ default:
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+ image_constraints.color_spaces_count = 1;
+ image_constraints.color_space[0].type =
+ fuchsia::sysmem::ColorSpaceType::SRGB;
+ image_constraints.min_coded_width = pImageInfo->extent.width;
+ image_constraints.max_coded_width = 0xfffffff;
+ image_constraints.min_coded_height = pImageInfo->extent.height;
+ image_constraints.max_coded_height = 0xffffffff;
+ image_constraints.min_bytes_per_row =
+ pImageInfo->extent.width * 4;
+ image_constraints.max_bytes_per_row = 0xffffffff;
+ image_constraints.max_coded_width_times_coded_height =
+ 0xffffffff;
+ image_constraints.layers = 1;
+ image_constraints.coded_width_divisor = 1;
+ image_constraints.coded_height_divisor = 1;
+ image_constraints.bytes_per_row_divisor = 1;
+ image_constraints.start_offset_divisor = 1;
+ image_constraints.display_width_divisor = 1;
+ image_constraints.display_height_divisor = 1;
+ }
}
(*collection)->SetConstraints(true, constraints);
@@ -1756,9 +1771,11 @@
const VkImageCreateInfo* pImageInfo) {
auto sysmem_collection =
reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
- return setBufferCollectionConstraints(
- sysmem_collection, pImageInfo,
- pImageInfo->extent.width * pImageInfo->extent.height * 4);
+ size_t minSizeBytes = pImageInfo ? pImageInfo->extent.width *
+ pImageInfo->extent.height * 4
+ : 0u;
+ return setBufferCollectionConstraints(sysmem_collection, pImageInfo,
+ minSizeBytes);
}
VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
@@ -1991,6 +2008,10 @@
VkImportColorBufferGOOGLE importCbInfo = {
VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE, 0,
};
+ VkImportBufferGOOGLE importBufferInfo = {
+ VK_STRUCTURE_TYPE_IMPORT_BUFFER_GOOGLE,
+ 0,
+ };
// VkImportPhysicalAddressGOOGLE importPhysAddrInfo = {
// VK_STRUCTURE_TYPE_IMPORT_PHYSICAL_ADDRESS_GOOGLE, 0,
// };
@@ -2180,6 +2201,7 @@
(dedicatedAllocInfoPtr->image != VK_NULL_HANDLE);
VkImageCreateInfo imageCreateInfo = {};
+ // TODO(liyl): Handle dedicated buffer allocation as well.
if (hasDedicatedImage) {
AutoLock lock(mLock);
@@ -2288,12 +2310,25 @@
abort();
}
zx_status_t status2 = ZX_OK;
- status = mControlDevice->GetColorBuffer(
- std::move(vmo_copy), &status2, &importCbInfo.colorBuffer);
+
+ fuchsia::hardware::goldfish::BufferHandleType handle_type;
+ uint32_t buffer_handle;
+
+ status = mControlDevice->GetBufferHandle(std::move(vmo_copy),
+ &status2, &buffer_handle,
+ &handle_type);
if (status != ZX_OK || status2 != ZX_OK) {
- ALOGE("GetColorBuffer failed: %d:%d", status, status2);
+ ALOGE("GetBufferHandle failed: %d:%d", status, status2);
}
- vk_append_struct(&structChainIter, &importCbInfo);
+
+ if (handle_type ==
+ fuchsia::hardware::goldfish::BufferHandleType::BUFFER) {
+ importBufferInfo.buffer = buffer_handle;
+ vk_append_struct(&structChainIter, &importBufferInfo);
+ } else {
+ importCbInfo.colorBuffer = buffer_handle;
+ vk_append_struct(&structChainIter, &importCbInfo);
+ }
}
#endif
@@ -3503,6 +3538,47 @@
VkBuffer *pBuffer) {
VkEncoder* enc = (VkEncoder*)context;
+#ifdef VK_USE_PLATFORM_FUCHSIA
+ Optional<zx::vmo> vmo;
+ bool isSysmemBackedMemory = false;
+
+ const auto* extBufferCollectionPtr =
+ vk_find_struct<VkBufferCollectionBufferCreateInfoFUCHSIA>(
+ pCreateInfo);
+
+ if (extBufferCollectionPtr) {
+ auto collection =
+ reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
+ extBufferCollectionPtr->collection);
+ uint32_t index = extBufferCollectionPtr->index;
+
+ fuchsia::sysmem::BufferCollectionInfo_2 info;
+ zx_status_t status2;
+ zx_status_t status =
+ (*collection)->WaitForBuffersAllocated(&status2, &info);
+
+ if (status == ZX_OK && status2 == ZX_OK) {
+ if (index < info.buffer_count) {
+ vmo = android::base::makeOptional(
+ std::move(info.buffers[index].vmo));
+ }
+ } else {
+ ALOGE("WaitForBuffersAllocated failed: %d %d", status, status2);
+ }
+
+ if (vmo && vmo->is_valid()) {
+ zx_status_t status2 = ZX_OK;
+ status = mControlDevice->CreateBuffer(
+ std::move(*vmo), pCreateInfo->size, &status2);
+ if (status != ZX_OK ||
+ (status2 != ZX_OK && status2 != ZX_ERR_ALREADY_EXISTS)) {
+ ALOGE("CreateBuffer failed: %d:%d", status, status2);
+ }
+ isSysmemBackedMemory = true;
+ }
+ }
+#endif // VK_USE_PLATFORM_FUCHSIA
+
VkResult res;
VkMemoryRequirements memReqs;
@@ -3536,6 +3612,12 @@
info.externalCreateInfo = *extBufCi;
}
+#ifdef VK_USE_PLATFORM_FUCHSIA
+ if (isSysmemBackedMemory) {
+ info.isSysmemBackedMemory = true;
+ }
+#endif
+
if (info.baseRequirementsKnown) {
transformBufferMemoryRequirementsForGuestLocked(*pBuffer, &memReqs);
info.baseRequirements = memReqs;
@@ -3967,7 +4049,7 @@
}
for (auto handle : toWait) {
- ALOGV("%s: waiting on work group item: %llu\n", __func__,
+ ALOGV("%s: waiting on work group item: %llu\n", __func__,
(unsigned long long)handle);
mWorkPool.waitAll(handle);
}