diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index 448b78cb1..7ad518a3a 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -1767,6 +1767,14 @@ void VkEmulation::initFeatures(Features features) { VkEmulation::~VkEmulation() { std::lock_guard lock(mMutex); +#ifdef __ANDROID__ + // Nothing claimed these before teardown; release the extra reference each was stashed with. + for (auto& [key, ahb] : mPendingDeferredLayoutAhbs) { + AHardwareBuffer_release(ahb); + } + mPendingDeferredLayoutAhbs.clear(); +#endif + mCompositorVk.reset(); mDisplayVk.reset(); mUdmabufCreator.reset(); @@ -2062,9 +2070,10 @@ MTLResource_id VkEmulation::getMtlResourceFromVkDeviceMemory(VulkanDispatch* vk, #endif #ifdef __ANDROID__ -// Allocate an AHardwareBuffer matching the given image's format, extent and usage. -// Returns nullptr on failure (caller falls back to the non-AHB allocation path). -static AHardwareBuffer* allocAhb(const VkImageCreateInfo* imageCreateInfo) { +// Derives the AHB shape (format, usage, extent) that allocAhb() would allocate for this image, +// without allocating anything. Shared with the deferred-layout pending-AHB pool so a probe AHB +// and a ColorBuffer's own AHB request can be matched without ever calling allocAhb() twice. +AhbShapeKey ComputeAhbShapeKey(const VkImageCreateInfo* imageCreateInfo) { // Map VkFormat to the corresponding AHB format — must match to avoid tiling mismatch. uint32_t ahbFormat; switch (imageCreateInfo->format) { @@ -2099,12 +2108,25 @@ static AHardwareBuffer* allocAhb(const VkImageCreateInfo* imageCreateInfo) { ahbUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; } - AHardwareBuffer_Desc desc = { + return AhbShapeKey{ .width = imageCreateInfo->extent.width, .height = imageCreateInfo->extent.height, + .ahbFormat = ahbFormat, + .ahbUsage = ahbUsage, + }; +} + +// Allocate an AHardwareBuffer matching the given image's format, extent and usage. +// Returns nullptr on failure (caller falls back to the non-AHB allocation path). +AHardwareBuffer* allocAhb(const VkImageCreateInfo* imageCreateInfo) { + const AhbShapeKey shape = ComputeAhbShapeKey(imageCreateInfo); + + AHardwareBuffer_Desc desc = { + .width = shape.width, + .height = shape.height, .layers = 1, - .format = ahbFormat, - .usage = ahbUsage, + .format = shape.ahbFormat, + .usage = shape.ahbUsage, }; AHardwareBuffer* ahb = nullptr; @@ -2116,6 +2138,37 @@ static AHardwareBuffer* allocAhb(const VkImageCreateInfo* imageCreateInfo) { } return ahb; } + +void VkEmulation::stashPendingDeferredLayoutAhb(const VkImageCreateInfo* imageCreateInfo, + AHardwareBuffer* ahb) { + AHardwareBuffer_acquire(ahb); + std::lock_guard lock(mMutex); + mPendingDeferredLayoutAhbs.emplace(ComputeAhbShapeKey(imageCreateInfo), ahb); +} + +void VkEmulation::unstashPendingDeferredLayoutAhb(const VkImageCreateInfo* imageCreateInfo, + AHardwareBuffer* ahb) { + std::lock_guard lock(mMutex); + auto range = mPendingDeferredLayoutAhbs.equal_range(ComputeAhbShapeKey(imageCreateInfo)); + for (auto it = range.first; it != range.second; ++it) { + if (it->second == ahb) { + mPendingDeferredLayoutAhbs.erase(it); + AHardwareBuffer_release(ahb); + return; + } + } +} + +AHardwareBuffer* VkEmulation::takePendingDeferredLayoutAhbLocked( + const VkImageCreateInfo* imageCreateInfo) { + auto it = mPendingDeferredLayoutAhbs.find(ComputeAhbShapeKey(imageCreateInfo)); + if (it == mPendingDeferredLayoutAhbs.end()) { + return nullptr; + } + AHardwareBuffer* ahb = it->second; + mPendingDeferredLayoutAhbs.erase(it); + return ahb; +} #endif // Precondition: sVkEmulation has valid device support info @@ -2341,7 +2394,19 @@ bool VkEmulation::allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalM if (colorBufferInfo) { auto cbInfoPtr = *colorBufferInfo; - AHardwareBuffer* ahb = allocAhb(&cbInfoPtr->imageCreateInfoShallow); + // A same-shaped image that hit a deferred layout query earlier (see + // on_vkCreateImage) may have left its probe AHB here. Only probes not already + // imported as their own image's backing memory are still in the pool, so + // adopting one cannot alias -- see unstashPendingDeferredLayoutAhb(). + AHardwareBuffer* ahb = + takePendingDeferredLayoutAhbLocked(&cbInfoPtr->imageCreateInfoShallow); + if (ahb) { + GFXSTREAM_INFO("DL-AHB adopted pending ahb=%p for ColorBuffer %u (%ux%u)", + (void*)ahb, cbInfoPtr->handle, cbInfoPtr->width, + cbInfoPtr->height); + } else { + ahb = allocAhb(&cbInfoPtr->imageCreateInfoShallow); + } if (!ahb) { GFXSTREAM_WARNING( "Falling back to non-exportable allocation for ColorBuffer %u (%ux%u).", diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index bafab240e..99e14cbcb 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -13,6 +13,10 @@ // limitations under the License. #pragma once +#ifdef __ANDROID__ +#include +#endif + #include #include @@ -85,6 +89,30 @@ enum class AstcEmulationMode { Gpu, // Decompress ASTC textures on the GPU }; +#ifdef __ANDROID__ +// The AHardwareBuffer_Desc fields that fully determine an AHB's allocation/property-query +// result, derived from a VkImageCreateInfo the same way allocAhb() derives its own AHB. Used to +// match an image against an AHB allocated for a different image of the identical shape. +struct AhbShapeKey { + uint32_t width = 0; + uint32_t height = 0; + uint32_t ahbFormat = 0; + uint64_t ahbUsage = 0; + + bool operator==(const AhbShapeKey& other) const { + return width == other.width && height == other.height && ahbFormat == other.ahbFormat && + ahbUsage == other.ahbUsage; + } +}; +struct AhbShapeKeyHash { + size_t operator()(const AhbShapeKey& key) const { + return (static_cast(key.width) << 48) ^ (static_cast(key.height) << 32) ^ + (static_cast(key.ahbFormat) << 16) ^ static_cast(key.ahbUsage); + } +}; +AhbShapeKey ComputeAhbShapeKey(const VkImageCreateInfo* imageCreateInfo); +#endif + // Global state that holds a global Vulkan instance along with globally // exported memory allocations + images. This is in order to service things // like AndroidHardwareBuffer/FuchsiaImagePipeHandle. Each such allocation is @@ -205,6 +233,7 @@ class VkEmulation { void onVkDeviceLost(); VkExternalMemoryHandleTypeFlagBits getDefaultExternalMemoryHandleType(); + void appendExternalMemoryModeDeviceExtensions(std::vector& outDeviceExtensions); ExternalMemory::Mode getExternalMemoryMode() const; bool supportsExternalMemory() { @@ -466,6 +495,23 @@ class VkEmulation { uint32_t vulkanInstanceVersion() const; +#ifdef __ANDROID__ + // Stashes an AHB allocated to answer a deferred AHB-external image's zero-size layout query + // (see on_vkCreateImage), so that a same-shaped ColorBuffer's own backing allocation can + // adopt it instead of allocating a second one -- see allocExternalMemory's AndroidAHB case. + // Takes its own reference via AHardwareBuffer_acquire, independent of whatever reference the + // caller (the probing image's own DeferredLayoutInfo) already holds. + void stashPendingDeferredLayoutAhb(const VkImageCreateInfo* imageCreateInfo, + AHardwareBuffer* ahb); + + // Withdraws a previously stashed AHB from the pending pool, releasing the pool's reference. + // Must be called once the probing image imports the AHB as its own backing memory: at that + // point it is in use, and letting a ColorBuffer adopt it would alias two unrelated images + // onto one allocation. No-op if it was already adopted or never stashed. + void unstashPendingDeferredLayoutAhb(const VkImageCreateInfo* imageCreateInfo, + AHardwareBuffer* ahb); +#endif + private: VkEmulation() = default; @@ -707,6 +753,23 @@ class VkEmulation { // memory handles. std::unordered_map mExternalMemories GUARDED_BY(mMutex); +#ifdef __ANDROID__ + // AHBs stashed by stashPendingDeferredLayoutAhb(), each holding its own + // AHardwareBuffer_acquire()'d reference, waiting for a same-shaped ColorBuffer to adopt + // instead of allocating a second AHB (see allocExternalMemory's AndroidAHB case). Any left + // unclaimed are released at VkEmulation teardown. + std::unordered_multimap + mPendingDeferredLayoutAhbs GUARDED_BY(mMutex); + + // Pops one AHB matching imageCreateInfo's shape from mPendingDeferredLayoutAhbs, or nullptr + // if none is pending. Caller already holds mMutex -- NO_THREAD_SAFETY_ANALYSIS rather than + // REQUIRES(mMutex) because its only caller, allocExternalMemory(), predates thread-safety + // annotations itself and isn't annotated, so REQUIRES here would just move the same + // unverifiable-by-the-analyzer assumption one frame up instead of removing it. + AHardwareBuffer* takePendingDeferredLayoutAhbLocked(const VkImageCreateInfo* imageCreateInfo) + NO_THREAD_SAFETY_ANALYSIS; +#endif + // The host keeps a set of occupied guest memory addresses to avoid a // host memory address mapped to guest twice. std::unordered_set mOccupiedGpas GUARDED_BY(mMutex); @@ -740,6 +803,11 @@ class VkEmulation { std::unique_ptr mUdmabufCreator; }; +#ifdef __ANDROID__ +// Allocates an AHardwareBuffer matching an image's create info. +AHardwareBuffer* allocAhb(const VkImageCreateInfo* imageCreateInfo); +#endif + } // namespace vk } // namespace host } // namespace gfxstream diff --git a/host/vulkan/vk_decoder.cpp b/host/vulkan/vk_decoder.cpp index 9728139e8..2de23adb7 100644 --- a/host/vulkan/vk_decoder.cpp +++ b/host/vulkan/vk_decoder.cpp @@ -3399,14 +3399,12 @@ size_t VkDecoder::Impl::decode(void* buf, size_t len, IOStream* ioStream, VkImage image; const VkImageSubresource* pSubresource; VkSubresourceLayout* pLayout; - // Begin non wrapped dispatchable handle unboxing for device; + // Begin global wrapped dispatchable handle unboxing for device; uint64_t cgen_var_0; memcpy((uint64_t*)&cgen_var_0, *readStreamPtrPtr, 1 * 8); *readStreamPtrPtr += 1 * 8; *(VkDevice*)&device = (VkDevice)(VkDevice)((VkDevice)(*&cgen_var_0)); - auto unboxed_device = unbox_VkDevice(device); auto vk = dispatch_VkDevice(device); - // End manual dispatchable handle unboxing for device; uint64_t cgen_var_1; memcpy((uint64_t*)&cgen_var_1, *readStreamPtrPtr, 1 * 8); *readStreamPtrPtr += 1 * 8; @@ -3435,7 +3433,8 @@ size_t VkDecoder::Impl::decode(void* buf, size_t len, IOStream* ioStream, (unsigned long long)pSubresource, (unsigned long long)pLayout); } if (CC_LIKELY(vk)) { - vk->vkGetImageSubresourceLayout(unboxed_device, image, pSubresource, pLayout); + m_state->on_vkGetImageSubresourceLayout(&m_pool, snapshotApiCallHandle, device, + image, pSubresource, pLayout); } vkStream->unsetHandleMapping(); if (pLayout) { diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index 14665afcd..e1fac243a 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -3164,6 +3164,71 @@ class VkDecoderGlobalState::Impl { imageInfo.imageCreateInfoShallow = vk_make_orphan_copy(*pCreateInfo); imageInfo.layout = pCreateInfo->initialLayout; imageInfo.anbInfo = std::move(anbInfo); + if (const auto* extMemCreateInfo = + vk_find_struct(pCreateInfo)) { + imageInfo.externalHandleTypes = extMemCreateInfo->handleTypes; + } +#ifdef __ANDROID__ + // Deferred image layout, see ImageInfo::DeferredLayoutInfo. Only for AHB-external + // images we are not already backing another way: the ANB path owns its own buffer, and for + // compressed images updateImageMemoryRequirementsLocked() overwrites them anyway. + if ((imageInfo.externalHandleTypes & + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) && + !imageInfo.anbInfo && !imageInfo.compressInfo) { + VkMemoryRequirements probeReqs = {}; + vk->vkGetImageMemoryRequirements(device, *pImage, &probeReqs); + // Only intervene where the driver actually refused to answer. A driver that reports a + // real size needs no help from us, and substituting there would be a regression. + if (probeReqs.size == 0) { + AHardwareBuffer* rawAhb = allocAhb(pCreateInfo); + if (rawAhb) { + VkAndroidHardwareBufferPropertiesANDROID ahbProps = { + .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID, + .pNext = nullptr, + }; + VkResult propsRes = + vk->vkGetAndroidHardwareBufferPropertiesANDROID(device, rawAhb, &ahbProps); + if (propsRes == VK_SUCCESS && ahbProps.allocationSize > 0) { + imageInfo.deferredLayout.ahb = + std::shared_ptr(rawAhb, [](AHardwareBuffer* b) { + if (b) AHardwareBuffer_release(b); + }); + imageInfo.deferredLayout.size = ahbProps.allocationSize; + // The driver reported no alignment either; the AHB satisfies its own. + imageInfo.deferredLayout.alignment = + probeReqs.alignment ? probeReqs.alignment : 1; + imageInfo.deferredLayout.memoryTypeBits = ahbProps.memoryTypeBits; + // The driver will also refuse to report rowPitch for this image; the AHB + // knows its own stride (in pixels), so derive the byte pitch from it. + AHardwareBuffer_Desc ahbDesc = {}; + AHardwareBuffer_describe(rawAhb, &ahbDesc); + uint32_t bytesPerPixel = 4; // allocAhb only ever picks 32-bit RGBA/BGRA + imageInfo.deferredLayout.rowPitch = + static_cast(ahbDesc.stride) * bytesPerPixel; + // Also offer this AHB to a same-shaped ColorBuffer's own allocation, + // which otherwise pays for a second AHardwareBuffer_allocate() for what + // is usually the very same image a moment later (see the guest's + // vkCreateImage -> vkGetImageSubresourceLayout -> CreateBlob sequence). + m_vkEmulation->stashPendingDeferredLayoutAhb(pCreateInfo, rawAhb); + GFXSTREAM_INFO( + "DL-AHB tracked image=%p size=%llu typeBits=0x%x rowPitch=%llu " + "ahbStridePx=%u (driver said size=0)", + (void*)*pImage, (unsigned long long)imageInfo.deferredLayout.size, + imageInfo.deferredLayout.memoryTypeBits, + (unsigned long long)imageInfo.deferredLayout.rowPitch, ahbDesc.stride); + } else { + GFXSTREAM_ERROR( + "DL-AHB properties query failed (res=%d size=%llu); leaving " + "requirements untouched", + (int)propsRes, (unsigned long long)ahbProps.allocationSize); + AHardwareBuffer_release(rawAhb); + } + } else { + GFXSTREAM_ERROR("DL-AHB allocAhb failed for image=%p", (void*)*pImage); + } + } + } +#endif if (boxImage) { *pImage = new_boxed_non_dispatchable_VkImage(*pImage); @@ -5454,6 +5519,11 @@ class VkDecoderGlobalState::Impl { } } + // An AHB-backed image does not need to be CPU-mappable, and it + // must not be: if the guest picks a HOST_VISIBLE memory type, gfxstream has to expose the + // allocation as a mappable blob, and crosvm's resource_map_blob() only accepts Mesa handles -- + // an AHB-backed blob fails with "invalid Mesa handle" and the guest's mmap64 returns EINVAL. + // So hand back only the device-local, non-host-visible subset when one exists. void on_vkGetImageMemoryRequirements(gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle, VkDevice boxed_device, VkImage image, VkMemoryRequirements* pMemoryRequirements) { @@ -5461,7 +5531,6 @@ class VkDecoderGlobalState::Impl { auto vk = dispatch_VkDevice(boxed_device); vk->vkGetImageMemoryRequirements(device, image, pMemoryRequirements); std::lock_guard lock(mMutex); - updateImageMemorySizeLocked(device, image, pMemoryRequirements); auto* deviceInfo = gfxstream::base::find(mDeviceInfo, device); if (!deviceInfo) { @@ -5477,9 +5546,32 @@ class VkDecoderGlobalState::Impl { } auto& physicalDeviceMemHelper = physicalDeviceInfo->memoryPropertiesHelper; + updateImageMemoryRequirementsLocked(device, image, pMemoryRequirements); physicalDeviceMemHelper->transformToGuestMemoryRequirements(pMemoryRequirements); } + // A driver that defers the layout also reports rowPitch=0; answer with the AHB's stride. + void on_vkGetImageSubresourceLayout(gfxstream::base::BumpPool*, VkSnapshotApiCallHandle, + VkDevice boxed_device, VkImage image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout) { + auto device = unbox_VkDevice(boxed_device); + auto vk = dispatch_VkDevice(boxed_device); + vk->vkGetImageSubresourceLayout(device, image, pSubresource, pLayout); +#ifdef __ANDROID__ + if (pLayout && pLayout->rowPitch == 0) { + std::lock_guard lock(mMutex); + auto* dlInfo = gfxstream::base::find(mImageInfo, image); + if (dlInfo && dlInfo->deferredLayout.rowPitch > 0) { + pLayout->rowPitch = dlInfo->deferredLayout.rowPitch; + if (pLayout->size == 0) pLayout->size = dlInfo->deferredLayout.size; + GFXSTREAM_INFO("DL-AHB stride image=%p rowPitch=%llu", (void*)image, + (unsigned long long)pLayout->rowPitch); + } + } +#endif + } + void on_vkGetImageMemoryRequirements2(gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle, VkDevice boxed_device, const VkImageMemoryRequirementsInfo2* pInfo, @@ -5518,9 +5610,9 @@ class VkDecoderGlobalState::Impl { &pMemoryRequirements->memoryRequirements); } - updateImageMemorySizeLocked(device, pInfo->image, &pMemoryRequirements->memoryRequirements); - auto& physicalDeviceMemHelper = physicalDeviceInfo->memoryPropertiesHelper; + updateImageMemoryRequirementsLocked(device, pInfo->image, + &pMemoryRequirements->memoryRequirements); physicalDeviceMemHelper->transformToGuestMemoryRequirements( &pMemoryRequirements->memoryRequirements); } @@ -6311,6 +6403,54 @@ class VkDecoderGlobalState::Impl { if (dedicatedAllocInfoPtr) { localDedicatedAllocInfo = vk_make_orphan_copy(*dedicatedAllocInfoPtr); } +#ifdef __ANDROID__ + // The driver only resolves the layout if the bound memory carries an AHB, so import the + // image's AHB on its dedicated allocation. Function scope: vk_append_struct() only stores + // a pointer and the chain is consumed at vkAllocateMemory below. + VkImportAndroidHardwareBufferInfoANDROID importDeferredLayoutAhb = { + .sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID, + .pNext = nullptr, + .buffer = nullptr, + }; + // Keeps the AHB alive past the lock: the chain is not consumed until vkAllocateMemory + // below, by which point the image may have been destroyed. + std::shared_ptr deferredAhbHold; + // Set when the probe AHB became this image's own backing memory, so it can be withdrawn + // from the pending pool below -- an in-use AHB must not be adopted by a ColorBuffer. + // Withdrawn after mMutex is dropped: unstashPendingDeferredLayoutAhb() takes + // VkEmulation's mutex, and createVkColorBuffer() already holds that one when it reaches + // the adopt side, so taking it under mMutex here would invert the two. + AHardwareBuffer* importedProbeAhb = nullptr; + VkImageCreateInfo importedProbeShape = {}; + if (dedicatedAllocInfoPtr && dedicatedAllocInfoPtr->image != VK_NULL_HANDLE) { + std::lock_guard dlLock(mMutex); + auto* dlInfo = gfxstream::base::find(mImageInfo, dedicatedAllocInfoPtr->image); + if (dlInfo && dlInfo->deferredLayout.ahb) { + // A ColorBuffer import below appends its own AHB import for this same + // allocation -- skip ours so the chain never carries two + // VkImportAndroidHardwareBufferInfoANDROID structs. + if (!vk_find_struct(pAllocateInfo)) { + deferredAhbHold = dlInfo->deferredLayout.ahb; + importDeferredLayoutAhb.buffer = deferredAhbHold.get(); + vk_append_struct(&structChainIter, &importDeferredLayoutAhb); + importedProbeAhb = deferredAhbHold.get(); + importedProbeShape = dlInfo->imageCreateInfoShallow; + GFXSTREAM_INFO("DL-AHB import image=%p ahb=%p size=%llu", + (void*)dedicatedAllocInfoPtr->image, + (void*)importDeferredLayoutAhb.buffer, + (unsigned long long)localAllocInfo.allocationSize); + } + // Either way, the probe AHB has served its purpose (imported above, or + // superseded by a ColorBuffer's own AHB) -- release it now rather than + // holding it for the image's lifetime. The cached size/alignment/ + // memoryTypeBits/rowPitch survive for later requirement/layout queries. + dlInfo->deferredLayout.ahb.reset(); + } + } + if (importedProbeAhb) { + m_vkEmulation->unstashPendingDeferredLayoutAhb(&importedProbeShape, importedProbeAhb); + } +#endif if (!usingDirectMapping()) { // We copy bytes 1 page at a time from the guest to the host // if we are not using direct mapping. This means we can end up @@ -10348,14 +10488,27 @@ class VkDecoderGlobalState::Impl { return false; } - void updateImageMemorySizeLocked(VkDevice device, VkImage image, - VkMemoryRequirements* pMemoryRequirements) REQUIRES(mMutex) { + void updateImageMemoryRequirementsLocked(VkDevice device, VkImage image, + VkMemoryRequirements* pMemoryRequirements) + REQUIRES(mMutex) { auto* imageInfo = gfxstream::base::find(mImageInfo, image); - if (!imageInfo || !imageInfo->compressInfo) { + if (!imageInfo) return; + + if (imageInfo->compressInfo) { + *pMemoryRequirements = imageInfo->compressInfo->getMemoryRequirements(); return; } - - *pMemoryRequirements = imageInfo->compressInfo->getMemoryRequirements(); +#ifdef __ANDROID__ + // A driver that defers an AHB-external image's layout answers size=0 until bind. Answer + // with what the image's own AHB needs instead. Host memory type indices here; the caller + // must still run transformToGuestMemoryRequirements afterwards. + if (pMemoryRequirements && pMemoryRequirements->size == 0 && + imageInfo->deferredLayout.size > 0) { + pMemoryRequirements->size = imageInfo->deferredLayout.size; + pMemoryRequirements->alignment = imageInfo->deferredLayout.alignment; + pMemoryRequirements->memoryTypeBits = imageInfo->deferredLayout.memoryTypeBits; + } +#endif } bool enableEmulatedEtc2() const { return m_vkEmulation->isEtc2EmulationEnabled(); } @@ -12018,6 +12171,13 @@ void VkDecoderGlobalState::on_vkCmdCopyImageToBuffer2KHR( mImpl->on_vkCmdCopyImageToBuffer2KHR(pool, apiCallHandle, commandBuffer, pCopyImageToBufferInfo); } +void VkDecoderGlobalState::on_vkGetImageSubresourceLayout( + gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, + VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) { + mImpl->on_vkGetImageSubresourceLayout(pool, apiCallHandle, device, image, pSubresource, + pLayout); +} + void VkDecoderGlobalState::on_vkGetImageMemoryRequirements( gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements) { diff --git a/host/vulkan/vk_decoder_global_state.h b/host/vulkan/vk_decoder_global_state.h index 204e2e51b..add118d3f 100644 --- a/host/vulkan/vk_decoder_global_state.h +++ b/host/vulkan/vk_decoder_global_state.h @@ -457,6 +457,11 @@ class VkDecoderGlobalState { VkSnapshotApiCallHandle apiCallHandle, VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); + void on_vkGetImageSubresourceLayout(gfxstream::base::BumpPool* pool, + VkSnapshotApiCallHandle apiCallHandle, VkDevice device, + VkImage image, const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout); + void on_vkGetImageMemoryRequirements2(gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, diff --git a/host/vulkan/vk_decoder_internal_structs.h b/host/vulkan/vk_decoder_internal_structs.h index 75dc2199b..472b25a1a 100644 --- a/host/vulkan/vk_decoder_internal_structs.h +++ b/host/vulkan/vk_decoder_internal_structs.h @@ -16,6 +16,10 @@ #include +#ifdef __ANDROID__ +#include +#endif + #ifdef _WIN32 #include #endif @@ -23,6 +27,7 @@ #include #include +#include #include #include #include @@ -359,6 +364,20 @@ struct ImageInfo { // TODO: might need to use an array of layouts to represent each sub resource VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; VkDeviceMemory memory = VK_NULL_HANDLE; + // From VkExternalMemoryImageCreateInfo; imageCreateInfoShallow drops pNext. + VkExternalMemoryHandleTypeFlags externalHandleTypes = 0; +#ifdef __ANDROID__ + // Set when a driver defers an AHB-external image's layout to vkBindImageMemory and reports + // size=0 until then. The AHB is shared_ptr-held so every mImageInfo teardown path frees it. + struct DeferredLayoutInfo { + std::shared_ptr ahb; + VkDeviceSize size = 0; + VkDeviceSize alignment = 0; + uint32_t memoryTypeBits = 0; + VkDeviceSize rowPitch = 0; + }; + DeferredLayoutInfo deferredLayout; +#endif }; struct ImageViewInfo {