Graphite shader-error handler + fix iOS-simulator dst read (mono/SkiaSharp#4555) - #308
Open
ramezgerges wants to merge 3 commits into
Open
Conversation
14 tasks
Skia's Graphite backend accepts a ShaderErrorHandler on its C++ ContextOptions and calls back into it whenever a driver-side shader compile fails (MSL for Metal, SPIR-V/GLSL for Vulkan, WGSL for Dawn). The default handler asserts + prints via SkDebugf, which is invisible in shipping apps on iOS/tvOS — see mono/SkiaSharp#4555 where a gradient scene silently returns a null Snap() on the Metal iOS simulator with no way to capture the failing shader text. Expose the hook on the C ABI so managed SkiaSharp callers can install a diagnostic. fShaderErrorHandler is stored as void* rather than the proc typedef so the generated managed struct stays unmanaged in both LibraryImport and delegate P/Invoke modes; a leaked FfiShaderErrorHandler bridge (one per Context creation) forwards Skia's compileError(shader, errors, wasCached) into the caller-provided function pointer. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ndler A Graphite Metal shader can pass the MSL front-end compile yet still be rejected when the MTLRenderPipelineState is created; until now that path only printed via SKIA_LOG_E (SkDebugf), which is invisible in shipping apps on iOS/tvOS, and Recorder::snap() surfaced it as a bare null. This is exactly the mono/SkiaSharp#4555 failure mode: on the iOS simulator the framebuffer-fetch gradient/blend pipeline compiles as MSL but newRenderPipelineStateWithDescriptor fails with CompilerError Code=2 "reading from a rendertarget is not supported". Route the NSError text through ShaderErrorHandler::compileError (with the pipeline label as the "shader" text) so the sk_graphite_context_options.fShaderErrorHandler hook added for #4555 sees driver-side PSO rejections too, not just MSL compile errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MtlCaps enabled framebuffer fetch (sk_LastFragColor [[color(0)]]) for every Apple-family GPU, and Caps::getDstReadStrategy() then always picks kFramebufferFetch for dst reads. The iOS/tvOS simulator advertises an Apple GPU family but its Metal implementation cannot read from a render target in a fragment shader: the MSL compiles, but PSO creation fails with CompilerError Code=2 "reading from a rendertarget is not supported", so any draw needing a dst read (e.g. a non-coefficient blend like kMultiply) nulls the pipeline and Recorder::snap() returns null. This is the root cause of mono/SkiaSharp#4555: the GradientBlend visual scene (linear gradient + Multiply-blended circle) failed only on Graphite/Metal on the iOS simulator. Ganesh Metal never uses framebuffer fetch (dst-copies instead) and real Apple devices / Apple-silicon macOS support it, which is why every other cell of the matrix rendered. Keep FB fetch off under TARGET_OS_SIMULATOR so dst reads fall back to DstReadStrategy::kTextureCopy, which the simulator handles correctly — verified by the SkiaSharp iOS visual matrix, where GradientBlend now renders pixel-identically to the graphite-metal.macos golden. Fixes mono/SkiaSharp#4555. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ramezgerges
force-pushed
the
dev/issue-4555-graphite-shader-error-handler
branch
from
August 3, 2026 17:41
34ee9f3 to
0ae988f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Three related changes that together fix mono/SkiaSharp#4555 (Graphite/Metal
GradientBlendcell returning nullRecorder::Snap()on the iOS simulator) and give SkiaSharp callers a way to see the shader/PSO compile diagnostics behind similar failures in the future.Commits:
Add
sk_graphite_context_options.fShaderErrorHandlercallback — expose Graphite'sskgpu::ShaderErrorHandleron the C API so callers can capture SkSL→driver shader compile failures. Skia's default handler isSkDebugf+ assert, which is invisible on iOS/tvOS. Bridged through a heap-allocatedFfiShaderErrorHandlerreferenced byContextOptions.fShaderErrorHandler(Skia stores it as a raw non-owning pointer, so the wrapper is deliberately leaked — one per Context creation with a handler set).Report Graphite Metal PSO-creation failures through the ShaderErrorHandler — a Graphite Metal shader can pass the MSL front-end compile yet still be rejected at
newRenderPipelineStateWithDescriptortime. Previously that failure only surfaced viaSKIA_LOG_E; now theNSErrortext goes throughShaderErrorHandler::compileErroralongside the MSL compile path. This is exactly the #4555 failure mode: MSL compiled, PSO creation failed withCompilerError Code=2 "reading from a rendertarget is not supported",Recorder::snap()returned bare null.Disable Graphite framebuffer fetch on the Metal simulator —
MtlCapsenabled framebuffer fetch (sk_LastFragColor [[color(0)]]) for every Apple-family GPU, andCaps::getDstReadStrategy()then always pickedkFramebufferFetchfor dst reads. The iOS/tvOS simulator advertises an Apple GPU family but its Metal implementation cannot read from a render target in a fragment shader. Root cause of #4555:GradientBlend's Multiply-blended circle needs a dst read → picked framebuffer fetch → PSO rejected → null Snap. Ganesh Metal never uses framebuffer fetch (dst-copies instead) and real Apple devices/macOS support it, which is why every other cell of the matrix rendered fine. Fix: keep FB fetch off underTARGET_OS_SIMULATORso dst reads fall back toDstReadStrategy::kTextureCopy, which the simulator handles correctly.Diagnosed on the iOS simulator using commit 1's callback + commit 2's PSO forwarding — the chain of null-paths led directly to the FB-fetch PSO rejection.
SkiaSharp issue
Related to mono/SkiaSharp#4555
Required SkiaSharp PR
Requires mono/SkiaSharp#4586
Areas affected
include/c,src/c)DEPSChanges
C API
Behavior
SkDebugf).kTextureCopyinstead ofkFramebufferFetch. Slightly more work per dst read, but correct — was previously silently broken for any non-coefficient blend needing a dst read (Multiply, Screen, Overlay, etc.).Testing
Verified in the companion SkiaSharp PR — full
SkiaSharp.Tests.Devicesrun on iPhone 16 / iOS 26.1 simulator (arm64): 1219 total, 0 failed, 1138 succeeded, 81 skipped, GradientBlend cell rendering and matching its golden.Locally on Linux/Lavapipe (Vulkan; validates commit 1 wiring only — the Metal-specific commits 2/3 need Apple hardware): shader-error-handler smoke test passes, no double-free / no
EntryPointNotFoundExceptionon teardown.Checklist
skiasharpbranchChangesabove lists every added/changed C API export (or "None.")mono/SkiaSharpPR linked above (submodule bump at minimum; regenerates bindings + adds tests for C API changes)