# 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)