stride3d/stride · error · InvalidOperationException

Vulkan: no memory type satisfies the AHardwareBuffer…

Error message

Vulkan: no memory type satisfies the AHardwareBuffer memoryTypeBits mask.

What it means

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.

Solutions

  1. Verify the AHardwareBuffer was created with GPU-capable usage flags (AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLEABLE_IMAGE) from the producer side.
  2. Check that the buffer format is GPU-supported; recreate the buffer with a common format (RGBA8_UNORM) if using exotic camera/codec formats.
  3. 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.
  4. 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.
  5. Test on a different physical device/driver to rule out an emulator or OEM ICD bug.

Example fix

// before: buffer created without GPU usage
AHardwareBuffer_Desc desc = { .format = AHARDWAREBUFFER_FORMAT_BLOB, .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN };

// after: GPU-usable usage so a memory type exists
desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLEABLE_IMAGE | desc.usage;
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    texture = Texture.NewFromAndroidHardwareBuffer(device, hardwareBuffer);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("memoryTypeBits"))
{
    log.Error("AHardwareBuffer has no compatible Vulkan memory type; falling back to CPU upload.");
    texture = UploadFallbackTexture(device, hardwareBuffer);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/04ca6301712a211b. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Vulkan/Texture.Android.Vulkan.cs:216

            texture.NativeMemory = memory;
            texture.NativeImageView = imageView;
            texture.NativeSamplerYcbcrConversion = ycbcrConversion;
            texture.androidHardwareBuffer = hardwareBuffer;
            texture.NativeFormat = formatInfo.format;
            texture.isImportedImage = true;
            texture.InitializeFrom(description);
            return texture;
        }

        private static unsafe uint FindMemoryTypeIndex(GraphicsDevice device, uint memoryTypeBits)
        {
            device.NativeInstanceApi.vkGetPhysicalDeviceMemoryProperties(device.NativePhysicalDevice, out var memoryProperties);
            for (uint i = 0; i < memoryProperties.memoryTypeCount; i++)
            {
                if ((memoryTypeBits & (1u << (int)i)) != 0)
                    return i;
            }
            throw new InvalidOperationException("Vulkan: no memory type satisfies the AHardwareBuffer memoryTypeBits mask.");
        }

        // P/Invokes for libandroid AHardwareBuffer reference counting / description.
        // Available on Android API 26+ (already required by the rest of the platform).
        [DllImport("android")]
        private static extern void AHardwareBuffer_acquire(IntPtr buffer);

        [DllImport("android")]
        private static extern void AHardwareBuffer_release(IntPtr buffer);

        [DllImport("android")]
        private static extern void AHardwareBuffer_describe(IntPtr buffer, out AHardwareBufferDesc outDesc);

        [StructLayout(LayoutKind.Sequential)]
        private struct AHardwareBufferDesc
        {
            public uint Width;
            public uint Height;

View on GitHub (pinned to 96fad776d2)