This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-skiko-metal-vulkan-frame-pacing-mutex-standard

KMP Skiko Metal/Vulkan Frame Pacing and Mutex Synchronization Standard

Enforces strict isolation between native frame-pacing mechanisms (CADisplayLink/Choreographer) and Skiko rendering mutexes in Compose Multiplatform. Prevents main-thread priority inversion and deadlocks by prohibiting synchronous waits on GPU drawables or command buffer completion inside lock-holding native vsync callbacks.

Prohibited Anti-Pattern: Synchronously blocking CADisplayLink or Main RunLoop on Skiko Render Mutexes and GPU Surface Acquisition

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP Skiko Metal/Vulkan Frame Pacing and Mutex Synchronization Standard - Enforces strict isolation between native frame-pacing mechanisms (CADisplayLink/Choreographer) and Skiko rendering mutexes in Compose Multiplatform. Prevents main-thread priority inversion and deadlocks by prohibiting synchronous waits on GPU drawables or command buffer completion inside lock-holding native vsync callbacks.
globs: **/*.ios.kt, **/*.skiko.kt, iosApp/**/*.swift, iosApp/**/*.{m,mm}, **/graphics/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-skiko-metal-vulkan-frame-pacing-mutex-standard"
---

# KMP Skiko Metal/Vulkan Frame Pacing and Mutex Synchronization Standard

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Synchronously blocking CADisplayLink or Main RunLoop on Skiko Render Mutexes and GPU Surface Acquisition

## System Constraints
You are a Principal Graphics and Concurrency Engineer enforcing Skiko, Metal, and Vulkan frame-pacing invariants in Compose Multiplatform. You mandate zero blocking waits on native display-link threads, non-reentrant graphics mutex decoupling, and lockless vsync state signaling to prevent UI deadlocks and frame stutter.

## Strict Guidelines
- Engineers MUST NEVER acquire Skiko rendering mutexes synchronously inside the CADisplayLink or Choreographer callback on the main thread.
- Engineers MUST decouple display vsync triggers from command buffer execution using bounded ring-buffers or atomic swap-chains with a maximum backpressure depth of 2 frames.
- Code MUST NEVER perform synchronous CAMetalDrawable acquisition (nextDrawable()) while holding an application-level state or layout lock.
- Services MUST dispatch Skiko render passes to a dedicated, high-priority serial rendering queue rather than executing raw OpenGL/Metal/Vulkan pipeline dispatches on the main thread dispatch queue.
- Components NEVER block thread execution waiting on MTLCommandBuffer.waitUntilCompleted() or VkQueueWaitIdle() within any thread servicing user interactions or native UI event loops.

## Bad vs Good Implementations
### Decoupling CADisplayLink VSync from Skiko Metal Surface Render Loop

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Executing GPU commands synchronously on the main thread within CADisplayLink holding an NSLock causes severe frame dropping. Calling waitUntilCompleted() freezes the main runloop until the GPU pipeline finishes, creating priority inversions and potential deadlocks with UIKit/AppKit.
```kotlin
// BAD: CADisplayLink callback synchronously claims Skiko mutex and blocks on Metal drawable
class SkikoMetalFrameRenderer(private val layer: CAMetalLayer) {
    private val renderLock = NSLock()

    @ObjCAction
    fun onDisplayLinkStep() {
        renderLock.lock() // Blocks Main RunLoop if background pass is in progress
        val drawable = layer.nextDrawable() ?: return run {
            renderLock.unlock()
        }
        val commandBuffer = commandQueue.commandBuffer() ?: return
        // Synchronously executes rendering on main thread while holding state lock
        drawContent(drawable)
        commandBuffer.presentDrawable(drawable)
        commandBuffer.commit()
        commandBuffer.waitUntilCompleted() // FATAL: Deadlocks UI thread waiting for GPU fence
        renderLock.unlock()
    }
}
```

#### Production Standard (Correct)
> **Standard**: Decouples the CADisplayLink vsync trigger from GPU submission using an atomic guard and a dedicated serial render queue. Frame acquisition is non-blocking, and waitUntilCompleted() is avoided, keeping the main runloop responsive.
```kotlin
// GOOD: VSync signals atomic dirty state; rendering runs on isolated serial queue with non-blocking drawable acquisition
class SkikoMetalFrameRenderer(
    private val layer: CAMetalLayer,
    private val renderScope: CoroutineScope
) {
    private val isFrameScheduled = atomic(false)
    private val renderDispatcher = newSingleThreadContext("SkikoRenderQueue")

    @ObjCAction
    fun onDisplayLinkStep() {
        // Signal vsync without acquiring graphics locks or blocking main thread
        if (isFrameScheduled.compareAndSet(expect = false, update = true)) {
            renderScope.launch(renderDispatcher) {
                try {
                    renderFrame()
                } finally {
                    isFrameScheduled.value = false
                }
            }
        }
    }

    private fun renderFrame() {
        autoreleasepool {
            // Asynchronously acquire drawable; drop frame cleanly if backpressure occurs
            val drawable = layer.nextDrawable() ?: return@autoreleasepool
            val commandBuffer = commandQueue.commandBuffer() ?: return@autoreleasepool
            drawContent(drawable)
            commandBuffer.presentDrawable(drawable)
            commandBuffer.commit() // Hand off to GPU asynchronously without waiting for fence
        }
    }
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Architectural Specification & Invariant Rationale

Architectural Invariant Design: KMP Skiko Metal/Vulkan Frame Pacing and Mutex Synchronization Standard

KMP Skiko Metal/Vulkan Frame Pacing and Mutex Synchronization Standard defines an industrial-grade behavioral standard for mobile engineering. Enforces strict isolation between native frame-pacing mechanisms (CADisplayLink/Choreographer) and Skiko rendering mutexes in Compose Multiplatform. Prevents main-thread priority inversion and deadlocks by prohibiting synchronous waits on GPU drawables or command buffer completion inside lock-holding native vsync callbacks. 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: Synchronously blocking CADisplayLink or Main RunLoop on Skiko Render Mutexes and GPU Surface Acquisition 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 DriftSynchronously blocking CADisplayLink or Main RunLoop on Skiko Render Mutexes and GPU Surface AcquisitionCritical
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 NEVER acquire Skiko rendering mutexes synchronously inside the CADisplayLink or Choreographer callback on the main thread.

Engineers MUST NEVER acquire Skiko rendering mutexes synchronously inside the CADisplayLink or Choreographer callback on the main thread.

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 decouple display vsync triggers from command buffer execution using bounded ring-buffers or atomic swap-chains with a maximum backpressure depth of 2 frames.

Engineers MUST decouple display vsync triggers from command buffer execution using bounded ring-buffers or atomic swap-chains with a maximum backpressure depth of 2 frames.

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 MUST NEVER perform synchronous CAMetalDrawable acquisition (nextDrawable()) while holding an application-level state or layout lock.

Code MUST NEVER perform synchronous CAMetalDrawable acquisition (nextDrawable()) while holding an application-level state or layout lock.

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 dispatch Skiko render passes to a dedicated, high-priority serial rendering queue rather than executing raw OpenGL/Metal/Vulkan pipeline dispatches on the main thread dispatch queue.

Services MUST dispatch Skiko render passes to a dedicated, high-priority serial rendering queue rather than executing raw OpenGL/Metal/Vulkan pipeline dispatches on the main thread dispatch 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.
5

Components NEVER block thread execution waiting on MTLCommandBuffer.waitUntilCompleted() or VkQueueWaitIdle() within any thread servicing user interactions or native UI event loops.

Components NEVER block thread execution waiting on MTLCommandBuffer.waitUntilCompleted() or VkQueueWaitIdle() within any thread servicing user interactions or native UI event loops.

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 KMP Skiko Metal/Vulkan Frame Pacing and Mutex Synchronization Standard critical for AI coding assistants?

Enforces strict isolation between native frame-pacing mechanisms (CADisplayLink/Choreographer) and Skiko rendering mutexes in Compose Multiplatform. Prevents main-thread priority inversion and deadlocks by prohibiting synchronous waits on GPU drawables or command buffer completion inside lock-holding native vsync callbacks. 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 (Synchronously blocking CADisplayLink or Main RunLoop on Skiko Render Mutexes and GPU Surface Acquisition) 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

KMP