stride3d/stride · error · InvalidOperationException
Vulkan: no memory type satisfies the IOSurface…
Error message
Vulkan: no memory type satisfies the IOSurface memoryTypeBits mask.
What it means
During IOSurface import, Stride queries IOSurface memory requirements via vkGetMetalIOSurfaceCreateInfoEXT/vkBindMetalIOSurface flow and picks a Vulkan memory type from the returned memoryTypeBits mask. FindMemoryTypeIndex throws InvalidOperationException when no physical-device memory type intersects that mask, meaning the driver cannot back this IOSurface import with any available memory.
Solutions
- Recreate the IOSurface with GPU-capable storage/usage (kIOSurfaceStorageModeShared or GPU-friendly pixel format such as BGRA8/RGBA8).
- Verify the IOSurface pixel format is one the Vulkan/MoltenVK implementation can import (e.g. MTLPixelFormat-compatible formats like BGRA8Unorm).
- Update MoltenVK to a newer release with complete metal_objects support, then rebuild the device with VK_EXT_metal_objects enabled.
- Fall back to reading the IOSurface pixels on CPU and uploading through Texture.Load/regular staging upload instead of direct import.
Example fix
// before: CPU-only IOSurface var ioSurface = IOSurface.Create(width, height, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, kIOSurfaceStorageModePrivate); // after: GPU-shareable format/storage var ioSurface = IOSurface.Create(width, height, kCVPixelFormatType_32BGRA, kIOSurfaceStorageModeShared);
Defensive patterns
Strategy: try-catch
Try / catch
try
{
texture = Texture.NewFromIOSurface(device, ioSurface, width, height);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("memoryTypeBits"))
{
log.Error("IOSurface has no compatible Vulkan memory type; falling back to CPU upload.");
texture = UploadSurfaceData(device, ioSurface, width, height);
} Prevention
- Create IOSurfaces with GPU-shareable storage modes and standard pixel formats (BGRA8/RGBA8).
- Avoid importing surfaces produced by camera/video pipelines with CPU-only storage modes.
- Keep MoltenVK up to date; incomplete metal_objects support yields zero masks.
- Implement a CPU read + upload fallback so zero-copy import failure is non-fatal.
When it happens
Trigger: Calling NewFromIOSurface where vkGetIOSurfaceProperties/Metal-objects property query yields a memoryTypeBits mask of 0 or disjoint from all device memory types; importing an IOSurface with pixel format/usage not supported by the GPU; MoltenVK reporting incomplete memory requirements for the surface.
Common situations: Importing IOSurfaces with exotic pixel formats or non-GPU-compatible usages; old MoltenVK builds with incomplete VK_EXT_metal_objects implementations; surfaces created by another subsystem (camera, video decode) without GPU-readable storage modes; mismatched storage mode (CPU-only) IOSurfaces.
Related errors
- IOSurface import requires VK_EXT_metal_objects.
- Required extension is not available
- Vulkan: no memory type satisfies the AHardwareBuffer…
- AVAssetReader (audio) create failed
- AVAssetReader.StartReading (audio) failed
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/7c9ac75e5b86066e.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/Vulkan/Texture.Apple.Vulkan.cs:154
texture.NativeImage = image;
texture.NativeMemory = memory;
texture.NativeImageView = imageView;
texture.NativeFormat = VkFormat.B8G8R8A8Srgb;
texture.ioSurfaceRef = ioSurface;
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 IOSurface memoryTypeBits mask.");
}
[DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
private static extern IntPtr CFRetain(IntPtr cf);
[DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
private static extern void CFRelease(IntPtr cf);
}
}
#endif
View on GitHub (pinned to 96fad776d2)