This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: cmp-gpu-swapchain-sync-fence-standard

Compose Multiplatform 1.7 GPU Swapchain Synchronization & Fence Lifecycle Guardrail

Enforces deterministic GPU swapchain synchronization fences across Metal (iOS) and Vulkan (Android) backends in Compose Multiplatform 1.7. Prevents render thread deadlocks, CAMetalDrawable exhaustion, and VK_ERROR_DEVICE_LOST during rapid view hierarchy churn, navigation transitions, and application lifecycle changes.

Prohibited Anti-Pattern: Asynchronous surface detachment without GPU fence draining or Skia context flushing during lifecycle transitions

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Compose Multiplatform 1.7 GPU Swapchain Synchronization & Fence Lifecycle Guardrail - Enforces deterministic GPU swapchain synchronization fences across Metal (iOS) and Vulkan (Android) backends in Compose Multiplatform 1.7. Prevents render thread deadlocks, CAMetalDrawable exhaustion, and VK_ERROR_DEVICE_LOST during rapid view hierarchy churn, navigation transitions, and application lifecycle changes.
globs: **/src/iosMain/**/*.kt, **/src/androidMain/**/*.kt, **/src/commonMain/**/ui/**/*.kt, **/platform/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/cmp-gpu-swapchain-sync-fence-standard"
---

# Compose Multiplatform 1.7 GPU Swapchain Synchronization & Fence Lifecycle Guardrail

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Asynchronous surface detachment without GPU fence draining or Skia context flushing during lifecycle transitions

## System Constraints
You are a Principal Mobile Graphics Architect enforcing strict GPU swapchain synchronization standards for Compose Multiplatform 1.7. Your mandate is to prevent CAMetalDrawable starvation, Vulkan out-of-date swapchain crashes, and render thread deadlocks across iOS Metal and Android Vulkan backends. Enforce deterministic teardown, explicit Skia DirectContext flushing with submit flags, and sync fence draining before any surface detachment or view disposal occurs.

## Strict Guidelines
- Engineers MUST ALWAYS flush the Skia DirectContext with syncCpu=true before destroying or detaching native swapchain surfaces (CAMetalLayer or Android SurfaceHolder).
- Engineers MUST NOT synchronously dispose ComposeUIViewController or ComposeView without first pausing render dispatch loops and awaiting in-flight GPU presentation fences.
- Code SHOULD decouple high-frequency state updates from frame pacing during active fragment/view transitions to avoid starving the swapchain queue.
- Services MUST orchestrate lifecycle events (onPause, viewWillDisappear) by immediately disabling new frame scheduling and draining command buffers before native surface release.
- Components NEVER bind native surface handles directly into unmanaged coroutine contexts without structured cancellation and explicit native resource finalization.

## Bad vs Good Implementations
### Metal Layer Teardown and Context Synchronization on iOS

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Disposing the Compose scene bridge immediately on viewWillDisappear without synchronizing with Metal command buffers causes CAMetalDrawable deadlock when Skia tries to present to an invalidated layer handle.
```kotlin
// ANTI-PATTERN: Disposing native layer immediately on viewWillDisappear
// Causes CAMetalLayer drawable deadlock or crashes during pending command buffer presentation
class CustomComposeViewController : UIViewController(null, null) {
    private var composeBridge: ComposeSceneBridge? = ComposeSceneBridge()

    override fun viewWillDisappear(animated: Boolean) {
        super.viewWillDisappear(animated)
        // Immediate teardown leaves command buffers in flight
        composeBridge?.dispose()
        composeBridge = null
    }
}
```

#### Production Standard (Correct)
> **Standard**: Halting rendering and forcing a synchronous GPU context flush (`flushAndSubmit(syncCpu = true)`) guarantees that all command buffers have completed presentation before detaching native swapchain layers.
```kotlin
// PRODUCTION STANDARD: Drain GPU queue and flush DirectContext before native detach
class CustomComposeViewController : UIViewController(null, null) {
    private var composeBridge: ComposeSceneBridge? = ComposeSceneBridge()

    override fun viewWillDisappear(animated: Boolean) {
        super.viewWillDisappear(animated)
        composeBridge?.let { bridge ->
            // 1. Stop dispatching new draw frames
            bridge.pauseRendering()
            // 2. Synchronize and flush GPU queues (Metal command buffers/Skia context)
            bridge.skiaContext?.flushAndSubmit(syncCpu = true)
            // 3. Deterministically release swapchain resources
            bridge.detachSwapchain()
        }
    }

    override fun viewDidDisappear(animated: Boolean) {
        super.viewDidDisappear(animated)
        composeBridge?.dispose()
        composeBridge = null
    }
}
```

### Android SurfaceView/Vulkan Swapchain Destruction Fence

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Android destroys the native window immediately upon return from surfaceDestroyed. If the Vulkan render thread is presenting or executing draw passes, this triggers VK_ERROR_DEVICE_LOST or driver crashes.
```kotlin
// ANTI-PATTERN: Detaching SurfaceHolder without waiting for Vulkan fence
class VulkanComposeView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // Surface is immediately destroyed by Android window manager,
        // causing VK_ERROR_DEVICE_LOST if GPU render pass is in flight
        renderer.stop()
    }
}
```

#### Production Standard (Correct)
> **Standard**: Enforcing a blocking fence drain with an explicit timeout ensures all pending Vulkan command buffers finish execution and release swapchain images before the native Surface is reclaimed.
```kotlin
// PRODUCTION STANDARD: Blocking fence drain during surfaceDestroyed
class VulkanComposeView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // 1. Signal render loop to cease enqueueing frames
        renderer.requestStop()
        // 2. Block until in-flight VkFence/Skia GPU submission completes
        renderer.awaitRenderFenceDrain(timeoutMs = 500)
        // 3. Invalidate Skia DirectContext target
        renderer.destroySurfaceTarget()
    }
}
```

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 1.7 GPU Swapchain Synchronization & Fence Lifecycle Guardrail

Compose Multiplatform 1.7 GPU Swapchain Synchronization & Fence Lifecycle Guardrail defines an industrial-grade behavioral standard for mobile engineering. Enforces deterministic GPU swapchain synchronization fences across Metal (iOS) and Vulkan (Android) backends in Compose Multiplatform 1.7. Prevents render thread deadlocks, CAMetalDrawable exhaustion, and VK_ERROR_DEVICE_LOST during rapid view hierarchy churn, navigation transitions, and application lifecycle changes. 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: Asynchronous surface detachment without GPU fence draining or Skia context flushing during lifecycle transitions 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 DriftAsynchronous surface detachment without GPU fence draining or Skia context flushing during lifecycle transitionsCritical
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 flush the Skia DirectContext with syncCpu=true before destroying or detaching native swapchain surfaces (CAMetalLayer or Android SurfaceHolder).

Engineers MUST ALWAYS flush the Skia DirectContext with syncCpu=true before destroying or detaching native swapchain surfaces (CAMetalLayer or Android SurfaceHolder).

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 NOT synchronously dispose ComposeUIViewController or ComposeView without first pausing render dispatch loops and awaiting in-flight GPU presentation fences.

Engineers MUST NOT synchronously dispose ComposeUIViewController or ComposeView without first pausing render dispatch loops and awaiting in-flight GPU presentation fences.

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

Code SHOULD decouple high-frequency state updates from frame pacing during active fragment/view transitions to avoid starving the swapchain queue.

Code SHOULD decouple high-frequency state updates from frame pacing during active fragment/view transitions to avoid starving the swapchain queue.

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

Services MUST orchestrate lifecycle events (onPause, viewWillDisappear) by immediately disabling new frame scheduling and draining command buffers before native surface release.

Services MUST orchestrate lifecycle events (onPause, viewWillDisappear) by immediately disabling new frame scheduling and draining command buffers before native surface release.

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 bind native surface handles directly into unmanaged coroutine contexts without structured cancellation and explicit native resource finalization.

Components NEVER bind native surface handles directly into unmanaged coroutine contexts without structured cancellation and explicit native resource finalization.

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 1.7 GPU Swapchain Synchronization & Fence Lifecycle Guardrail critical for AI coding assistants?

Enforces deterministic GPU swapchain synchronization fences across Metal (iOS) and Vulkan (Android) backends in Compose Multiplatform 1.7. Prevents render thread deadlocks, CAMetalDrawable exhaustion, and VK_ERROR_DEVICE_LOST during rapid view hierarchy churn, navigation transitions, and application lifecycle changes. 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 (Asynchronous surface detachment without GPU fence draining or Skia context flushing during lifecycle transitions) 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