stride3d/stride · error · InvalidOperationException
IOSurface import requires VK_EXT_metal_objects.
Error message
IOSurface import requires VK_EXT_metal_objects.
What it means
Texture.NewFromIOSurface imports an Apple IOSurface as a Vulkan texture on macOS/iOS, which requires the VK_EXT_metal_objects extension (device.HasMetalObjectsSupport). If the Vulkan implementation (e.g. MoltenVK) does not report support, Stride throws InvalidOperationException instead of attempting the import.
Solutions
- Check device.HasMetalObjectsSupport before calling and fall back to uploading texture data normally when it is false.
- Upgrade MoltenVK to a version supporting VK_EXT_metal_objects and rebuild the Vulkan device enabling the extension in the device extension list.
- Ensure the GraphicsDevice creation requests VK_EXT_metal_objects (and dependency VK_KHR_portability_subset where needed) rather than using a default device config.
- Verify you are actually on the Vulkan/MoltenVK backend and not another backend misconfigured to use the Vulkan IOSurface path.
Example fix
// before
var texture = Texture.NewFromIOSurface(device, surfaceHandle, width, height);
// after
if (device.HasMetalObjectsSupport)
texture = Texture.NewFromIOSurface(device, surfaceHandle, width, height);
else
texture = UploadSurfaceData(device, surfaceHandle, width, height); Defensive patterns
Strategy: validation
Validate before calling
if (device == null || ioSurface == IntPtr.Zero) throw new ArgumentException("Invalid device or IOSurface.");
if (!device.HasMetalObjectsSupport)
throw new NotSupportedException("VK_EXT_metal_objects unavailable; IOSurface import not supported."); Type guard
bool CanImportIOSurface(GraphicsDevice device) => device != null && device.HasMetalObjectsSupport;
Try / catch
try
{
texture = Texture.NewFromIOSurface(device, ioSurface, width, height);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("VK_EXT_metal_objects"))
{
texture = UploadSurfaceData(device, ioSurface, width, height);
} Prevention
- Gate IOSurface imports behind device.HasMetalObjectsSupport.
- Use a recent MoltenVK and enable VK_EXT_metal_objects at device creation.
- Verify at app startup which Vulkan ICD is active on macOS.
- Keep a CPU-side texture upload fallback for machines without metal_objects support.
When it happens
Trigger: Calling Texture.NewFromIOSurface(device, ioSurface, w, h) on a GraphicsDevice whose physical device lacks VK_EXT_metal_objects, or where the extension was not enabled at device creation; using a Vulkan ICD other than MoltenVK with no Metal interop support.
Common situations: macOS builds with a non-MoltenVK Vulkan loader/ICD; old MoltenVK versions before VK_EXT_metal_objects support; creating the Vulkan device without requesting VK_EXT_metal_objects; attempting IOSurface sharing on iOS where support configuration differs.
Related errors
- Required extension is not available
- Vulkan: no memory type satisfies the IOSurface…
- AHardwareBuffer import requires…
- AVAssetReader (audio) create failed
- AVAssetReader.StartReading (audio) failed
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/3a97765c259c4b0d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/Vulkan/Texture.Apple.Vulkan.cs:60
{
if (ioSurfaceRef != IntPtr.Zero)
{
CFRelease(ioSurfaceRef);
ioSurfaceRef = IntPtr.Zero;
}
}
/// <summary>
/// Imports a CoreVideo IOSurface as a sampleable BGRA8_sRGB <see cref="Texture"/> via VK_EXT_metal_objects.
/// Retains the IOSurface for the lifetime of the returned Texture; the caller is free to dispose its
/// CVPixelBuffer once this call returns.
/// </summary>
public static unsafe Texture NewFromIOSurface(GraphicsDevice device, IntPtr ioSurface, int width, int height)
{
if (device == null) throw new ArgumentNullException(nameof(device));
if (ioSurface == IntPtr.Zero) throw new ArgumentNullException(nameof(ioSurface));
if (!device.HasMetalObjectsSupport)
throw new InvalidOperationException("IOSurface import requires VK_EXT_metal_objects.");
CFRetain(ioSurface);
var ioSurfaceInfo = new VkImportMetalIOSurfaceInfoEXT
{
sType = VkStructureType.ImportMetalIOSurfaceInfoEXT,
ioSurface = ioSurface,
};
var imageCreateInfo = new VkImageCreateInfo
{
sType = VkStructureType.ImageCreateInfo,
pNext = &ioSurfaceInfo,
imageType = VkImageType.Image2D,
format = VkFormat.B8G8R8A8Srgb,
extent = new VkExtent3D(width, height, 1),
mipLevels = 1,
arrayLayers = 1,View on GitHub (pinned to 96fad776d2)