mirror of
https://github.com/Kbz-8/Pulse.git
synced 2026-01-11 15:33:34 +00:00
116 lines
3.4 KiB
Objective-C
116 lines
3.4 KiB
Objective-C
// Copyright (C) 2025 kanel
|
|
// This file is part of "Pulse"
|
|
// For conditions of distribution and use, see copyright notice in LICENSE
|
|
|
|
#include <Pulse.h>
|
|
#include "../../PulseInternal.h"
|
|
#include "Metal.h"
|
|
#include "MetalComputePipeline.h"
|
|
#include "MetalCommandList.h"
|
|
#include "MetalDevice.h"
|
|
#include "MetalFence.h"
|
|
#include "MetalBuffer.h"
|
|
#include "MetalImage.h"
|
|
#include "MetalComputePass.h"
|
|
|
|
static uint64_t MetalScoreDevice(id<MTLDevice> device)
|
|
{
|
|
uint64_t score = 0;
|
|
|
|
if(!device.lowPower)
|
|
score += 1000;
|
|
|
|
// A GPU with dedicated memory is typically a dedicated one
|
|
if(!device.hasUnifiedMemory)
|
|
score += 10000;
|
|
|
|
score += device.maxThreadsPerThreadgroup.width;
|
|
score += device.maxThreadsPerThreadgroup.height;
|
|
score += device.maxThreadsPerThreadgroup.depth;
|
|
score += device.maxThreadgroupMemoryLength;
|
|
|
|
return score;
|
|
}
|
|
|
|
static bool MetalIsDeviceForbidden(id<MTLDevice> device, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count)
|
|
{
|
|
if(!device)
|
|
return true;
|
|
for(uint32_t i = 0; i < forbiden_devices_count; i++)
|
|
{
|
|
if(device.registryID == METAL_RETRIEVE_DRIVER_DATA_AS(forbiden_devices[i], MetalDevice*)->device.registryID)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
PulseDevice MetalCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count)
|
|
{
|
|
@autoreleasepool
|
|
{
|
|
PULSE_UNUSED(forbiden_devices);
|
|
PULSE_UNUSED(forbiden_devices_count);
|
|
|
|
PULSE_CHECK_HANDLE_RETVAL(backend, PULSE_NULLPTR);
|
|
|
|
PulseDevice pulse_device = (PulseDeviceHandler*)calloc(1, sizeof(PulseDeviceHandler));
|
|
PULSE_CHECK_ALLOCATION_RETVAL(pulse_device, PULSE_NULL_HANDLE);
|
|
|
|
MetalDevice* metal_device = (MetalDevice*)calloc(1, sizeof(MetalDevice));
|
|
PULSE_CHECK_ALLOCATION_RETVAL(metal_device, PULSE_NULL_HANDLE);
|
|
|
|
#ifdef PULSE_PLAT_MACOS
|
|
uint64_t best = 0;
|
|
NSArray<id<MTLDevice>>* devices = MTLCopyAllDevices();
|
|
for(id<MTLDevice> candidate in devices)
|
|
{
|
|
if(MetalIsDeviceForbidden(candidate, forbiden_devices, forbiden_devices_count))
|
|
continue;
|
|
uint64_t current = MetalScoreDevice(candidate);
|
|
if(current > best)
|
|
{
|
|
best = current;
|
|
metal_device->device = candidate;
|
|
}
|
|
}
|
|
#endif
|
|
if(!metal_device->device)
|
|
{
|
|
#ifdef PULSE_PLAT_MACOS
|
|
if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend))
|
|
PulseLogWarning(backend, "(Metal) failed to select device, falling back on default device");
|
|
#endif
|
|
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
|
|
if(!MetalIsDeviceForbidden(device, forbiden_devices, forbiden_devices_count))
|
|
metal_device->device = device;
|
|
}
|
|
|
|
if(!metal_device->device)
|
|
{
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
|
|
PulseLogError(backend, "(Metal) failed to retrieve default device");
|
|
return PULSE_NULL_HANDLE;
|
|
}
|
|
|
|
metal_device->queue = [metal_device->device newCommandQueue];
|
|
|
|
pulse_device->driver_data = metal_device;
|
|
pulse_device->backend = backend;
|
|
PULSE_LOAD_DRIVER_DEVICE(Metal);
|
|
|
|
if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend))
|
|
PulseLogInfoFmt(backend, "(Metal) created device from %s", [metal_device->device.name UTF8String]);
|
|
return pulse_device;
|
|
}
|
|
}
|
|
|
|
void MetalDestroyDevice(PulseDevice device)
|
|
{
|
|
MetalDevice* metal_device = (MetalDevice*)METAL_RETRIEVE_DRIVER_DATA_AS(device, MetalDevice*);
|
|
if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend))
|
|
PulseLogInfoFmt(device->backend, "(Metal) destroyed device created from %s", [metal_device->device.name UTF8String]);
|
|
metal_device->queue = nil;
|
|
free(metal_device);
|
|
free(device);
|
|
}
|