Skip to content

[flame_tiled] skwasm renderer crashes ("memory access out of bounds") on tilemaps with >~2000 batched tiles — upstream Flutter bug #3913

@Ortes

Description

@Ortes

Summary

Rendering a moderately large tilemap (≥ ~2000 visible/batched tiles in one layer) on Flutter web with the skwasm renderer crashes the engine with RuntimeError: memory access out of bounds.

Root cause is upstream in Flutter, not in flame_tiled itself, but reporting here so anyone hitting the crash finds the workaround quickly.

Steps to reproduce

  1. flutter run -d chrome --wasm with _flutter.loader.load({config: {renderer: "skwasm"}}) in web/flutter_bootstrap.js.
  2. Load any TiledComponent whose visible tile-layer batch exceeds ~2000 tiles. A 64×64 ground layer triggers it.

Trace

RuntimeError: memory access out of bounds
  at $malloc                       (skwasm.wasm)
  at $paint_create                 (skwasm.wasm)
  at $SkwasmPaint.toRawPaint       (paint.dart:16)
  at $SkwasmCanvas.drawAtlas       (canvas.dart, inside withStackScope)
  at $SpriteBatch.render           (flame sprite_batch.dart:520)
  at $FlameTileLayer.render        (tile_layer.dart:147)
  at $RenderableTiledMap.render    (renderable_tile_map.dart:487)
  at $TiledComponent.render        (tiled_component.dart:83)

FlameTileLayer.render calls SpriteBatch.render which calls Canvas.drawAtlas once per layer with one entry per tile. Skwasm's drawAtlas writes the per-entry arrays into the wasm stack (_emscripten_stack_alloc, default 64 KiB), and ~2000+ entries overflow the stack into the heap; the next malloc traps.

Upstream

Once that fix lands, no flame_tiled change is needed.

Workaround until upstream fix is released

final tiled = await TiledComponent.load(
  'wedding_pilgrimage.tmx',
  Vector2.all(32),
  useAtlas: false, // bypasses SpriteBatch.drawAtlas → uses drawImageRect per tile
);

useAtlas: false switches FlameTileLayer to a per-tile Canvas.drawImageRect path instead of SpriteBatch.drawAtlas. It boots fine, but expect ~10× lower FPS in debug and a measurable drop in release because the GPU batching is gone (in our case ~100 FPS skwasm + useAtlas: false vs ~120 FPS canvaskit + useAtlas: true). Acceptable as a stop-gap; not as a permanent solution.

The other workaround is to switch the web bootstrap to renderer: "canvaskit", which doesn't share this code path.

Suggested README/docs note

A short note in the flame_tiled README under "Web / known issues" pointing at flutter/flutter#185995 and the useAtlas: false escape hatch would save future users a lot of time — the crash signature points at paint_create rather than drawAtlas, so it's easy to misdiagnose. Happy to PR the docs change if useful.

Versions

  • flame: ^1.37.0
  • flame_tiled: ^3.1.1
  • Flutter 3.44.0-0.3.pre, Dart 3.12.0-327.4.beta, engine 285ae5207
  • macOS 15 / arm64, Chrome stable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions