Руководство
Metal
Metal — интерфейс GPU от Apple: приложение записывает работу в командные буферы, а GPU её выполняет. В hakios за это отвечает hakios-metal: он превращает работу в собственные командные пакеты GPU Adreno и передаёт их напрямую драйверу GPU в ядре. Без Vulkan и без Mesa посередине.
Где мы сейчас
| Часть | Состояние |
|---|---|
| очереди и командные буферы — с состояниями Metal и обработчиками завершения в порядке отправки | работает на GPU телефона |
| буферы в памяти GPU | работает |
| копирование и заливка (blit) командным процессором GPU | работает на GPU телефона |
библиотеки шейдеров .metallib: чтение и проверка |
работает |
| шейдеры: выполнение функции Metal на GPU | ещё нет: компилятор AIR → NIR → ir3 уже есть в сборке Mesa в hakios, его подключают к драйверу |
| конвейеры отрисовки и вычислений, текстуры | ещё нет |
| интерфейс системы рисуется через Metal | ещё нет: сейчас — через OpenGL ES |
На Adreno 642L в POCO X5 Pro 28 октября 2026 года проба прошла все проверки:
| Проверка | Результат |
|---|---|
| копирование 500 000 байт | байт в байт, соседняя память не тронута, 4,2 мс |
| заливка 4, 256, 260, 65 540 и 999 996 байт | всё верно |
| 40 командных буферов одновременно | завершились по порядку, с обработчиками |
| копирование 16 МБ | 182 мс (92 МБ/с: верно, но медленно; быстрый путь — блиттер GPU, он следующий) |
Как связаны части
программа на Metal
│ MTLDevice · MTLCommandQueue · MTLCommandBuffer · MTLBlitCommandEncoder
▼
HakiosMetal.bundle плагин Metal (hakios-xnu-kernel: userland/src/HakiosMetal.m)
▼
command.hpp очереди, командные буферы, blit → пакеты PM4 (pm4.hpp)
▼
gpu.hpp буферы GPU, отправка, барьеры (fences)
▼
транспорт iokit_transport на телефоне · fake_gpu в тестах
▼
HakiosGPU драйвер GPU в ядре (drivers/gpu/hakios.gpu.cpp) ──► Adreno
Как Metal его находит: с аргументом загрузки metal=N ядро называет HakiosMetal плагином Metal для GPU. Metal загружает /System/Library/Extensions/HakiosMetal.bundle, и MTLCreateSystemDefaultDevice() возвращает наше устройство.
metal= |
Кто видит устройство Metal |
|---|---|
| (не задан) | никто — так по умолчанию, специально |
1 |
только тестовая программа metal_test |
2 |
все процессы, кроме оконного сервера |
3 |
все процессы |
Почему выключено по умолчанию. Устройство Metal, которое пока не умеет рисовать, заставляет оконный сервер запросить его, упасть и перезапускаться по кругу. Пока шейдеры не работают, держите
metal=на 1 или 2.
1. Сборка и тесты на компьютере
Тесты гоняют драйвер на поддельном GPU, который так же строг, как настоящий командный процессор: неверный бит чётности, счётчик за концом, неизвестный опкод или адрес вне всех буферов — это сбой, а не падение. Подойдёт любой компилятор C++17 в macOS или Linux.
git clone https://github.com/oosexgang/hakios-metal.git
cd hakios-metal
make test # 21 тест на поддельном GPU
out/host/tests copy # только тесты, в имени которых есть "copy"
2. Проба на GPU телефона
Проба делает на настоящем GPU то же, что тесты на поддельном, по строке на проверку. Нужен телефон с hakios и gpu=1 (значит, fw-gpu/ уже снят) и iPhoneOS 16.5 SDK — его скачивает xnu-deps/setup.sh в основном репозитории.
Положите hakios-metal рядом с основным репозиторием:
work/
├── hakios/ hakios-xnu-kernel
└── hakios-metal/
cd hakios-metal
make ios HAKIOS=../hakios # out/ios/hakios-metal-probe и out/ios/libhakios-metal.a
cd ../hakios
# список задач: что система запустит, когда поднимется
printf '/redwood/bin/hakios-metal-probe\n' > userland/rc.jobs.metalprobe
EXTRA="../hakios-metal/out/ios/hakios-metal-probe" RC_JOBS=rc.jobs.metalprobe userland/build.sh
./xl enter && ./xl ramdisk userland/system.apfs
XL_SECS=120 XL_CMDLINE="$(tools/hakios-config.py args) gpu=1" ./xl run
grep probe: logs/last.log
EXTRAкопирует программы с вашего компьютера в/redwood/binна телефоне.RC_JOBSвыбирает список команд, которые система выполнит, когда поднимется. Это не скрипт оболочки: одна команда на строку, без переменных и кавычек.- Что печатает удачный запуск:
probe: GPU 660, chip id 0x…
probe: ok … по строке на проверку: копирование, заливки, 40 командных буферов, 16 МБ
probe: 0 failures
Код выхода — число сбоев; 100 значит «нет GPU» (строкой выше сказано почему — например, ядро запущено без gpu=1).
3. Использование из кода
Через Metal (Objective-C)
Это настоящий путь через API — те же вызовы, что делает приложение. Сокращённый фрагмент userland/src/metal_test.m.
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
id<MTLCommandQueue> queue = [device newCommandQueue];
id<MTLBuffer> a = [device newBufferWithLength:n options:MTLResourceStorageModeShared];
id<MTLBuffer> b = [device newBufferWithLength:n options:MTLResourceStorageModeShared];
id<MTLCommandBuffer> cb = [queue commandBuffer];
id<MTLBlitCommandEncoder> blit = [cb blitCommandEncoder];
[blit copyFromBuffer:a sourceOffset:4096 toBuffer:b destinationOffset:8192 size:500000];
[blit fillBuffer:b range:NSMakeRange(600000, 4096) value:0xa5];
[blit endEncoding];
[cb addCompletedHandler:^(id<MTLCommandBuffer> done) { /* done.status == MTLCommandBufferStatusCompleted */ }];
[cb commit];
[cb waitUntilCompleted];
- Смещения и размеры должны быть кратны 4.
- Нужны
gpu=1иmetal=1(или выше) в командной строке. - То, что плагин ещё не умеет, пишется в лог как
HakiosMetal: asked and not implemented: -...и получает ответ nil: лог точно говорит, чего хотело приложение.
Без Metal (C)
include/hakios-metal/hakios_metal.h — небольшой интерфейс на C, его можно вызывать из любой программы. Каждый вызов сообщает, получилось ли; причина — в hakios_metal_error().
#include <hakios-metal/hakios_metal.h>
hakios_metal_device *d = hakios_metal_open(); /* NULL без gpu=1: см. hakios_metal_error() */
hakios_metal_buffer *a = hakios_metal_buffer_new(d, 4096);
hakios_metal_buffer *b = hakios_metal_buffer_new(d, 4096);
memset(hakios_metal_buffer_contents(a), 0x3c, 4096);
hakios_metal_queue *q = hakios_metal_queue_new(d);
hakios_metal_cb *cb = hakios_metal_cb_new(q);
hakios_metal_cb_copy(cb, a, 0, b, 0, 4096); /* 0, или -1 и причина в hakios_metal_error() */
hakios_metal_cb_commit(cb, NULL, NULL); /* или обратный вызов в потоке очереди */
hakios_metal_cb_wait(cb);
/* hakios_metal_cb_status(cb) == HAKIOS_METAL_COMPLETED */
hakios_metal_cb_free(cb);
hakios_metal_open_fake() даёт то же устройство на поддельном GPU — для тестов на компьютере.
Связать плагин с GPU
userland/build.sh собирает HakiosMetal.bundle с командными буферами и копированием на GPU, только если находит ../../hakios-metal/out/darwin/libhakios-metal.a (или $HAKIOS_METAL/out/darwin/...). Без неё буферы лежат в обычной памяти, а очередь не создаёт командных буферов. Makefile hakios-metal пока пишет библиотеку в out/ios/; пока у него нет цели darwin, положите её туда, где её ищет сборка:
mkdir -p ../hakios-metal/out/darwin && cp ../hakios-metal/out/ios/libhakios-metal.a ../hakios-metal/out/darwin/
userland/build.sh # напишет "HakiosMetal with hakios-metal (...)", если нашёл
Попробовать в QEMU
В QEMU нет Adreno, поэтому пути через GPU там нет, но можно увидеть, что Darwin думает о Metal: какие сервисы ищет, загружается ли плагин, какое устройство возвращает MTLCreateSystemDefaultDevice().
RC_JOBS=rc.jobs.metal REST=1 userland/build.sh
CMDLINE="metal=1" qemu/run-darwin.sh 600 -display gtk > logs/qemu.log
Сессия должна быть длинной: в QEMU SpringBoard поднимается примерно за 208 секунд, а metal_test идёт после него — дайте 480 секунд или больше.
Что дальше
- Шейдеры: подключить фронтенд AIR (
tools/mesa/airв основном репозитории) к драйверу, чтобы функция Metal компилировалась в ir3 для Adreno. Из 456 шейдерных модулей системы 321 уже доходит до ir3, а 54 выполнились на GPU телефона. - Конвейеры отрисовки и вычислений поверх этих шейдеров.
- Быстрое копирование через блиттер GPU.
- Тогда CoreAnimation сможет рисовать через Metal вместо OpenGL ES.
Подробный план со всеми шагами и тестами: Metal на Adreno и компилятор шейдеров.