Skip to main content

⚡ Performance

The data below is based on the Demo test image (assets/test/origin.png 1080×1920, 6 semantic regions), default pipelineConfig, and onWatch durationMs (measured from init). These are empirical ranges, not strict benchmarks; actual device results vary with CPU, storage, and RN version.

Measured Reference (Dev Env + PNG Pre-warming)

The Demo calls prewarmPngBgrCacheAsync([origin, mask]) before mounting the canvas, so PNG decoding hits the memory cache. Typical logs:

StagewatchStateApprox. DurationNotes
Mask alignedmask_aligned~160msMask scaled to segmentation working resolution
Regions readyregions_ready / mask_sampled~320msLayout scan + baseboard + pickMap
Interactive**interactive**~320–450msCan tap regions, select colors, Shader paint
Outlines readymask_paths_ready~430–550ms~100ms after interactive; carousel outlines can display

interactive does not wait for outline paths; mask_paths_ready only affects the initial carousel and optional UI hints.

Same-image sub-step magnitudes (__DEV__ logs, default pipeline):

Sub-stepApprox. DurationWorking Resolution
OpenCV LAB high/low freq~10–40ms270×480
High/low freq Skia textures~20–30mssame
Layout scan + baseboard + pick table~90–120ms405×720 (1080p → longSide 720)
Full contour paths (async, non-blocking)~80–150ms270×480

Resolution vs pipelineConfig

Compute-intensive steps are capped by maximum long side limits and do not scale linearly with 4K/8K origin images. Full PNG decoding still scales linearly with pixel count.

StepConfig Key1080×1920 Actual SizeScales with Origin Pixels
PNG decode1080×1920 × 2 imagesYes
Mask seg / pickMapmaxImageLongSide: 720~405×720No (fixed when long side >720)
Shader high/low freqpaintFreqMaxLongSide: 480~270×480No
Working area Skia originsame as maxImageLongSide~405×720No
Dashed outlinesmaskPathMaxLongSide: 480~270×480No (does not block interactive)

interactive Estimation (Default Pipeline)

Origin SpecRelative to 1080p PixelsWith PNG Pre-warmCold Start (no pre-warm)
1080×1920320–450ms450–700ms
1440×2560 (2K)~1.8×400–550ms600–900ms
3840×2160 (4K)~4×500–750ms800–1200ms
7680×4320 (8K)~16×0.8–1.5s1.5–3s+

<300ms interactive: achievable on 1080p + pre-warm + default pipeline + high-end devices, but optimistic — do not treat as an all-device SLA.

Device Tier (1080p, Default Pipeline)

Relative to the ~320ms dev-environment baseline:

TierRelative MultiplierPre-warm interactiveCold Start
Flagship iOS / new flagship Android0.8–1.2×300–450ms500–800ms
Mid-range Android1.5–2.5×500–800ms700ms–1.2s
Low-end Android (4GB, old SoC)2.5–4×800ms–1.3s1–2s+

Android overhead primarily comes from: JS ↔ OpenCV bridge, memory bandwidth/GC, Skia texture upload.

Impact of Raising maxImageLongSide

Setting pipelineConfig.maxImageLongSide to 1280 (above the default 720) results in a segmentation working area of ~720×1280, roughly the pixel count of the 720 tier:

ScenarioDefault 720Raised to 1280
1080p interactive (mid-range)~320–800ms500ms–1s+
Segmentation / pickMap duration~90–120ms~250–350ms

Higher precision for longer init time. To stay <500ms interactive, keep the default 720; reduce to 640 if needed.

Optimization Tips

  1. 🚀 PNG pre-warming (recommended): Call prewarmPngBgrCacheAsync after download/extraction and before navigating to the paint screen. Typically saves 100–250ms (greatest benefit on low-end devices).
import { prewarmPngBgrCacheAsync } from 'react-native-mask-segment-canvas';

await prewarmPngBgrCacheAsync([originPath, maskPath]);
// Then mount MaskSegmentCanvas
  1. ⏱️ Loading timing: Dismiss the blocking loader at interactive; optionally listen for mask_paths_ready for "outlines preparing" hints.
  2. 🖼️ Large images / low-end devices: Keep default maxImageLongSide: 720; optionally lower paintFreqMaxLongSide to 360.
  3. 📷 4K assets: Downsample on the host side before passing in, or accept ~0.8–1.5s interactive (with pre-warm).
  4. 🔍 Observability: Watch Metro logs for [MaskSegment], [⏱ ...] prefixes and onWatch durationMs.