From 956c6847ee6ec34357f1936c611918e21236ae86 Mon Sep 17 00:00:00 2001 From: Jason Le Date: Tue, 25 Aug 2026 16:17:56 -0700 Subject: [PATCH 1/6] gfxstream: route vkGetImageSubresourceLayout through the global state Decode it with emit_global_state_wrapped_decoding, as the other image entry points already are, so the host can answer it. The implementation added here just calls through to the driver, so behaviour is unchanged. The generator side is a separate change in Mesa: gitlab.freedesktop.org/mesa/mesa/-/merge_requests/43969 vk_decoder.cpp carries only the delta that change produces. A plain regeneration also rewrites ~87 unrelated lines across three generated files, because the checked-in output has drifted from the generator; that is left alone here. Test: regenerated with and without MR 43969 -- the only difference is the dispatch below, and the other generated files are identical --- host/vulkan/vk_decoder.cpp | 7 +++---- host/vulkan/vk_decoder_global_state.cpp | 16 ++++++++++++++++ host/vulkan/vk_decoder_global_state.h | 5 +++++ 3 files changed, 24 insertions(+), 4 deletions(-) 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 9c00af40c..408d548dc 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -5480,6 +5480,15 @@ class VkDecoderGlobalState::Impl { physicalDeviceMemHelper->transformToGuestMemoryRequirements(pMemoryRequirements); } + 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); + } + void on_vkGetImageMemoryRequirements2(gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle, VkDevice boxed_device, const VkImageMemoryRequirementsInfo2* pInfo, @@ -12021,6 +12030,13 @@ void VkDecoderGlobalState::on_vkGetImageMemoryRequirements( mImpl->on_vkGetImageMemoryRequirements(pool, apiCallHandle, device, image, pMemoryRequirements); } +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_vkGetImageMemoryRequirements2( gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* 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, From e181255ad339be8647e814f7840fe3b7ef9b5f18 Mon Sep 17 00:00:00 2001 From: Jason Le Date: Tue, 25 Aug 2026 16:19:45 -0700 Subject: [PATCH 2/6] gfxstream: answer a deferred AHB image layout from the AHB itself Intel ANV leaves an AHB-external image's layout unresolved until vkBindImageMemory and reports size=0 until then. That is spec-valid, but guests take it literally: Mesa zink asks for a zero-sized allocation, the host rejects it with VK_ERROR_OUT_OF_HOST_MEMORY, and the compositor dies on the NULL. The image is AHB-external because gfxstream makes it so -- a Linux guest asks for DMA_BUF and transformImpl_VkImageCreateInfo_tohost ORs in the host default, which is what lets the image alias an AHB-backed ColorBuffer. So the requirements have to be answered, not avoided. Allocate the AHB up front for an image the driver refuses to describe, take the size from vkGetAndroidHardwareBufferPropertiesANDROID, and import the same AHB on the guest's dedicated allocation so the layout resolves on bind. The substitution runs in updateImageMemoryRequirementsLocked, so it happens before transformToGuestMemoryRequirements -- necessary because ahbProps.memoryTypeBits is in host indices and that transform maps them to guest indices. Bug: 545345381 Test: Intel PTL host -- Weston reaches its GL renderer and the host substitutes size=3768320 for the 1280x720 scanout image Test: glmark2-wayland runs accelerated on zink/Intel PTL --- host/vulkan/vk_common_operations.cpp | 2 +- host/vulkan/vk_common_operations.h | 10 ++ host/vulkan/vk_decoder_global_state.cpp | 144 ++++++++++++++++++++-- host/vulkan/vk_decoder_internal_structs.h | 19 +++ 4 files changed, 161 insertions(+), 14 deletions(-) diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index 7ea71efa2..98a278892 100644 --- a/host/vulkan/vk_common_operations.cpp +++ b/host/vulkan/vk_common_operations.cpp @@ -2064,7 +2064,7 @@ MTLResource_id VkEmulation::getMtlResourceFromVkDeviceMemory(VulkanDispatch* vk, #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) { +AHardwareBuffer* allocAhb(const VkImageCreateInfo* imageCreateInfo) { // Map VkFormat to the corresponding AHB format — must match to avoid tiling mismatch. uint32_t ahbFormat; switch (imageCreateInfo->format) { diff --git a/host/vulkan/vk_common_operations.h b/host/vulkan/vk_common_operations.h index bafab240e..18a163df9 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 @@ -205,6 +209,7 @@ class VkEmulation { void onVkDeviceLost(); VkExternalMemoryHandleTypeFlagBits getDefaultExternalMemoryHandleType(); + void appendExternalMemoryModeDeviceExtensions(std::vector& outDeviceExtensions); ExternalMemory::Mode getExternalMemoryMode() const; bool supportsExternalMemory() { @@ -740,6 +745,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_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index 408d548dc..09a97033f 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -3164,6 +3164,66 @@ 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; + 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 +5514,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 +5526,7 @@ class VkDecoderGlobalState::Impl { auto vk = dispatch_VkDevice(boxed_device); vk->vkGetImageMemoryRequirements(device, image, pMemoryRequirements); std::lock_guard lock(mMutex); - updateImageMemorySizeLocked(device, image, pMemoryRequirements); + updateImageMemoryRequirementsLocked(device, image, pMemoryRequirements); auto* deviceInfo = gfxstream::base::find(mDeviceInfo, device); if (!deviceInfo) { @@ -5480,6 +5545,7 @@ class VkDecoderGlobalState::Impl { 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, @@ -5487,6 +5553,18 @@ class VkDecoderGlobalState::Impl { 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, @@ -5527,7 +5605,8 @@ class VkDecoderGlobalState::Impl { &pMemoryRequirements->memoryRequirements); } - updateImageMemorySizeLocked(device, pInfo->image, &pMemoryRequirements->memoryRequirements); + updateImageMemoryRequirementsLocked(device, pInfo->image, + &pMemoryRequirements->memoryRequirements); auto& physicalDeviceMemHelper = physicalDeviceInfo->memoryPropertiesHelper; physicalDeviceMemHelper->transformToGuestMemoryRequirements( @@ -6320,6 +6399,32 @@ 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; + 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) { + deferredAhbHold = dlInfo->deferredLayout.ahb; + importDeferredLayoutAhb.buffer = deferredAhbHold.get(); + vk_append_struct(&structChainIter, &importDeferredLayoutAhb); + GFXSTREAM_INFO("DL-AHB import image=%p ahb=%p size=%llu", + (void*)dedicatedAllocInfoPtr->image, + (void*)importDeferredLayoutAhb.buffer, + (unsigned long long)localAllocInfo.allocationSize); + } + } +#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 @@ -10354,14 +10459,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(); } @@ -12024,12 +12142,6 @@ void VkDecoderGlobalState::on_vkCmdCopyImageToBuffer2KHR( mImpl->on_vkCmdCopyImageToBuffer2KHR(pool, apiCallHandle, commandBuffer, pCopyImageToBufferInfo); } -void VkDecoderGlobalState::on_vkGetImageMemoryRequirements( - gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, - VkImage image, VkMemoryRequirements* pMemoryRequirements) { - mImpl->on_vkGetImageMemoryRequirements(pool, apiCallHandle, device, image, pMemoryRequirements); -} - void VkDecoderGlobalState::on_vkGetImageSubresourceLayout( gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout) { @@ -12037,6 +12149,12 @@ void VkDecoderGlobalState::on_vkGetImageSubresourceLayout( pLayout); } +void VkDecoderGlobalState::on_vkGetImageMemoryRequirements( + gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, + VkImage image, VkMemoryRequirements* pMemoryRequirements) { + mImpl->on_vkGetImageMemoryRequirements(pool, apiCallHandle, device, image, pMemoryRequirements); +} + void VkDecoderGlobalState::on_vkGetImageMemoryRequirements2( gfxstream::base::BumpPool* pool, VkSnapshotApiCallHandle apiCallHandle, VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { 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 { From 131d21749d0f1804e57724dfcf0070ff507d265b Mon Sep 17 00:00:00 2001 From: Jason Le Date: Thu, 27 Aug 2026 16:14:30 -0700 Subject: [PATCH 3/6] gfxstream: keep the deferred AHB layout from leaking host-visible types Two gaps @gurchetansingh caught in the AHB-layout deferral: the substituted memoryTypeBits copied ahbProps.memoryTypeBits verbatim, so on a host where the AHB reports HOST_VISIBLE types (Intel ANV's unified memory typically does), the guest could pick one -- the exact case the comment above on_vkGetImageMemoryRequirements says is disallowed, but nothing enforced it. Separately, vkAllocateMemory could append two VkImportAndroidHardwareBufferInfoANDROID structs to the same pNext chain: one from the deferred-layout import, one from an existing VkImportColorBufferGOOGLE import, whenever a dedicated allocation carried both. Mask deferredLayout.memoryTypeBits down to the host's non-host-visible memory types before handing it back, falling back to the full mask only if the AHB has no such type. Skip the deferred-layout import when a ColorBuffer import is already present on the same allocation -- that path supplies its own. Bug: 545345381 Test: fatcat -- Weston GL renderer, desktop and app windows composite correctly, no GFXSTREAM errors --- host/vulkan/vk_decoder_global_state.cpp | 42 +++++++++++++++++++------ 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index 09a97033f..64e09dfcf 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -5526,7 +5526,6 @@ class VkDecoderGlobalState::Impl { auto vk = dispatch_VkDevice(boxed_device); vk->vkGetImageMemoryRequirements(device, image, pMemoryRequirements); std::lock_guard lock(mMutex); - updateImageMemoryRequirementsLocked(device, image, pMemoryRequirements); auto* deviceInfo = gfxstream::base::find(mDeviceInfo, device); if (!deviceInfo) { @@ -5542,6 +5541,8 @@ class VkDecoderGlobalState::Impl { } auto& physicalDeviceMemHelper = physicalDeviceInfo->memoryPropertiesHelper; + updateImageMemoryRequirementsLocked(device, image, pMemoryRequirements, + physicalDeviceMemHelper.get()); physicalDeviceMemHelper->transformToGuestMemoryRequirements(pMemoryRequirements); } @@ -5605,10 +5606,10 @@ class VkDecoderGlobalState::Impl { &pMemoryRequirements->memoryRequirements); } - updateImageMemoryRequirementsLocked(device, pInfo->image, - &pMemoryRequirements->memoryRequirements); - auto& physicalDeviceMemHelper = physicalDeviceInfo->memoryPropertiesHelper; + updateImageMemoryRequirementsLocked(device, pInfo->image, + &pMemoryRequirements->memoryRequirements, + physicalDeviceMemHelper.get()); physicalDeviceMemHelper->transformToGuestMemoryRequirements( &pMemoryRequirements->memoryRequirements); } @@ -6411,7 +6412,10 @@ class VkDecoderGlobalState::Impl { // 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; - if (dedicatedAllocInfoPtr && dedicatedAllocInfoPtr->image != VK_NULL_HANDLE) { + // A ColorBuffer import below appends its own AHB import for this same allocation -- + // skip ours so the chain never carries two VkImportAndroidHardwareBufferInfoANDROID. + if (dedicatedAllocInfoPtr && dedicatedAllocInfoPtr->image != VK_NULL_HANDLE && + !vk_find_struct(pAllocateInfo)) { std::lock_guard dlLock(mMutex); auto* dlInfo = gfxstream::base::find(mImageInfo, dedicatedAllocInfoPtr->image); if (dlInfo && dlInfo->deferredLayout.ahb) { @@ -10459,9 +10463,9 @@ class VkDecoderGlobalState::Impl { return false; } - void updateImageMemoryRequirementsLocked(VkDevice device, VkImage image, - VkMemoryRequirements* pMemoryRequirements) - REQUIRES(mMutex) { + void updateImageMemoryRequirementsLocked( + VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements, + const EmulatedPhysicalDeviceMemoryProperties* memHelper = nullptr) REQUIRES(mMutex) { auto* imageInfo = gfxstream::base::find(mImageInfo, image); if (!imageInfo) return; @@ -10477,7 +10481,27 @@ class VkDecoderGlobalState::Impl { imageInfo->deferredLayout.size > 0) { pMemoryRequirements->size = imageInfo->deferredLayout.size; pMemoryRequirements->alignment = imageInfo->deferredLayout.alignment; - pMemoryRequirements->memoryTypeBits = imageInfo->deferredLayout.memoryTypeBits; + + uint32_t typeBits = imageInfo->deferredLayout.memoryTypeBits; + // The AHB must not be exposed as a host-visible/mappable type: crosvm's + // resource_map_blob() rejects AHB-backed blobs, and on a unified-memory host + // (e.g. Intel ANV) most or all of ahbProps.memoryTypeBits can be HOST_VISIBLE. + // Prefer the non-host-visible subset; fall back to the full mask if the AHB has + // no such type, since some allocation beats failing this call outright. + if (memHelper) { + const auto& hostProps = memHelper->getHostMemoryProperties(); + uint32_t deviceLocalOnlyBits = 0; + for (uint32_t i = 0; i < hostProps.memoryTypeCount; i++) { + if ((typeBits & (1u << i)) && !(hostProps.memoryTypes[i].propertyFlags & + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + deviceLocalOnlyBits |= (1u << i); + } + } + if (deviceLocalOnlyBits != 0) { + typeBits = deviceLocalOnlyBits; + } + } + pMemoryRequirements->memoryTypeBits = typeBits; } #endif } From 02cd169ad9b8771c1f79f280b9b4147289e4cb3a Mon Sep 17 00:00:00 2001 From: Jason Le Date: Fri, 28 Aug 2026 11:44:38 -0700 Subject: [PATCH 4/6] gfxstream: release the deferred-layout AHB once vkAllocateMemory resolves it The probe AHB allocated in on_vkCreateImage to answer a deferred AHB-external image layout was being held for the image's full lifetime, even though vkAllocateMemory is its only consumer: it either gets imported there, or is superseded by a ColorBuffer's own AHB. Release it right after that decision; the cached size/alignment/memoryTypeBits/rowPitch remain for later requirement/layout queries. This does not eliminate the double AHardwareBuffer_allocate() call between the guest image's probe and the ColorBuffer's own backing AHB (createVkColorBufferLocked runs independently, usually before the guest's vkCreateImage, so there is no single pending AHB to hand over without a larger ownership refactor). It does shorten the wasted allocation's lifetime from "until image destruction" to "until vkAllocateMemory returns". Change-Id: I4a5005f28aebb590e913072f50bdf21c868c7d06 --- host/vulkan/vk_decoder_global_state.cpp | 29 +++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index 64e09dfcf..c4558e449 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -6412,20 +6412,27 @@ class VkDecoderGlobalState::Impl { // 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; - // A ColorBuffer import below appends its own AHB import for this same allocation -- - // skip ours so the chain never carries two VkImportAndroidHardwareBufferInfoANDROID. - if (dedicatedAllocInfoPtr && dedicatedAllocInfoPtr->image != VK_NULL_HANDLE && - !vk_find_struct(pAllocateInfo)) { + 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) { - deferredAhbHold = dlInfo->deferredLayout.ahb; - importDeferredLayoutAhb.buffer = deferredAhbHold.get(); - vk_append_struct(&structChainIter, &importDeferredLayoutAhb); - GFXSTREAM_INFO("DL-AHB import image=%p ahb=%p size=%llu", - (void*)dedicatedAllocInfoPtr->image, - (void*)importDeferredLayoutAhb.buffer, - (unsigned long long)localAllocInfo.allocationSize); + // 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); + 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(); } } #endif From a290b16a21b4ea38d567903608b2b70907b325ea Mon Sep 17 00:00:00 2001 From: Jason Le Date: Wed, 2 Sep 2026 17:37:32 -0700 Subject: [PATCH 5/6] gfxstream: reuse deferred-layout AHB for ColorBuffer Keep deferred-layout probe AHBs in a shape-keyed pool so a matching ColorBuffer can reuse one instead of allocating another. Remove the probe when its source image imports it, preventing reuse of an in-use AHB. Bug: 545345381 Test: fatcat, Intel PTL, SystemBlob enabled and udmabuf disabled; Weston reaches its GL renderer with no error or SIGSEGV Change-Id: I1e851037788481e031eb5ac617fff7beb8494042 --- host/vulkan/vk_common_operations.cpp | 79 ++++++++++++++++++++++--- host/vulkan/vk_common_operations.h | 58 ++++++++++++++++++ host/vulkan/vk_decoder_global_state.cpp | 17 ++++++ 3 files changed, 147 insertions(+), 7 deletions(-) diff --git a/host/vulkan/vk_common_operations.cpp b/host/vulkan/vk_common_operations.cpp index 8289aa9c7..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). -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 @@ 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 @@ 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 18a163df9..99e14cbcb 100644 --- a/host/vulkan/vk_common_operations.h +++ b/host/vulkan/vk_common_operations.h @@ -89,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 @@ -471,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; @@ -712,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); diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index c4558e449..ca1217486 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -3205,6 +3205,11 @@ class VkDecoderGlobalState::Impl { 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)", @@ -6412,6 +6417,13 @@ class VkDecoderGlobalState::Impl { // 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); @@ -6423,6 +6435,8 @@ class VkDecoderGlobalState::Impl { 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, @@ -6435,6 +6449,9 @@ class VkDecoderGlobalState::Impl { 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 From e55963e800f9253371761f4c692e389f76bf94c7 Mon Sep 17 00:00:00 2001 From: Jason Le Date: Fri, 4 Sep 2026 11:29:28 -0700 Subject: [PATCH 6/6] gfxstream: drop the deferred-layout memoryTypeBits filtering The substituted memoryTypeBits were masked down to the host's non-host-visible types, on the theory that letting the guest pick a host-visible type for an AHB-backed image would send it into resource_map_blob(), which rejects AHB handles. The guest never tries to map it: ColorBuffers are created with kBlobFlagShareable | kBlobFlagCrossDevice and not kBlobFlagMappable, so nothing asks for a mappable type in the first place. Hand back what the AHB reports and let the driver's own bits stand, rather than keeping code that looks load-bearing for correctness but is not. This also drops the memHelper parameter that existed only to feed the mask. Bug: 545345381 Test: fatcat, Intel PTL -- typeBits now handed back unmasked as 0x3f (all six host types, host-visible included). Weston still reaches its GL renderer, size=3768320 is still substituted for the 1280x720 scanout image, and there is no mmap64/EINVAL, no resource_map_blob failure, no vkMapMemory failure and no SIGSEGV. Change-Id: I97cd32a878c17580cd1f09218cde09e9cbffe834 --- host/vulkan/vk_decoder_global_state.cpp | 34 +++++-------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/host/vulkan/vk_decoder_global_state.cpp b/host/vulkan/vk_decoder_global_state.cpp index ca1217486..8fd2bbb7c 100644 --- a/host/vulkan/vk_decoder_global_state.cpp +++ b/host/vulkan/vk_decoder_global_state.cpp @@ -5546,8 +5546,7 @@ class VkDecoderGlobalState::Impl { } auto& physicalDeviceMemHelper = physicalDeviceInfo->memoryPropertiesHelper; - updateImageMemoryRequirementsLocked(device, image, pMemoryRequirements, - physicalDeviceMemHelper.get()); + updateImageMemoryRequirementsLocked(device, image, pMemoryRequirements); physicalDeviceMemHelper->transformToGuestMemoryRequirements(pMemoryRequirements); } @@ -5613,8 +5612,7 @@ class VkDecoderGlobalState::Impl { auto& physicalDeviceMemHelper = physicalDeviceInfo->memoryPropertiesHelper; updateImageMemoryRequirementsLocked(device, pInfo->image, - &pMemoryRequirements->memoryRequirements, - physicalDeviceMemHelper.get()); + &pMemoryRequirements->memoryRequirements); physicalDeviceMemHelper->transformToGuestMemoryRequirements( &pMemoryRequirements->memoryRequirements); } @@ -10487,9 +10485,9 @@ class VkDecoderGlobalState::Impl { return false; } - void updateImageMemoryRequirementsLocked( - VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements, - const EmulatedPhysicalDeviceMemoryProperties* memHelper = nullptr) REQUIRES(mMutex) { + void updateImageMemoryRequirementsLocked(VkDevice device, VkImage image, + VkMemoryRequirements* pMemoryRequirements) + REQUIRES(mMutex) { auto* imageInfo = gfxstream::base::find(mImageInfo, image); if (!imageInfo) return; @@ -10505,27 +10503,7 @@ class VkDecoderGlobalState::Impl { imageInfo->deferredLayout.size > 0) { pMemoryRequirements->size = imageInfo->deferredLayout.size; pMemoryRequirements->alignment = imageInfo->deferredLayout.alignment; - - uint32_t typeBits = imageInfo->deferredLayout.memoryTypeBits; - // The AHB must not be exposed as a host-visible/mappable type: crosvm's - // resource_map_blob() rejects AHB-backed blobs, and on a unified-memory host - // (e.g. Intel ANV) most or all of ahbProps.memoryTypeBits can be HOST_VISIBLE. - // Prefer the non-host-visible subset; fall back to the full mask if the AHB has - // no such type, since some allocation beats failing this call outright. - if (memHelper) { - const auto& hostProps = memHelper->getHostMemoryProperties(); - uint32_t deviceLocalOnlyBits = 0; - for (uint32_t i = 0; i < hostProps.memoryTypeCount; i++) { - if ((typeBits & (1u << i)) && !(hostProps.memoryTypes[i].propertyFlags & - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { - deviceLocalOnlyBits |= (1u << i); - } - } - if (deviceLocalOnlyBits != 0) { - typeBits = deviceLocalOnlyBits; - } - } - pMemoryRequirements->memoryTypeBits = typeBits; + pMemoryRequirements->memoryTypeBits = imageInfo->deferredLayout.memoryTypeBits; } #endif }