Skip to content

Hello Triangle (Native Apple)

This example shows how to use KDGpu in a real Apple application without the KDGpuExample helper framework. It handles platform-specific initialization including Metal layer setup, MoltenVK configuration, and native window integration. This is essential for integrating KDGpu into existing Objective-C or Swift applications.

Full Source: KDGpuRenderer.cpp

Overview

What this example demonstrates:

  • Manual KDGpu initialization on Apple platforms
  • Creating Vulkan surface from CAMetalLayer
  • MoltenVK-specific configuration and limitations
  • Integrating with native Objective-C/Swift applications
  • Platform-specific swapchain and device setup

Use cases:

  • Adding KDGpu to existing macOS/iOS applications
  • Custom render loops in native Apple frameworks (AppKit, UIKit)
  • Full control over initialization for production apps
  • Understanding platform-specific Vulkan requirements

Vulkan Requirements

  • Vulkan Version: 1.0+ (via MoltenVK)
  • Platform: macOS 10.13+ or iOS 11+
  • Extensions:
    • VK_KHR_surface (platform abstraction)
    • VK_MVK_macos_surface (macOS) or VK_MVK_ios_surface (iOS)
    • VK_KHR_portability_subset (MoltenVK portability)
  • Metal: Requires Metal 2.0+ support

Key Concepts

MoltenVK:

MoltenVK is a Vulkan Portability implementation that layers Vulkan API over Apple's Metal graphics framework. It's the only way to use Vulkan on Apple platforms, translating Vulkan commands to Metal at runtime.

Key characteristics:

  • Not full Vulkan conformance - implements "portability subset"
  • Some Vulkan features unavailable (geometry shaders, tessellation)
  • Performance very close to native Metal
  • Required for cross-platform Vulkan applications on Apple

Official MoltenVK docs: https://github.com/KhronosGroup/MoltenVK

CAMetalLayer:

On Apple platforms, rendering requires a CAMetalLayer - a Core Animation layer backed by Metal. The Vulkan surface is created from this Metal layer:

1
2
3
4
// Objective-C: Create Metal layer
CAMetalLayer *metalLayer = [CAMetalLayer layer];
metalLayer.device = MTLCreateSystemDefaultDevice();
view.layer = metalLayer;

The Vulkan surface then wraps this Metal layer, allowing Vulkan commands to target the layer.

Portability Subset:

MoltenVK implements the VK_KHR_portability_subset extension, indicating it doesn't support all Vulkan features. Applications must:

  • Enable the extension during instance/device creation
  • Query feature availability before use
  • Handle missing features gracefully

Spec: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_portability_subset.html

Implementation

Manual KDGpu Initialization:

Unlike helper API examples, this manually creates Instance, Surface, Device, and Swapchain. See the KDGpuRenderer.cpp source file for the complete initialization implementation. Key Apple-specific steps include:

  1. Enable portability extensions: VK_KHR_portability_subset must be enabled
  2. Create surface from Metal layer: Use platform-specific surface creation
  3. Query portability features: Check which Vulkan features MoltenVK supports
  4. Configure swapchain: Apple platforms may have specific format/present mode requirements

Frame Rendering:

The render loop handles swapchain acquisition, command recording, and presentation. See Renderer/KDGpuRenderer.cpp for implementation details.

Platform Considerations

macOS-Specific:

  • Use VK_MVK_macos_surface extension
  • AppKit integration via NSView's CAMetalLayer
  • Full screen exclusive mode not available
  • Multiple GPU support (query correct Metal device)

iOS-Specific:

  • Use VK_MVK_ios_surface extension
  • UIKit integration via UIView's CAMetalLayer
  • Handle app lifecycle (background/foreground)
  • Respect memory constraints (mobile devices)

MoltenVK Limitations:

  • No geometry or tessellation shaders
  • Limited descriptor indexing support
  • Some image formats unavailable
  • Memory budget constraints
  • Shader translation overhead (compile SPIR-V to Metal at runtime)

Performance Tips:

  • Use Metal-native formats (BGRA8 for swap chain)
  • Minimize descriptor set updates (Metal has overhead)
  • Consider Metal Performance Shaders (MPS) for compute
  • Profile with Xcode Instruments Metal profiler

See Also

Further Reading


Updated on 2026-03-31 at 00:02:07 +0000