Skip to content

Fix graphics screenshot tests: Scale, AffineScale, TransformPerspective, TransformCamera#4875

Open
shai-almog wants to merge 1 commit intomasterfrom
fix-graphics-screenshot-tests
Open

Fix graphics screenshot tests: Scale, AffineScale, TransformPerspective, TransformCamera#4875
shai-almog wants to merge 1 commit intomasterfrom
fix-graphics-screenshot-tests

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

Four graphics screenshot tests in scripts/hellocodenameone/common/.../tests/graphics/ produced empty cells in the iOS and Android screenshot pipelines because each test had a structural defect.

  • Scale.java + AffineScale.java: xScale = 0.01 * bounds.height was applied to the X axis (and yScale from width to Y) — axes swapped, so the 100×100 logical fill was clipped to a thin strip on portrait screens. Also relied on g.translate + g.scale separately, which doesn't compose because g.translate(int, int) is a no-op on JavaSE and the iOS form-graphics path doesn't carry the translate into fillLinearGradient.
  • TransformPerspective.java + TransformCamera.java: passed the raw clip-space output of makePerspective / makeCamera straight to fillRect, so the rect projected to a sub-pixel region around the screen origin and rendered nothing visible. Also used the static Transform.isPerspectiveSupported() (the global check) instead of the per-graphics g.isPerspectiveTransformSupported() — on iOS Metal, mutable-image graphics return false for the per-graphics check, so the bottom 2 cells of each 2×2 grid silently no-oped.

Fixes

All four tests now:

  • Paint a deterministic white background + black border so the cell is visible regardless of platform support.
  • Use a single composed Transform (translate × scale) applied via g.setTransform(t) instead of g.translate + g.scale.
  • Use cell-relative coordinates so fills always land inside the cell on every screen size.
  • For perspective/camera, draw a deterministic centred marker first so the screenshot is comparable even when the perspective branch is unsupported, then exercise the perspective API on top with a viewport-corrected matrix following the FlipTransition.paint() pattern.
  • Use g.isPerspectiveTransformSupported() and emit a clear "No perspective" / "No camera" label when the per-graphics target doesn't support perspective.

Verified end-to-end on the JavaSE simulator — all four tests now emit valid 65–72 KB PNGs with visible content (previously the cells were mostly empty).

Test plan

  • iOS Metal pipeline runs the suite and the 4 tests emit valid PNGs with visible content
  • Android pipeline runs the suite and the 4 tests emit valid PNGs with visible content
  • Goldens regenerated for graphics-scale, graphics-affine-scale, graphics-transform-perspective, graphics-transform-camera on each pipeline (the new pixel output differs from the previously broken goldens)

🤖 Generated with Claude Code

…tive/camera

The Scale, AffineScale, TransformPerspective, and TransformCamera grid
tests produced empty cells in the screenshot pipelines because each
test had a structural defect:

- Scale + AffineScale crossed the axes in the scale formula
  (xScale=0.01*height, yScale=0.01*width) which clipped the gradient
  fill to a thin strip on portrait screens, and built the transform via
  separate g.translate + g.scale calls -- but g.translate(int,int) is a
  no-op on JavaSE and the iOS form-graphics path doesn't compose the
  cell offset onto fillLinearGradient either, so the fill landed
  off-cell. Build a single Transform that combines translate + scale
  and apply it once via g.setTransform.

- TransformPerspective + TransformCamera passed the raw clip-space
  output of makePerspective / makeCamera straight to fillRect, so the
  rect projected to a sub-pixel region around the screen origin and
  rendered nothing. They also used the static
  Transform.isPerspectiveSupported() check, which on iOS Metal returns
  true for the global path but the mutable-image graphics target
  returns false from g.isPerspectiveTransformSupported(), so the
  bottom 2 cells of the 2x2 grid silently no-oped. Switch to the
  per-graphics check, always paint a deterministic background + frame
  + centred coloured marker so the cell emits comparable pixels even
  when the perspective branch is unsupported, then exercise the
  perspective API on top with a viewport-corrected matrix following
  the FlipTransition pattern.

Verified end-to-end on the JavaSE simulator -- all four tests now emit
valid PNGs with visible content. Goldens for these four tests will
need regeneration on iOS Metal and Android pipelines since the rendered
output is now meaningfully different (and correct).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 7, 2026

iOS Metal screenshot updates

Compared 86 screenshots: 82 matched, 4 updated.

  • graphics-affine-scale — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-affine-scale
    Preview info: JPEG preview quality 20; JPEG preview quality 20; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-affine-scale.png in workflow artifacts.

  • graphics-scale — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-scale
    Preview info: JPEG preview quality 20; JPEG preview quality 20; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-scale.png in workflow artifacts.

  • graphics-transform-camera — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-camera
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-camera.png in workflow artifacts.

  • graphics-transform-perspective — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-perspective
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-perspective.png in workflow artifacts.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 85000 ms
Simulator Boot (Run) 2000 ms
App Install 17000 ms
App Launch 8000 ms
Test Execution 256000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1270.000 ms
Base64 CN1 encode 2313.000 ms
Base64 encode ratio (CN1/native) 1.821x (82.1% slower)
Base64 native decode 1028.000 ms
Base64 CN1 decode 1723.000 ms
Base64 decode ratio (CN1/native) 1.676x (67.6% slower)
Base64 SIMD encode 818.000 ms
Base64 encode ratio (SIMD/native) 0.644x (35.6% faster)
Base64 encode ratio (SIMD/CN1) 0.354x (64.6% faster)
Base64 SIMD decode 425.000 ms
Base64 decode ratio (SIMD/native) 0.413x (58.7% faster)
Base64 decode ratio (SIMD/CN1) 0.247x (75.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 66.000 ms
Image createMask (SIMD on) 11.000 ms
Image createMask ratio (SIMD on/off) 0.167x (83.3% faster)
Image applyMask (SIMD off) 143.000 ms
Image applyMask (SIMD on) 97.000 ms
Image applyMask ratio (SIMD on/off) 0.678x (32.2% faster)
Image modifyAlpha (SIMD off) 150.000 ms
Image modifyAlpha (SIMD on) 124.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.827x (17.3% faster)
Image modifyAlpha removeColor (SIMD off) 305.000 ms
Image modifyAlpha removeColor (SIMD on) 247.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.810x (19.0% faster)
Image PNG encode (SIMD off) 1605.000 ms
Image PNG encode (SIMD on) 1511.000 ms
Image PNG encode ratio (SIMD on/off) 0.941x (5.9% faster)
Image JPEG encode 1035.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 7, 2026

iOS screenshot updates

Compared 90 screenshots: 86 matched, 4 updated.

  • graphics-affine-scale — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-affine-scale
    Preview info: JPEG preview quality 30; JPEG preview quality 30; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-affine-scale.png in workflow artifacts.

  • graphics-scale — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-scale
    Preview info: JPEG preview quality 40; JPEG preview quality 40; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-scale.png in workflow artifacts.

  • graphics-transform-camera — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-camera
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-camera.png in workflow artifacts.

  • graphics-transform-perspective — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-perspective
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-perspective.png in workflow artifacts.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 115000 ms
Simulator Boot (Run) 1000 ms
App Install 59000 ms
App Launch 13000 ms
Test Execution 303000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 4346.000 ms
Base64 CN1 encode 2358.000 ms
Base64 encode ratio (CN1/native) 0.543x (45.7% faster)
Base64 native decode 1346.000 ms
Base64 CN1 decode 1580.000 ms
Base64 decode ratio (CN1/native) 1.174x (17.4% slower)
Base64 SIMD encode 591.000 ms
Base64 encode ratio (SIMD/native) 0.136x (86.4% faster)
Base64 encode ratio (SIMD/CN1) 0.251x (74.9% faster)
Base64 SIMD decode 672.000 ms
Base64 decode ratio (SIMD/native) 0.499x (50.1% faster)
Base64 decode ratio (SIMD/CN1) 0.425x (57.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 87.000 ms
Image createMask (SIMD on) 12.000 ms
Image createMask ratio (SIMD on/off) 0.138x (86.2% faster)
Image applyMask (SIMD off) 242.000 ms
Image applyMask (SIMD on) 188.000 ms
Image applyMask ratio (SIMD on/off) 0.777x (22.3% faster)
Image modifyAlpha (SIMD off) 211.000 ms
Image modifyAlpha (SIMD on) 126.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.597x (40.3% faster)
Image modifyAlpha removeColor (SIMD off) 298.000 ms
Image modifyAlpha removeColor (SIMD on) 204.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.685x (31.5% faster)
Image PNG encode (SIMD off) 1767.000 ms
Image PNG encode (SIMD on) 1286.000 ms
Image PNG encode ratio (SIMD on/off) 0.728x (27.2% faster)
Image JPEG encode 827.000 ms

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.

1 participant