diff --git a/CHANGELOG.md b/CHANGELOG.md index bb3116b..8f9c799 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.19.6] - 2026-03-05 + +### Fixed + +- **Metal: MSAA resolve store action** — when a render pass has a resolve target + (MSAA → single-sample), Metal requires `MTLStoreActionMultisampleResolve` or + `MTLStoreActionStoreAndMultisampleResolve`. We were setting `MTLStoreActionStore`, + causing Metal to silently skip the resolve. The surface texture stayed + uninitialized (purple/magenta screen). + ([ui#23](https://github.com/gogpu/ui/issues/23)) + ## [0.19.5] - 2026-03-05 ### Fixed diff --git a/hal/metal/encoder.go b/hal/metal/encoder.go index 34785db..75bd6b8 100644 --- a/hal/metal/encoder.go +++ b/hal/metal/encoder.go @@ -284,12 +284,21 @@ func (e *CommandEncoder) BeginRenderPass(desc *hal.RenderPassDescriptor) hal.Ren clearColor := MTLClearColor{Red: ca.ClearValue.R, Green: ca.ClearValue.G, Blue: ca.ClearValue.B, Alpha: ca.ClearValue.A} msgSendClearColor(attachment, Sel("setClearColor:"), clearColor) } - _ = MsgSend(attachment, Sel("setStoreAction:"), uintptr(storeOpToMTL(ca.StoreOp))) + storeAction := storeOpToMTL(ca.StoreOp) if ca.ResolveTarget != nil { if rtv, ok := ca.ResolveTarget.(*TextureView); ok && rtv != nil { _ = MsgSend(attachment, Sel("setResolveTexture:"), uintptr(rtv.raw)) + // Metal requires MultisampleResolve store action when a resolve + // texture is set. Without this, Metal silently skips the MSAA + // resolve and the surface stays uninitialized (purple screen). + if storeAction == MTLStoreActionStore { + storeAction = MTLStoreActionStoreAndMultisampleResolve + } else { + storeAction = MTLStoreActionMultisampleResolve + } } } + _ = MsgSend(attachment, Sel("setStoreAction:"), uintptr(storeAction)) } if desc.DepthStencilAttachment != nil { dsa := desc.DepthStencilAttachment