{"record":{"id":"04ca6301712a211b","repo":"stride3d/stride","slug":"vulkan-no-memory-type-satisfies-the-ahardwarebuffer","errorCode":null,"errorMessage":"Vulkan: no memory type satisfies the AHardwareBuffer memoryTypeBits mask.","messagePattern":"Vulkan: no memory type satisfies the AHardwareBuffer memoryTypeBits mask\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Vulkan/Texture.Android.Vulkan.cs","lineNumber":216,"sourceCode":"            texture.NativeMemory = memory;\n            texture.NativeImageView = imageView;\n            texture.NativeSamplerYcbcrConversion = ycbcrConversion;\n            texture.androidHardwareBuffer = hardwareBuffer;\n            texture.NativeFormat = formatInfo.format;\n            texture.isImportedImage = true;\n            texture.InitializeFrom(description);\n            return texture;\n        }\n\n        private static unsafe uint FindMemoryTypeIndex(GraphicsDevice device, uint memoryTypeBits)\n        {\n            device.NativeInstanceApi.vkGetPhysicalDeviceMemoryProperties(device.NativePhysicalDevice, out var memoryProperties);\n            for (uint i = 0; i < memoryProperties.memoryTypeCount; i++)\n            {\n                if ((memoryTypeBits & (1u << (int)i)) != 0)\n                    return i;\n            }\n            throw new InvalidOperationException(\"Vulkan: no memory type satisfies the AHardwareBuffer memoryTypeBits mask.\");\n        }\n\n        // P/Invokes for libandroid AHardwareBuffer reference counting / description.\n        // Available on Android API 26+ (already required by the rest of the platform).\n        [DllImport(\"android\")]\n        private static extern void AHardwareBuffer_acquire(IntPtr buffer);\n\n        [DllImport(\"android\")]\n        private static extern void AHardwareBuffer_release(IntPtr buffer);\n\n        [DllImport(\"android\")]\n        private static extern void AHardwareBuffer_describe(IntPtr buffer, out AHardwareBufferDesc outDesc);\n\n        [StructLayout(LayoutKind.Sequential)]\n        private struct AHardwareBufferDesc\n        {\n            public uint Width;\n            public uint Height;","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Vulkan/Texture.Android.Vulkan.cs#L198-L234","documentation":"During AHardwareBuffer import, Stride picks a Vulkan memory type index from the memoryTypeBits mask returned by the Android hardware buffer (via vkGetAndroidHardwareBufferPropertiesANDROID). FindMemoryTypeIndex scans the physical device's memory types and throws InvalidOperationException when no memory type intersects the buffer's required mask, i.e. the driver offers no compatible memory heap for this buffer.","triggerScenarios":"Calling NewFromAndroidHardwareBuffer on a device whose vkGetAndroidHardwareBufferPropertiesANDROID returns a memoryTypeBits mask of 0 or one disjoint from all memory types; passing an AHardwareBuffer with format/usage combinations unsupported by the GPU (e.g. unsupported YUV or CPU-only-usable buffer); a driver returning invalid properties.","commonSituations":"Importing AHardwareBuffers with unusual format/usage flags (e.g. GPU-incompatible producer usages from camera or codecs) on quirky OEM drivers; emulator Vulkan ICDs with incomplete external-memory property reporting; buffers produced with usage bits that don't map to any device-local memory type.","solutions":["Verify the AHardwareBuffer was created with GPU-capable usage flags (AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLEABLE_IMAGE) from the producer side.","Check that the buffer format is GPU-supported; recreate the buffer with a common format (RGBA8_UNORM) if using exotic camera/codec formats.","Confirm the extension support check passed (device.HasAndroidHardwareBufferSupport) and that vkGetAndroidHardwareBufferPropertiesANDROID succeeds — a zero mask usually means bad properties from the driver; update the device's Vulkan driver.","Fall back to a CPU round-trip: read the buffer contents on Android and upload via a regular Texture upload instead of zero-copy import.","Test on a different physical device/driver to rule out an emulator or OEM ICD bug."],"exampleFix":"// before: buffer created without GPU usage\nAHardwareBuffer_Desc desc = { .format = AHARDWAREBUFFER_FORMAT_BLOB, .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN };\n\n// after: GPU-usable usage so a memory type exists\ndesc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLEABLE_IMAGE | desc.usage;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    texture = Texture.NewFromAndroidHardwareBuffer(device, hardwareBuffer);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"memoryTypeBits\"))\n{\n    log.Error(\"AHardwareBuffer has no compatible Vulkan memory type; falling back to CPU upload.\");\n    texture = UploadFallbackTexture(device, hardwareBuffer);\n}","preventionTips":["Create producer AHardwareBuffers with GPU usage flags (GPU_COLOR_OUTPUT | GPU_SAMPLEABLE_IMAGE).","Use widely supported formats like RGBA8_UNORM instead of camera/codec-specific formats.","Test on real hardware and multiple OEM drivers; emulator ICDs are the usual culprit.","Always implement a non-import fallback upload path for zero-copy failures."],"tags":["vulkan","android","memory-allocation","hardware-buffer"],"backgroundTag":"no-suitable-vulkan-memory-type","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}