Fix dark/faded Metal rendering: use premultiplied alpha blend factors#15
Fix dark/faded Metal rendering: use premultiplied alpha blend factors#15praeclarum merged 3 commits intomasterfrom
Conversation
The fragment shader outputs premultiplied alpha (rgb*alpha, alpha) but the blend state was using SourceAlpha, causing double-alpha-multiplication. Changed source blend factors from SourceAlpha to One for correct premultiplied alpha compositing (Porter-Duff Source Over). Also fixed acceptance test texture format mismatch: was using RGBA8Unorm while the pipeline expects BGRA8Unorm (DefaultPixelFormat). Agent-Logs-Url: https://github.com/praeclarum/CrossGraphics/sessions/7b870bed-9976-46fb-86e2-060fa9acf87a Co-authored-by: praeclarum <323548+praeclarum@users.noreply.github.com>
| { | ||
| var renderPassDescriptor = new Metal.MTLRenderPassDescriptor (); | ||
| var tdesc = Metal.MTLTextureDescriptor.CreateTexture2DDescriptor (MTLPixelFormat.RGBA8Unorm, (UIntPtr)width, | ||
| var tdesc = Metal.MTLTextureDescriptor.CreateTexture2DDescriptor (CrossGraphics.Metal.MetalGraphics.DefaultPixelFormat, (UIntPtr)width, |
There was a problem hiding this comment.
Since SaveDrawing is blitting the texture to a CGBitmapContext with a fixed pixel format it seems dangerous to just use DefaultPixelFormat? Or am I misunderstanding DefaultPixelFormat? I'm not necessarily asking for a change but I do need a n explanation. DefaultPixelFormat is seeming like a bad idea haha.
There was a problem hiding this comment.
You're right — the original PremultipliedLast in SaveDrawing expects RGBA byte order, so blindly using DefaultPixelFormat (BGRA) for the texture would swap R and B during readback.
Fixed in 9c1bbac: SaveDrawing now selects CGBitmapFlags based on DefaultPixelFormat — uses PremultipliedFirst | ByteOrder32Little for BGRA, or PremultipliedLast for RGBA. This keeps the texture format in sync with both the pipeline and the bitmap readback.
The texture format change itself is still needed because Metal requires the render target format to match the pipeline's color attachment format — the original RGBA8Unorm mismatched the pipeline's BGRA8Unorm.
Update CGBitmapContext flags in SaveDrawing to handle BGRA byte order correctly: use PremultipliedFirst | ByteOrder32Little for BGRA textures, or PremultipliedLast for RGBA textures. Agent-Logs-Url: https://github.com/praeclarum/CrossGraphics/sessions/29dd2aa3-9992-4e38-a81d-7015cac6a679 Co-authored-by: praeclarum <323548+praeclarum@users.noreply.github.com>
The fragment shader outputs premultiplied alpha (
rgb * alpha, alpha) but the blend state was usingSourceAlpha, causing double-multiplication by alpha and darkened output.MetalGraphics.cs): ChangedSourceRgbBlendFactorandSourceAlphaBlendFactorfromSourceAlphatoOne— standard premultiplied alpha over compositing.AcceptanceTests.cs): Test was creating render targets withRGBA8Unormwhile the pipeline expectsBGRA8Unorm. Now usesMetalGraphics.DefaultPixelFormat.