aboutsummaryrefslogtreecommitdiff
path: root/src/platform/metal
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-23 17:21:37 +0200
committerhachem <im@hachem.wtf>2026-08-23 17:21:37 +0200
commit3fd33ecff7472e4d6fc9e6b3905f56982e497ef2 (patch)
tree66e5812f1a18b926e88a0dd549fe14e7c7327165 /src/platform/metal
parente3aa33fc9a99d8b817bda42a567a4c347e18ab32 (diff)
[feat]: complete RHI api
Diffstat (limited to 'src/platform/metal')
-rw-r--r--src/platform/metal/metal_context.h16
-rw-r--r--src/platform/metal/metal_context.mm124
2 files changed, 0 insertions, 140 deletions
diff --git a/src/platform/metal/metal_context.h b/src/platform/metal/metal_context.h
deleted file mode 100644
index f1e376b..0000000
--- a/src/platform/metal/metal_context.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-// Pure-C++ interface to the Metal backend (no Objective-C leaks into the rest
-// of the engine). Implemented in MetalContext.mm.
-namespace Donut
-{
- // Phase 1 bring-up: creates the default Metal device + command queue and
- // logs its capabilities, proving the Metal toolchain and build integration
- // work natively on Apple Silicon. This grows into the Metal compute island
- // that runs the geodesic ray tracer in real time.
- auto metal_probe() -> bool;
-
- // Compiles + dispatches a trivial compute kernel and validates the read-back,
- // proving the Metal compute path the geodesic ray tracer will run on.
- auto metal_compute_self_test() -> bool;
-}
diff --git a/src/platform/metal/metal_context.mm b/src/platform/metal/metal_context.mm
deleted file mode 100644
index 71e8551..0000000
--- a/src/platform/metal/metal_context.mm
+++ /dev/null
@@ -1,124 +0,0 @@
-#import <Metal/Metal.h>
-#import <Foundation/Foundation.h>
-
-#include "metal_context.h"
-#include "core/log.h"
-
-#include <vector>
-
-namespace Donut
-{
- bool metal_probe()
- {
- @autoreleasepool
- {
- id<MTLDevice> device = MTLCreateSystemDefaultDevice();
- if (device == nil)
- {
- DONUT_ERROR("Metal: no default device available");
- return false;
- }
-
- id<MTLCommandQueue> queue = [device newCommandQueue];
- const char* name = [[device name] UTF8String];
-
- DONUT_INFO("Metal device: {}", name ? name : "(unknown)");
- DONUT_INFO("Metal: unified memory = {}, max threads/threadgroup = {}",
- device.hasUnifiedMemory ? "yes" : "no",
- (unsigned long)device.maxThreadsPerThreadgroup.width);
-
- if (queue == nil)
- {
- DONUT_WARN("Metal: failed to create command queue");
- return false;
- }
-
- return true;
- }
- }
-
- // Compiles a trivial compute kernel, dispatches it over a small texture, and
- // reads the result back to confirm the full Metal compute path works: source
- // compilation, pipeline state, command encoding, dispatch, and shared-memory
- // read-back. This is the mechanism the geodesic ray tracer will run on.
- bool metal_compute_self_test()
- {
- @autoreleasepool
- {
- id<MTLDevice> device = MTLCreateSystemDefaultDevice();
- id<MTLCommandQueue> queue = [device newCommandQueue];
- if (device == nil || queue == nil)
- return false;
-
- NSString* src =
- @"#include <metal_stdlib>\n"
- "using namespace metal;\n"
- "kernel void selfTest(texture2d<float, access::write> outTex [[texture(0)]],\n"
- " uint2 gid [[thread_position_in_grid]])\n"
- "{\n"
- " uint w = outTex.get_width();\n"
- " uint h = outTex.get_height();\n"
- " if (gid.x >= w || gid.y >= h) return;\n"
- " outTex.write(float4(float(gid.x) / float(w - 1),\n"
- " float(gid.y) / float(h - 1), 0.5, 1.0), gid);\n"
- "}\n";
-
- NSError* err = nil;
- id<MTLLibrary> lib = [device newLibraryWithSource:src options:nil error:&err];
- if (lib == nil)
- {
- DONUT_ERROR("Metal self-test: kernel compile failed: {}",
- err ? [[err localizedDescription] UTF8String] : "unknown");
- return false;
- }
-
- id<MTLFunction> fn = [lib newFunctionWithName:@"selfTest"];
- id<MTLComputePipelineState> pipeline =
- [device newComputePipelineStateWithFunction:fn error:&err];
- if (pipeline == nil)
- {
- DONUT_ERROR("Metal self-test: pipeline creation failed");
- return false;
- }
-
- const uint32_t W = 64, H = 64;
- MTLTextureDescriptor* desc =
- [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
- width:W
- height:H
- mipmapped:NO];
- desc.usage = MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead;
- desc.storageMode = MTLStorageModeShared;
- id<MTLTexture> tex = [device newTextureWithDescriptor:desc];
-
- id<MTLCommandBuffer> cb = [queue commandBuffer];
- id<MTLComputeCommandEncoder> enc = [cb computeCommandEncoder];
- [enc setComputePipelineState:pipeline];
- [enc setTexture:tex atIndex:0];
-
- MTLSize tg = MTLSizeMake(16, 16, 1);
- MTLSize grid = MTLSizeMake(W, H, 1);
- [enc dispatchThreads:grid threadsPerThreadgroup:tg];
- [enc endEncoding];
- [cb commit];
- [cb waitUntilCompleted];
-
- // Read back the far corner; the kernel writes (~1, ~1, 0.5, 1) there.
- std::vector<uint8_t> px(W * H * 4);
- [tex getBytes:px.data()
- bytesPerRow:W * 4
- fromRegion:MTLRegionMake2D(0, 0, W, H)
- mipmapLevel:0];
-
- size_t corner = ((size_t)(H - 1) * W + (W - 1)) * 4;
- DONUT_INFO("Metal compute self-test: corner pixel RGBA = ({}, {}, {}, {})",
- (int)px[corner + 0], (int)px[corner + 1],
- (int)px[corner + 2], (int)px[corner + 3]);
-
- bool ok = px[corner + 0] > 250 && px[corner + 1] > 250 &&
- px[corner + 3] == 255;
- DONUT_INFO("Metal compute self-test: {}", ok ? "PASS" : "FAIL");
- return ok;
- }
- }
-}