device.cpp

cross platform rendering playground

src/backend/metal/device.cpp

2.92 KB
#include <math.h>
#ifndef INFINITY
#define INFINITY __builtin_huge_valf()
#endif
#include <Foundation/Foundation.hpp>
#include <Metal/Metal.hpp>

#include <cstdlib>

#include "backend/metal/mt_api.h"
#include "backend/metal/mt_internal.h"
#include "core/logger.h"

namespace rhi {
using namespace mt;

static void set_default_env(const char *name, const char *value) {
    if (::getenv(name) == nullptr) {
        ::setenv(name, value, 0);
    }
}

void create_context(Device &device, rhi::Config &cfg) {
    if (cfg.enable_validation) {
        set_default_env("MTL_DEBUG_LAYER", "1");
        set_default_env("MTL_DEBUG_LAYER_ERROR_MODE", "assert");
        set_default_env("MTL_DEBUG_LAYER_VALIDATE_LOAD_ACTIONS", "1");
        set_default_env("MTL_DEBUG_LAYER_VALIDATE_STORE_ACTIONS", "1");
        set_default_env("MTL_SHADER_VALIDATION", "1");
        set_default_env("MTL_SHADER_VALIDATION_REPORT_TO_STDERR", "1");
    }
    VEL_INFO("Initializing Metal Context");

    MTL::Device *dev = MTL::CreateSystemDefaultDevice();
    if (!dev) {
        VEL_CRITICAL("Failed to create a Metal device");
        std::abort();
    }

    MTL4::CommandQueue *queue = dev->newMTL4CommandQueue();
    if (!queue) {
        VEL_CRITICAL("Failed to create MTL4 command queue");
        std::abort();
    }

    device.handle = dev;
    device.graphics.handle = queue;

    mt::create_heap(device);
    if (!device.heap) {
        VEL_CRITICAL("Failed to create Metal argument heap");
        std::abort();
    }

    VEL_INFO("Selected GPU: {}", dev->name()->utf8String());
    if (::getenv("MTL_DEBUG_LAYER") != nullptr || ::getenv("MTL_SHADER_VALIDATION") != nullptr) {
        VEL_INFO(
            "Metal validation: API={} Shader={}",
            ::getenv("MTL_DEBUG_LAYER") ? ::getenv("MTL_DEBUG_LAYER") : "0",
            ::getenv("MTL_SHADER_VALIDATION") ? ::getenv("MTL_SHADER_VALIDATION") : "0"
        );
    }
}

void destroy_context(Device &device) {
    VEL_INFO("Shutting down Metal Context...");

    mt::destroy_heap(device);

    if (device.graphics.handle) {
        device.graphics.handle->release();
        device.graphics.handle = nullptr;
    }
    if (device.handle) {
        device.handle->release();
        device.handle = nullptr;
    }
}

void device_wait_idle(Device &device) {
    (void)device;
    mt_wait_idle();
}

void queue_wait_idle(Device &device) {
    (void)device;
    mt_wait_idle();
}

bool create_memory_allocator(Device &device) {
    (void)device;
    // unified. nothing to do.
    return true;
}

void destroy_memory_allocator(Device &device) {
    (void)device;
}

MemoryStats memory_stats(Device &device) {
    (void)device;
    return {};
}

Queue find_queue(Device &device, u32 required, u32 excluded) {
    (void)required;
    (void)excluded;
    return device.graphics;
}

Queue graphics_queue(Device &device) {
    return device.graphics;
}

u32 queue_family_index(const Queue &queue) {
    return queue.family_index;
}

} // namespace rhi