stride3d/stride · error · InvalidOperationException

AHardwareBuffer import requires…

Error message

AHardwareBuffer import requires VK_ANDROID_external_memory_android_hardware_buffer.

What it means

Texture.NewFromAndroidHardwareBuffer imports an Android AHardwareBuffer as a Vulkan texture. This requires the Vulkan driver to expose the VK_ANDROID_external_memory_android_hardware_buffer extension (device.HasAndroidHardwareBufferSupport). If the physical device lacks that extension, Stride throws InvalidOperationException rather than attempting an import the driver cannot perform.

Solutions

  1. Check device.HasAndroidHardwareBufferSupport before calling NewFromAndroidHardwareBuffer and use a fallback (copy the buffer via CPU or a different sharing path) when it is false.
  2. Recreate the GraphicsDevice enabling the extension chain: VK_ANDROID_external_memory_android_hardware_buffer plus its dependencies (VK_KHR_external_memory, VK_KHR_sampler_ycbcr_conversion) in device creation.
  3. Run on physical hardware/Android 8.0+ (API 26) with a driver that supports AHardwareBuffer import instead of an emulator or outdated ICD.
  4. Update the GPU driver/OEM Vulkan ICD, which may add the extension.

Example fix

// before
displayTexture = Texture.NewFromAndroidHardwareBuffer(device, surfaceView.HardwareBuffer);

// after
if (device.HasAndroidHardwareBufferSupport)
    displayTexture = Texture.NewFromAndroidHardwareBuffer(device, surfaceView.HardwareBuffer);
else
    displayTexture = CopyHardwareBufferToTexture(device, surfaceView.HardwareBuffer);
Defensive patterns

Strategy: validation

Validate before calling

if (device == null || hardwareBuffer == IntPtr.Zero) throw new ArgumentException("Invalid device or hardware buffer.");
if (!device.HasAndroidHardwareBufferSupport)
    throw new NotSupportedException("VK_ANDROID_external_memory_android_hardware_buffer unavailable; use fallback upload.");

Type guard

bool CanImportAHardwareBuffer(GraphicsDevice device) => device != null && device.HasAndroidHardwareBufferSupport;

Try / catch

try
{
    texture = Texture.NewFromAndroidHardwareBuffer(device, hardwareBuffer);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("VK_ANDROID_external_memory_android_hardware_buffer"))
{
    texture = UploadFallbackTexture(device, hardwareBuffer);
}

Prevention

When it happens

Trigger: Calling Texture.NewFromAndroidHardwareBuffer(device, buffer) on a GraphicsDevice whose Vulkan physical device does not report VK_ANDROID_external_memory_android_hardware_buffer; also when the extension is available but not enabled at device creation because the required instance/device extension chain was not requested.

Common situations: Running on an Android emulator or older/low-end GPU whose Vulkan ICD omits the extension; on devices below Android API 26 where AHardwareBuffer APIs are missing; enabling Vulkan on Android without enabling the extension chain (VK_KHR_external_memory, AndroidSamplerYcbcrConversion dependencies) during device creation.

Related errors


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

Appendix: source

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

            {
                GraphicsDevice.Collect(NativeSamplerYcbcrConversion);
                NativeSamplerYcbcrConversion = VkSamplerYcbcrConversion.Null;
            }
            if (androidHardwareBuffer != IntPtr.Zero)
            {
                AHardwareBuffer_release(androidHardwareBuffer);
                androidHardwareBuffer = IntPtr.Zero;
            }
        }

        /// <summary>Imports an <c>AHardwareBuffer</c> as a Vulkan-backed sampleable Texture.
        /// Acquires a reference released when the Texture is destroyed.</summary>
        public static unsafe Texture NewFromAndroidHardwareBuffer(GraphicsDevice device, IntPtr hardwareBuffer)
        {
            if (device == null) throw new ArgumentNullException(nameof(device));
            if (hardwareBuffer == IntPtr.Zero) throw new ArgumentNullException(nameof(hardwareBuffer));
            if (!device.HasAndroidHardwareBufferSupport)
                throw new InvalidOperationException("AHardwareBuffer import requires VK_ANDROID_external_memory_android_hardware_buffer.");

            AHardwareBuffer_acquire(hardwareBuffer);

            AHardwareBufferDesc desc;
            AHardwareBuffer_describe(hardwareBuffer, out desc);

            var formatInfo = new VkAndroidHardwareBufferFormatPropertiesANDROID
            {
                sType = VkStructureType.AndroidHardwareBufferFormatPropertiesAndroid,
            };
            var props = new VkAndroidHardwareBufferPropertiesANDROID
            {
                sType = VkStructureType.AndroidHardwareBufferPropertiesAndroid,
                pNext = &formatInfo,
            };
            device.CheckResult(device.NativeDeviceApi.vkGetAndroidHardwareBufferPropertiesANDROID(device.NativeDevice, hardwareBuffer, &props));

            // Non-zero externalFormat = buffer needs sampler-YCbCr conversion to read as RGB.

View on GitHub (pinned to 96fad776d2)