{"record":{"id":"70c165d439782061","repo":"AvaloniaUI/Avalonia","slug":"need-skia-to-dump-textures-sorry","errorCode":null,"errorMessage":"Need skia to dump textures, sorry","messagePattern":"Need skia to dump textures, sorry","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"samples/GpuInterop/VulkanDemo/VulkanImage.cs","lineNumber":365,"sourceCode":"                {\n                    var surf = ExportIOSurface();\n                    if (NativeMethods.IOSurfaceLock(surf, 0, IntPtr.Zero) != 0)\n                        throw new Exception(\"IOSurfaceLock failed\");\n                    var w = (int)NativeMethods.IOSurfaceGetWidth(surf);\n                    var h = (int)NativeMethods.IOSurfaceGetHeight(surf);\n                    var sstride = NativeMethods.IOSurfaceGetBytesPerRow(surf);\n\n                    var pSurface = NativeMethods.IOSurfaceGetBaseAddress(surf);\n                    using var b = new Avalonia.Media.Imaging.Bitmap(PixelFormat.Bgra8888,\n                        AlphaFormat.Premul, pSurface, new PixelSize(w, h),\n                        new Vector(96, 96), (int)sstride);\n                    b.Save(path, PngBitmapEncoderOptions.Default);\n\n                    NativeMethods.IOSurfaceUnlock(surf, 0, IntPtr.Zero);\n                    return;\n                }\n                else\n                    throw new NotSupportedException(\"Need skia to dump textures, sorry\");\n            }\n\n            _vk.GrContext.ResetContext();\n            var _image = this;\n            var imageInfo = new GRVkImageInfo()\n            {\n                CurrentQueueFamily = _vk.QueueFamilyIndex,\n                Format = (uint)_image.Format,\n                Image = _image.Handle,\n                ImageLayout = (uint)_image.CurrentLayout,\n                ImageTiling = (uint)_image.Tiling,\n                ImageUsageFlags = (uint)_image.UsageFlags,\n                LevelCount = _image.MipLevels,\n                SampleCount = 1,\n                Protected = false,\n                Alloc = new GRVkAlloc()\n                {\n                    Memory = _image.MemoryHandle, Flags = 0, Offset = 0, Size = _image.MemorySize","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/samples/GpuInterop/VulkanDemo/VulkanImage.cs#L347-L383","documentation":"In SaveTexture, when there is no Skia GPU context (_vk.GrContext == null) and no IOSurface path available, the sample throws NotSupportedException. It means the texture-dump fallback requires Skia (GrContext) to read GPU pixels, and on non-macOS without Skia it cannot proceed.","triggerScenarios":"Calling SaveTexture when the demo has no GrContext (SkiaSharp GPU context) wired up and the platform is not macOS-with-IOSurface. The code only handles IOSurface on macOS; everything else routes through Skia, which is absent here.","commonSituations":"Running the Vulkan demo on Linux/Windows where the Skia GPU bridge was not initialized; GrContext disposed before dump; trimming/AOT removing Skia.","solutions":["Initialize and keep a valid Skia GrContext bound to the Vulkan device so SaveTexture can use it.","On macOS, ensure _hasIOSurface is true so the IOSurface dump path is taken instead.","Avoid calling SaveTexture when no GPU readback backend (Skia or IOSurface) is available.","Implement a plain vkCmdCopyImageToBuffer readback fallback if Skia is undesirable."],"exampleFix":"// before\nelse\n    throw new NotSupportedException(\"Need skia to dump textures, sorry\");\n\n// after (explicit, actionable)\nelse\n    throw new NotSupportedException(\n        \"Texture dump requires a Skia GrContext (or an IOSurface on macOS). Initialize _vk.GrContext before calling SaveTexture.\");","handlingStrategy":"validation","validationCode":"// only attempt a dump if a readback backend exists\nvar canDump = _vk.GrContext is not null || (OperatingSystem.IsOSPlatform(OSPlatform.OSX) && _hasIOSurface);\nif (!canDump) return;","typeGuard":"static bool HasReadbackBackend(VulkanImage img) => img._vk.GrContext is not null || img._hasIOSurface;","tryCatchPattern":"try { SaveTexture(path); }\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"skia\"))\n{ _logger.LogWarning(\"No Skia GPU context; cannot dump texture.\"); }","preventionTips":["Initialize a Skia GrContext on Linux/Windows if you need texture dumps.","On macOS, ensure _hasIOSurface so the IOSurface path is used.","Gate SaveTexture behind a readback-backend check."],"tags":["skia","vulkan","texture","dump","macos","sample"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}