Run smoke-render on Linux and fix OpenGL ES rendering#144
Merged
Conversation
Hosted macOS runners have no display, so the integration test's first frame never pumps (confirmed: even a bare pumpWidget hangs). Linux has Xvfb, which gives the GTK window a virtual display so frames flow, and Flutter GPU is enabled cross-platform via the --enable-flutter-gpu engine switch, so flutter_scene's native path can run on Linux under Mesa software GL (llvmpipe). Replace the unfixable hosted-macOS job with a linux job (xvfb-run + llvmpipe + --enable-impeller --enable-flutter-gpu, Argos build-name linux), and add the linux/ desktop scaffolding. Revert the macOS hang diagnostics and the window-activation attempt; macos/ scaffolding stays for local validation.
The standard fragment shader held its 16-tap Poisson disk in a const array. impellerc/SPIRV-Cross emits a const array as a GLSL array constructor (`vec2[](...)`) in its `#version 100` GLES output, which is invalid ES 1.00, so the shader fails to compile on conformant ES drivers (Mesa/llvmpipe under headless Linux CI). Lenient drivers accept it, which is why it went unnoticed. Even an element-wise-filled array is folded back into a const array by the SPIR-V optimizer, so the only robust fix is to remove the array entirely. Unroll the PCF loop with the kernel as inline literals (a ShadowTap helper plus a local macro), leaving no array for the optimizer to materialize. Verified conformant ES 1.00 with glslangValidator and byte-identical output on macOS/Metal. This is a temporary workaround; the real fix belongs upstream in impellerc (emit valid ES 1.00, or target ES 3.00 for the bundle's GLES stage). See the TODO in flutter_scene_standard.frag.
On Linux CI (llvmpipe software GL) the low-roughness metallic scene renders correctly but with only 43 distinct colors, below the >100 gate. That metric is the weakest sanity check (noisy, edge-AA-dominated) and coverage + foreground luma are the real blank detectors, so lower the threshold to 24: still catches a flat/uniform fill, tolerates software output.
Temporary: lets us pull the actual rendered PNGs to verify software-Mesa fidelity (the metallic scene in particular) before landing.
flutter_scene (like Impeller's Metal/Vulkan backends) assumes render-to- texture content is stored top-down. Impeller's OpenGL ES backend stores it bottom-up, and the upstream fix that makes GLES match (flutter/flutter#186556) is not yet in the engines we build against, so flutter_scene rendered upside down on native GLES (e.g. Linux desktop, headless CI). Absorb the difference in flutter_scene as a temporary workaround, gated on a GL-backend proxy (no offscreen-MSAA support; Flutter GPU exposes no backend query). New src/render/y_flip.dart: - negates gl_Position.y in every offscreen pass (matrix premultiply for the matrix-based scene/shadow passes; a FlipInfo uniform for the full-screen tonemap/prefilter passes), storing targets top-down; - inverts cull winding to compensate (the Y negation reverses screen winding); - so the existing render-target sampling flips become the top-down value on every backend (tonemap flip_y 0.0, render_target_flip_y 1.0). Gated off for Metal/Vulkan and the WebGL2 shim (which does its own flip), so those paths are byte-identical (verified on macOS/Metal and web). TODO: remove once the GLES top-down fix lands upstream; see the note in y_flip.dart.
…proxy The offscreen-MSAA proxy is true on the Linux runner (llvmpipe supports GLES3 MSAA), so the Y-flip stayed gated off. Dump capabilities to find a signal that distinguishes the GLES backend from Metal/Vulkan.
…pabilities The offscreen-MSAA proxy is unreliable: it is true on GLES3/llvmpipe (the Linux CI runner), and no Flutter GPU capability cleanly separates GLES from Vulkan, so a format-based guess risks flipping Vulkan. Instead, measure the orientation directly: on the first Scene.render, render a known top/bottom pattern to an offscreen texture and read it back (asImage + toByteData). Top row red means top-down (Metal/Vulkan/web shim); otherwise bottom-up (OpenGL ES) and backendFlipsRenderTargetY becomes true. The probe runs during a frame (the GLES context is only up after the first frame) and reads back asynchronously, so the first frame uses the default (no flip) and later frames use the measured value. Verified byte-identical on macOS/Metal and web (probe measures top-down, flip stays off).
The vertex-stage flip stores the scene top-down, but asImage presents the swapchain as-is on native (unlike the web shim's present-time blit flip), so the result landed upside down. Flip the drawImageRect blit vertically when backendFlipsRenderTargetY to match.
Remove the backendFlipsRenderTargetY debug print and the per-run frame artifact upload now that the Y-flip workaround is validated (Linux renders right-side up, matching macOS; web and Metal unchanged).
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.
Adds a Linux job to the smoke-render check and fixes two flutter_scene rendering bugs it surfaced on OpenGL ES. Replaces the hosted-macOS job, which can't produce frames on CI runners.
flutter_scene:
constarray, which compiles to a construct some OpenGL ES drivers reject; it is now unrolled.smoke-render check:
Verified: byte-identical output on the unaffected backends; Linux renders upright with both jobs green.