Theme Catppuccin
Make yourself at homeCatppuccin

A softer light for long learning sessions.

Appearance

Loading your preference…

Dark palette

Choose a dark palette to try it.

Light uses Latte. Your choices stay in this browser.

Back to your source shelf

Inside the companion

Metal · Copper Orchard

Connect a Cocoa window to a C++ Metal renderer and verify GPU results.

Project files 7

Open the Copper Orchard checkpoint

Build the C++/Cocoa window and run device and compute verification probes.

191 lines README.md
# Copper Orchard · Metal companions

Course 6 teaches an original 12-week native Metal project in six chapters. The
intended renderer uses **C++ with metal-cpp** and a narrow Objective-C++ boundary
for Cocoa window/view/event integration. A complete runnable clear-color window now provides that boundary and frame
lifetime foundation. The final material/compute orchard scene remains a staged
extension project; it is not silently supplied by the clear checkpoint.

## Current host-language baseline

The companions build as **C++23** with extensions disabled. The recipes select
Ninja and Clang explicitly; on macOS, `clang++` normally selects Apple Clang.
Use a fresh build directory when changing generator or compiler. CMake describes
and configures the targets, Ninja runs their build steps, and Clang compiles them.
No setup command here installs a dependency. The shader language is configured
separately from C++.

No C++26 feature is required by the GPU programs. Check the exact compiler and
standard-library support before adopting a later feature. Older idioms remain
useful when their contracts are clear: the purpose of scoped owners and checked return values here
is to make cleanup and failure paths explicit, not to replace every line with new
syntax. The independent C++23 audit is recorded in `audits/gpu-courses.md` at the
project root; earlier C++20 evidence below retains its original scope.

## The complete window bridge

`orchard_window.mm` owns Cocoa/MTKView integration under ARC and drives drawing
from a single main-thread event pump. `window_renderer.hpp/.cpp` owns the renderer
in ordinary C++23 using metal-cpp. A std::unique_ptr with a custom release deleter
owns each retained Cocoa reference; a checked retain helper acquires borrowed
references. This avoids null C++ member calls in the current NS::SharedPtr
assignment implementation observed by UBSan, without suppressing diagnostics.
The earlier device probe still illustrates Apple’s TransferPtr/RetainPtr helpers.
Implementation macros appear in exactly one
translation unit. `OrchardBridge` catches every C++ exception in its draw callback;
main reports failures. Borrowed view objects cross the boundary for one call.

Three slots retain submitted command buffers until completion. Each diagnostic
slot also owns its readback buffer. Normal rendering polls the next slot and skips
if busy, before asking for a drawable; it does not block on every frame. Missing
drawables and minimized/zero-size views skip work. MTKView manages its color
drawable size; a future owned depth attachment still needs an explicit size policy.

From the **Parallax project root**, with Apple's developer tools, CMake, Ninja,
and Apple's official metal-cpp headers already available:

```sh
cmake -S native/advanced/metal -B native/build-orchard -G Ninja \
  -DCMAKE_CXX_COMPILER=/usr/bin/clang++ \
  -DCMAKE_OBJCXX_COMPILER=/usr/bin/clang++ \
  -DCMAKE_BUILD_TYPE=Debug \
  -DMETAL_CPP_INCLUDE_DIR=/absolute/path/to/metal-cpp
cmake --build native/build-orchard
ctest --test-dir native/build-orchard --output-on-failure
./native/build-orchard/orchard-window --frames 12 --verify
./native/build-orchard/orchard-window --frames 300 --verify --resize
./native/build-orchard/orchard-window --frames 12 --verify --fail-after 2
```

The last command deliberately fails after two successful submissions. Expect
nonzero exit with `injected host failure`; the renderer's destructor still waits
remaining command buffers before releasing their resources. This tests a host
exception, not an injected GPU/device failure. `--frames 0` also rejects input
before GPU/window setup. Run without arguments to leave the blue window open for
manual minimize/restore/resize/close testing.

`--verify` disables framebuffer-only drawable usage, clears an actual
BGRA8Unorm attachment to RGBA `(0.125,0.25,0.5,1)`, copies one pixel to shared
memory with a 256-byte row pitch, waits for completion before inspection, and
checks BGRA bytes approximately `[128,64,32,255]` (±1 quantization unit). The
normal path keeps framebuffer-only enabled. Clear and Store actions preserve
the defined color for presentation/readback; this clear-only pass needs no shader
pipeline. Change only the red clear value in a scratch copy: the unchanged oracle
must reject it. A one-pixel oracle is not an entire scene or display-color proof.

Normal exit detaches callbacks, drains and checks the remaining command buffers,
then destroys scoped owners. The nonthrowing destructor supplies a completion
fallback during exceptions. No callbacks capture renderer ownership in this
checkpoint. Later asynchronous callback lessons must preserve the same lifetime
and writable-range contracts with their own bounded completion handoff.

**Executed on M4 Pro, 2026-10-24:** twelve and three hundred submitted/verified
frames, resize to a 1920×1080 drawable, and drained shutdown. The injected host
failure and invalid frame count failed as intended. The existing 1,003-element
compute oracle and 63 padding sentinels also passed. These are actual GPU runs,
not only C++ type checks. The computer was locked during the later manual CUA
walkthrough attempt, so interactive minimize/restore/close evidence remains
unverified; no claim of a manual pass is made. Full evidence is in
`audits/renderer-vulkan-metal-update.md`.

## Two earlier probes, preserved as separate checkpoints

### `orchard_probe.mm`: executed SDK-only compute check

This complete command-line program uses Objective-C++ and ARC with the installed
Foundation/Metal frameworks. It does **not** use metal-cpp and does not create a
window. It reports the actual device, several supported feature families, unified
memory, buffer limits, and recommended working set. It then compiles a small MSL
kernel, dispatches 1,003 float elements, waits for completion, and checks every
result against a CPU oracle. The deliberately awkward element count exercises a
rounded workgroup dispatch. The probe now initializes 63 padded output values
to a sentinel and checks that none changed, so a missing tail guard cannot pass
merely because the first 1,003 outputs are correct.

The blocking wait is appropriate for this one-shot verification program. It is
not a pattern for a continuously overlapping renderer. The later lessons teach
bounded frame slots, completion callbacks, safe CPU/GPU range reuse, and shutdown.

From this directory:

```sh
cmake -S . -G Ninja -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_OBJCXX_COMPILER=/usr/bin/clang++ -B /tmp/prism-orchard -DCMAKE_BUILD_TYPE=Debug
cmake --build /tmp/prism-orchard
ctest --test-dir /tmp/prism-orchard --output-on-failure
```

Or directly:

```sh
xcrun clang++ -std=c++23 -fobjc-arc -Wall -Wextra -Wpedantic orchard_probe.mm -framework Foundation -framework Metal -o /tmp/prism-orchard-probe
/tmp/prism-orchard-probe
```

Verification on the authoring Mac: compiled with Apple Clang and the installed
SDK; ran on **Apple M4 Pro**; all **1,003 GPU results matched the CPU oracle**.
The queried device reported unified memory and support for Apple7, Apple8, and
Apple9 families. These are observations from that run, not hard-coded requirements
or a claim about every Metal feature. The code has a top-level C++ exception
boundary for host allocation failures and checks resource/shader/command failures.
The C++23 audit rerun additionally verified all 63 padding sentinels, and a
safely padded guard-removal control failed at index 1,003 as expected. The probe
requires actual GPU access; an execution sandbox may report no device.

### `metal_cpp_device.cpp`: executed C++ ownership probe

This complete small program uses Apple's metal-cpp headers to create a device,
queue, and command buffer. It demonstrates adoption of owned Create/new returns
with `NS::TransferPtr`, and retention of an autoreleased command-buffer result
with `NS::RetainPtr`. It does not submit work. Implementation macros appear in
one translation unit. ARC does not manage these C++ pointers.

Obtain metal-cpp from Apple's official source and supply its include directory:

```sh
cmake -S . -G Ninja -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_OBJCXX_COMPILER=/usr/bin/clang++ -B /tmp/prism-orchard-cpp -DMETAL_CPP_INCLUDE_DIR=/absolute/path/to/metal-cpp
cmake --build /tmp/prism-orchard-cpp
/tmp/prism-orchard-cpp/orchard-cpp-device
```

This optional target was **compiled and run on 2026-10-24** using Apple's official
[metal-cpp source at revision `8cdde68ae36a636c84cbb48ebcbc8f3b60251ea0`](https://github.com/apple/metal-cpp/tree/8cdde68ae36a636c84cbb48ebcbc8f3b60251ea0)
(the macOS 27.0.1 / iOS 27.0.1 header release, dated 2026-09-22). The headers were
downloaded into the authoring task's `work/apple-metal-cpp` directory, outside this
course project. No system software or headers were installed.

The earlier supplied CMake target built in Debug with AppleClang 21.0.0.21000334, C++20 as
configured, and the Foundation/Metal frameworks. Build and link completed without
diagnostics. With access to the local Metal device, the executable printed
`Apple M4 Pro` and exited with status zero. This exercised device/queue/command-buffer
creation, `TransferPtr`/`RetainPtr` ownership, and normal scoped destruction. It
submitted no GPU work. The separate SDK-only probe supplies the 1,003-result compute
evidence; neither probe establishes the window bridge, complete renderer, callback
shutdown policy, or absence of all memory errors.

## What you build through the lessons

1. An actual-device passport, C++ ownership table, and small Cocoa window bridge.
2. Bounded buffers, explicit storage choices, and completion-based writable slots.
3. MSL stages and a verified host/shader ABI with matching pipeline formats.
4. A depth-tested material study with intentional attachment load/store choices.
5. Asynchronous frame completion, callback ownership, and safe shutdown.
6. A deterministic compute effect, Xcode GPU capture, measured change, and finished
   original orchard scene for your portfolio.

Lesson code is marked as an integration fragment, model, or complete shader.
The MSL kernel alone does not supply its host bindings or synchronization. The
course baseline requires neither Metal 4 nor hardware ray tracing. Query feature
families and specific capabilities on the actual target before adding optional
paths. Shared/unified memory gives access; it does not make concurrent CPU/GPU
writes or reads automatically safe.

## Primary references

- [Apple metal-cpp setup](https://developer.apple.com/metal/cpp/)
- [Apple metal-cpp ownership README](https://github.com/apple/metal-cpp/blob/main/README.md)
- [Apple Metal Shading Language specification](https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf)
- [Apple GPU calculations](https://developer.apple.com/documentation/metal/performing-calculations-on-a-gpu)
- [Apple CPU/GPU synchronization](https://developer.apple.com/documentation/metal/synchronizing-cpu-and-gpu-work)
- [Apple Metal tools](https://developer.apple.com/metal/tools/)
- [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)

This is the file included with the course. Copy and download give you its complete source.

Taking your work offline? Download all course companions