#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