diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/application.cpp | 13 | ||||
| -rw-r--r-- | src/engine/engine.h | 24 | ||||
| -rw-r--r-- | src/platform/metal/metal_context.h | 8 | ||||
| -rw-r--r-- | src/platform/metal/metal_context.mm | 119 |
4 files changed, 150 insertions, 14 deletions
diff --git a/src/core/application.cpp b/src/core/application.cpp index 37d7fa0..fa5fd6e 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -10,6 +10,10 @@ #include <GLFW/glfw3.h> #include <ImGuizmo.h> +#ifdef __APPLE__ +#include "platform/metal/metal_context.h" +#endif + namespace Donut { Application* Application::s_instance = nullptr; @@ -103,9 +107,14 @@ namespace Donut m_state_manager->on_event(event); } - void Application::on_init() - { + void Application::on_init() + { Logger::init(); + +#ifdef __APPLE__ + metal_probe(); + metal_compute_self_test(); +#endif SettingsManager::initialize(); diff --git a/src/engine/engine.h b/src/engine/engine.h index 0a50612..1c25466 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -35,7 +35,7 @@ namespace Donut double m_radius; double m_rs; - BlackHole(glm::vec3 pos, float mass) + BlackHole(glm::vec3 pos, float mass) : m_position(pos), m_mass(mass) { m_rs = 2.0 * G * m_mass / (c * c); @@ -99,33 +99,33 @@ namespace Donut int get_compute_height() const { return m_compute_height; } int get_compute_width() const { return (m_width * m_compute_height) / m_height; } void update_compute_dimensions(); - + int get_max_steps_moving() const { return m_max_steps_moving; } int get_max_steps_static() const { return m_max_steps_static; } float get_early_exit_distance() const { return m_early_exit_distance; } void set_max_steps_moving(int steps) { m_max_steps_moving = steps; } void set_max_steps_static(int steps) { m_max_steps_static = steps; } void set_early_exit_distance(float distance) { m_early_exit_distance = distance; } - + float get_disk_thickness() const { return m_disk_thickness; } void set_disk_thickness(float thickness) { m_disk_thickness = thickness; } - + float get_disk_density() const { return m_disk_density; } void set_disk_density(float density) { m_disk_density = density; } - + float get_rotation_speed() const { return m_rotation_speed; } void set_rotation_speed(float speed) { m_rotation_speed = speed; } - + float get_blur_strength() const { return m_blur_strength; } void set_blur_strength(float strength) { m_blur_strength = strength; } - + float get_glow_intensity() const { return m_glow_intensity; } void set_glow_intensity(float intensity) { m_glow_intensity = intensity; } - + void load_objects_from_scene(const std::vector<Donut::Object>& objects); void export_high_res_frame(const std::string& filename, int width = 4096, int height = 3072); void print_object_info() const; - + void set_hdri_environment(Ref<CubemapTexture> hdri) { m_hdri_environment = hdri; } Ref<CubemapTexture> get_hdri_environment() const { return m_hdri_environment; } private: @@ -161,12 +161,12 @@ namespace Donut BlackHole m_sag_a; Camera m_camera; bool m_gravity = false; - + int m_max_steps_moving = 60000; int m_max_steps_static = 30000; float m_early_exit_distance = 5.0e11f; - - float m_disk_thickness = 0.1f; + + float m_disk_thickness = 0.1f; float m_disk_density = 0.1f; float m_rotation_speed = 1.0f; float m_blur_strength = 2.0f; diff --git a/src/platform/metal/metal_context.h b/src/platform/metal/metal_context.h new file mode 100644 index 0000000..66e8ae2 --- /dev/null +++ b/src/platform/metal/metal_context.h @@ -0,0 +1,8 @@ +#pragma once + +namespace Donut +{ + bool metal_probe(); + + bool metal_compute_self_test(); +} diff --git a/src/platform/metal/metal_context.mm b/src/platform/metal/metal_context.mm new file mode 100644 index 0000000..a616865 --- /dev/null +++ b/src/platform/metal/metal_context.mm @@ -0,0 +1,119 @@ +#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; + } + } + + 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]; + + 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; + } + } +} |
