This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: cmp-skiko-render-target-sync-guardrail

Compose Multiplatform Skiko Render Target Sync & GPU Context Invalidation

Enforces strict synchronization between platform surface lifecycle events and Skiko GPU render loops across Desktop (JVM) and iOS (Metal) targets. Prevents native driver deadlocks, memory corruption, and EXC_BAD_ACCESS crashes caused by resizing or destroying backing surfaces while Skia DirectContext operations or CAMetalDrawables remain in flight.

Prohibited Anti-Pattern: Unsynchronized Platform Surface Destruction and Asynchronous GPU Render Loop Dispatch

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Compose Multiplatform Skiko Render Target Sync & GPU Context Invalidation - Enforces strict synchronization between platform surface lifecycle events and Skiko GPU render loops across Desktop (JVM) and iOS (Metal) targets. Prevents native driver deadlocks, memory corruption, and EXC_BAD_ACCESS crashes caused by resizing or destroying backing surfaces while Skia DirectContext operations or CAMetalDrawables remain in flight.
globs: **/*View*.kt, **/*Window*.kt, **/*Layer*.kt, **/*Redrawer*.kt, iosApp/**/*.swift
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/cmp-skiko-render-target-sync-guardrail"
---

# Compose Multiplatform Skiko Render Target Sync & GPU Context Invalidation

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Unsynchronized Platform Surface Destruction and Asynchronous GPU Render Loop Dispatch

## System Constraints
You are a Principal Software Architect enforcing Compose Multiplatform and Skiko GPU lifecycle invariants. You must prevent race conditions between UIKit/AWT window resize/destruction and the Skiko render loop. Mandate deterministic GPU context abandonment, strict render locks, and non-blocking surface disposal sequences.

## Strict Guidelines
- Engineers MUST ALWAYS acquire the native render lock (e.g., SkiaLayer.renderLock or synchronized redrawer token) prior to mutating backing surface dimensions or invalidating render buffers.
- Engineers MUST ALWAYS abandon or flush the Skia DirectContext (context.abandonContext() / context.flushAndSubmit()) on the designated GPU rendering thread before releasing the native window handle, NSView, or CAMetalLayer.
- Engineers MUST NOT synchronously invoke blocking platform destruction routines from inside an active Skiko redraw callback (onRender/draw loop).
- Code SHOULD isolate window resize debounce logic from native Metal/DirectX/Vulkan surface recreation to prevent continuous driver reallocation churn under rapid window resizing.
- Components NEVER retain stale Skia Surface or Canvas references across frame boundaries; all render targets must be queried and bound on each draw pass under active lifecycle validity checks.

## Bad vs Good Implementations
### Skiko Surface Disposal & Dimension Resync

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Mutating dimensions or detaching SkiaLayer without acquiring the renderLock or checking renderer thread state leads to concurrent execution of native draw passes on unbacked or partially destroyed CAMetalDrawable / SwapChain buffers, precipitating EXC_BAD_ACCESS or GPU kernel deadlocks.
```kotlin
class CustomSkiaHostView(private val skiaLayer: SkiaLayer) {
    // ANTI-PATTERN: Direct asynchronous surface resize and disposal without render synchronization
    fun onBoundsChanged(width: Int, height: Int) {
        // Race condition: Render thread is actively reading context while width/height change
        skiaLayer.width = width
        skiaLayer.height = height
        skiaLayer.needRedraw()
    }

    fun dispose() {
        // Fatal: Destroys the layer while the redraw loop might be inside GrDirectContext draw calls
        skiaLayer.detach()
    }
}
```

#### Production Standard (Correct)
> **Standard**: Acquiring skiaLayer.renderLock guarantees mutual exclusion between platform-triggered lifecycle changes (such as resize or screen transition) and the underlying Skiko GPU rendering pass, ensuring memory safety across concurrent thread architectures.
```kotlin
class CustomSkiaHostView(private val skiaLayer: SkiaLayer) {
    // PRODUCTION FIX: Coordinated synchronization with Skia render lock and controlled context lifecycle
    fun onBoundsChanged(newWidth: Int, newHeight: Int) {
        if (newWidth <= 0 || newHeight <= 0) return

        // Acquire renderLock to guarantee no frame drawing happens mid-mutation
        synchronized(skiaLayer.renderLock) {
            if (skiaLayer.isDisposed) return
            skiaLayer.width = newWidth
            skiaLayer.height = newHeight
            // Surface resize will be processed deterministically on next frame cycle
            skiaLayer.needRedraw()
        }
    }

    fun dispose() {
        synchronized(skiaLayer.renderLock) {
            if (skiaLayer.isDisposed) return
            // Flush pending GPU commands and cleanly detach while locked
            skiaLayer.detach()
            skiaLayer.dispose()
        }
    }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Compose Multiplatform Skiko Render Target Sync & GPU Context Invalidation

Compose Multiplatform Skiko Render Target Sync & GPU Context Invalidation defines an industrial-grade behavioral standard for mobile engineering. Enforces strict synchronization between platform surface lifecycle events and Skiko GPU render loops across Desktop (JVM) and iOS (Metal) targets. Prevents native driver deadlocks, memory corruption, and EXC_BAD_ACCESS crashes caused by resizing or destroying backing surfaces while Skia DirectContext operations or CAMetalDrawables remain in flight. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Unsynchronized Platform Surface Destruction and Asynchronous GPU Render Loop Dispatch Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftUnsynchronized Platform Surface Destruction and Asynchronous GPU Render Loop DispatchCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS acquire the native render lock (e.g., SkiaLayer.renderLock or synchronized redrawer token) prior to mutating backing surface dimensions or invalidating render buffers.

Engineers MUST ALWAYS acquire the native render lock (e.g., SkiaLayer.renderLock or synchronized redrawer token) prior to mutating backing surface dimensions or invalidating render buffers.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST ALWAYS abandon or flush the Skia DirectContext (context.abandonContext() / context.flushAndSubmit()) on the designated GPU rendering thread before releasing the native window handle, NSView, or CAMetalLayer.

Engineers MUST ALWAYS abandon or flush the Skia DirectContext (context.abandonContext() / context.flushAndSubmit()) on the designated GPU rendering thread before releasing the native window handle, NSView, or CAMetalLayer.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST NOT synchronously invoke blocking platform destruction routines from inside an active Skiko redraw callback (onRender/draw loop).

Engineers MUST NOT synchronously invoke blocking platform destruction routines from inside an active Skiko redraw callback (onRender/draw loop).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Code SHOULD isolate window resize debounce logic from native Metal/DirectX/Vulkan surface recreation to prevent continuous driver reallocation churn under rapid window resizing.

Code SHOULD isolate window resize debounce logic from native Metal/DirectX/Vulkan surface recreation to prevent continuous driver reallocation churn under rapid window resizing.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER retain stale Skia Surface or Canvas references across frame boundaries

Components NEVER retain stale Skia Surface or Canvas references across frame boundaries; all render targets must be queried and bound on each draw pass under active lifecycle validity checks.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Compose Multiplatform Skiko Render Target Sync & GPU Context Invalidation critical for AI coding assistants?

Enforces strict synchronization between platform surface lifecycle events and Skiko GPU render loops across Desktop (JVM) and iOS (Metal) targets. Prevents native driver deadlocks, memory corruption, and EXC_BAD_ACCESS crashes caused by resizing or destroying backing surfaces while Skia DirectContext operations or CAMetalDrawables remain in flight. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Unsynchronized Platform Surface Destruction and Asynchronous GPU Render Loop Dispatch) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

Compose