Skip to content

Fix Metal stencil mismatch in mutable-image seed pass (#5103)#5106

Merged
shai-almog merged 1 commit into
masterfrom
fix-metal-seed-pass-stencil-5103
May 30, 2026
Merged

Fix Metal stencil mismatch in mutable-image seed pass (#5103)#5106
shai-almog merged 1 commit into
masterfrom
fix-metal-seed-pass-stencil-5103

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

  • Fixes App not starting correctly with Metal #5103. iOS apps built with Metal enabled crash to a white screen on the first form that paints a seeded mutable image. The Metal validation layer aborts in setRenderPipelineState: with For stencil attachment, the renderPipelineState pixelFormat must be MTLPixelFormatInvalid, as no texture is set.
  • Root cause: every pipeline in CN1MetalPipelineCache.m declares stencilAttachmentPixelFormat = MTLPixelFormatStencil8 (added with the polygon-clip stencil work in Clipping region not respected with non-90 degree rotations. #3921), so every render pass that binds one must attach a Stencil8 texture. The seed pass in CN1MetalEnsureMutableTexture (used to carry an existing UIImage's pixels — gausianBlurImage, FontImage thumbnails, etc. — into a freshly-allocated mutable target) was built with only a colour attachment but then bound the TexturedRGBA pipeline.
  • Fix: allocate a throwaway Stencil8 render-target texture for the seed pass, mirroring the pattern already used in CN1MetalBeginMutableImageDraw a few lines below. The seed draw never engages the stencil test, so loadAction=Clear / storeAction=DontCare is sufficient.

The sibling clearPass immediately above the seed pass does not need the same fix — it never calls setRenderPipelineState: (it just clears the colour attachment and ends the encoder), so the validation rule is not triggered.

Test plan

  • Build an iOS app (locally via Xcode) on a screen that paints a FontImage/gausianBlurImage-derived mutable image and confirm the app no longer crashes on the first form.
  • Run the polygon-clip-under-rotation screenshot test from Clipping region not respected with non-90 degree rotations. #3921 to confirm the main mutable draw path still renders correctly.
  • Verify no Metal validation warnings appear in the Xcode console during seeded mutable-image draws.

🤖 Generated with Claude Code

CN1MetalEnsureMutableTexture's seed pass (used when an existing
UIImage's pixels need to be carried into a freshly-allocated mutable
texture) built its render pass with only a colour attachment, then
bound the TexturedRGBA pipeline -- which declares
stencilAttachmentPixelFormat=Stencil8 since the polygon-clip work
in #3921. Metal's validation layer aborts setRenderPipelineState:
with "For stencil attachment, the renderPipelineState pixelFormat
must be MTLPixelFormatInvalid, as no texture is set", crashing any
app that lands on a screen whose first paint touches a seeded
mutable image (e.g. gausianBlurImage, FontImage thumbnails).

Allocate a throwaway Stencil8 texture for the pass mirroring the
pattern already used in CN1MetalBeginMutableImageDraw. The seed
draw never engages the stencil test, so loadAction=Clear /
storeAction=DontCare is enough.

The sibling clearPass above doesn't need the same treatment -- it
never calls setRenderPipelineState:, so the validation rule isn't
triggered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 223 seconds

Build and Run Timing

Metric Duration
Simulator Boot 83000 ms
Simulator Boot (Run) 1000 ms
App Install 15000 ms
App Launch 47000 ms
Test Execution 315000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 699.000 ms
Base64 CN1 encode 1428.000 ms
Base64 encode ratio (CN1/native) 2.043x (104.3% slower)
Base64 native decode 359.000 ms
Base64 CN1 decode 1006.000 ms
Base64 decode ratio (CN1/native) 2.802x (180.2% slower)
Base64 SIMD encode 432.000 ms
Base64 encode ratio (SIMD/native) 0.618x (38.2% faster)
Base64 encode ratio (SIMD/CN1) 0.303x (69.7% faster)
Base64 SIMD decode 386.000 ms
Base64 decode ratio (SIMD/native) 1.075x (7.5% slower)
Base64 decode ratio (SIMD/CN1) 0.384x (61.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 57.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.158x (84.2% faster)
Image applyMask (SIMD off) 126.000 ms
Image applyMask (SIMD on) 90.000 ms
Image applyMask ratio (SIMD on/off) 0.714x (28.6% faster)
Image modifyAlpha (SIMD off) 133.000 ms
Image modifyAlpha (SIMD on) 122.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.917x (8.3% faster)
Image modifyAlpha removeColor (SIMD off) 166.000 ms
Image modifyAlpha removeColor (SIMD on) 112.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.675x (32.5% faster)
Image PNG encode (SIMD off) 1415.000 ms
Image PNG encode (SIMD on) 1027.000 ms
Image PNG encode ratio (SIMD on/off) 0.726x (27.4% faster)
Image JPEG encode 613.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 133 seconds

Build and Run Timing

Metric Duration
Simulator Boot 73000 ms
Simulator Boot (Run) 1000 ms
App Install 17000 ms
App Launch 7000 ms
Test Execution 363000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1369.000 ms
Base64 CN1 encode 1846.000 ms
Base64 encode ratio (CN1/native) 1.348x (34.8% slower)
Base64 native decode 608.000 ms
Base64 CN1 decode 1508.000 ms
Base64 decode ratio (CN1/native) 2.480x (148.0% slower)
Base64 SIMD encode 962.000 ms
Base64 encode ratio (SIMD/native) 0.703x (29.7% faster)
Base64 encode ratio (SIMD/CN1) 0.521x (47.9% faster)
Base64 SIMD decode 775.000 ms
Base64 decode ratio (SIMD/native) 1.275x (27.5% slower)
Base64 decode ratio (SIMD/CN1) 0.514x (48.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 78.000 ms
Image createMask (SIMD on) 17.000 ms
Image createMask ratio (SIMD on/off) 0.218x (78.2% faster)
Image applyMask (SIMD off) 191.000 ms
Image applyMask (SIMD on) 101.000 ms
Image applyMask ratio (SIMD on/off) 0.529x (47.1% faster)
Image modifyAlpha (SIMD off) 325.000 ms
Image modifyAlpha (SIMD on) 105.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.323x (67.7% faster)
Image modifyAlpha removeColor (SIMD off) 328.000 ms
Image modifyAlpha removeColor (SIMD on) 126.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.384x (61.6% faster)
Image PNG encode (SIMD off) 1263.000 ms
Image PNG encode (SIMD on) 1198.000 ms
Image PNG encode ratio (SIMD on/off) 0.949x (5.1% faster)
Image JPEG encode 970.000 ms

@shai-almog shai-almog merged commit 9081093 into master May 30, 2026
17 checks passed
@shai-almog shai-almog deleted the fix-metal-seed-pass-stencil-5103 branch May 30, 2026 05:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App not starting correctly with Metal

1 participant