Программный конвейер GFX (экспериментально)

Экспериментально. Конвейер реализован целиком, и прогон демок DolphinSDK ниже на большинстве демок даёт те же картинки, что и шейдерный бэкенд, но в некоторых заголовках ещё есть дефекты картинки (среди них демки сглаженного framebuffer). По умолчанию остаётся шейдерный бэкенд.

У графической подсистемы Flipper есть второй путь рендеринга: программная (CPU) реализация тех же аппаратных блоков. Она написана по спецификациям GameCube — блок трансформации, блок setup, три растеризатора, блок текстур с настоящей TMEM, TEV и пиксельный движок с настоящим массивом памяти EFB — и не открывает контекст OpenGL вообще. Готовый кадр превращается блоком копирования в XFB в основной памяти, а видеоинтерфейс выводит его на экран — всё как на настоящей консоли.

Два конвейера

Шейдерный бэкенд отображает две программируемые ступени Flipper на две программируемые ступени OpenGL (XF — на вершинный шейдер, TEV — на фрагментный) и отдаёт растеризацию драйверу. Программный конвейер проходит весь конвейер сам, в тех же модулях (xf.cpp, su.cpp, ras.cpp, tx.cpp, tev.cpp, pe.cpp); программные методы блока помечены префиксом Soft. Два пути не делят между собой состояние рендеринга — поэтому конвейер и является переменной конфига, а не выбором на этапе сборки: его можно переключать на лету, и выбор сохраняется в настройках.

НастройкаЗначение
hardware.GFX_PIPELINE0 — шейдерный (OpenGL) бэкенд, 1 — программный конвейер. Читается при запуске.
gxpipelineКоманда отладчика / JDI: показывает активный конвейер или переключает его (gxpipeline soft, gxpipeline shader). Переключение вступает в силу со следующего кадра и сохраняется в настройках.
Gekko --PI FIFO--> CP --команды--> XF(soft) --> SU(soft) --> RAS(soft) --> TEV(soft) --> PE(soft)
                                                              ^            ^
                                                      TX(soft, TMEM)      |
                                                                          v
                                                          EFB-память --(блок копирования)--> XFB
                                                                                            |
                                                                                    vi.cpp выводит его

Блоки

XF — трансформация

Высокоуровневая трансформация вершины, а не интерпретатор микрокода XF: умножения на матрицы геометрии и текстур, объединение с проекцией, освещение двух каналов и генерация текстурных координат (обычная, цветовая и двойная трансформация). Затем низ конвейера делит на однородную компоненту и отображает результат через регистры viewport в экранное пространство: пиксели EFB с началом в левом верхнем углу, 24-битная глубина и 1/w для перспективной коррекции растеризаторов.

SU — setup

Сборка примитивов и ступень setup. Точки, линии, полосы, веера и квады Flipper становятся треугольниками, и каждый треугольник получает запись, по которой идёт растеризатор: ограничивающий прямоугольник, три коэффициента рёбер и плоскость интерполяции каждого атрибута. Параметры с перспективной коррекцией хранятся плоскостями значение/w рядом с плоскостью 1/w — то самое деление, которое аппаратура делает в центрах пикселей.

RAS — обход квадами

Растеризаторы обходят примитив как аппаратура: по сетке квадов 2×2 пикселя, по одному кваду за шаг, с 12-битной маской покрытия (три подвыборки на пиксель) и правилом top-left на общих рёбрах. Затеняются только пиксели с покрытой подвыборкой — в центре пикселя или в одной из его покрытых подвыборок. Позиции подвыборок задают регистры GEN_MSLOC0..3.

TX — настоящая TMEM

32 банка по 16K × 16 бит, две половины по 512 КБ. Команды TX_LOADBLOCK0..3 и TX_LOADTLUT0/1 заливают в неё тайлы и палитры из основной памяти, кэшируемые изображения подтягиваются через кэш тегов в той же памяти, а сэмплер выполняет расчёт LOD, операции clamp / repeat / mirror и фильтрацию: все форматы текселей, включая индексированные через TLUT, билинейные S/T-интерполяции с 6-битными дробями и трилинейное смешивание.

TEV — комбайн

Datapath ступеней, выполняемый на каждую затенённую выборку: до 16 ступеней комбинирования над файлом цветовых регистров, константы K ревизии B, режимы сравнения альфы, окружение Z-текстуры, блок тумана и финальная альфа-функция.

PE — EFB и XFB

Настоящий массив памяти EFB, адресуемый как окно CPU у аппаратуры (цветовое слово пикселя (x, y) лежит по адресу y * 1024 + x, бит 22 адреса выбирает плоскость Z). Он выполняет Z-тест, смешивание и логические операции с масками записи, а также работу блока копирования: display-копию, превращающую прямоугольник в упакованный YUV 4:2:2 XFB в основной памяти, texture-копию в тайловые форматы текстур и очистку, которую может запросить копия.

Что он рисует

Картинки ниже отрисованы модульными тестами и публикуются в отчёте тестов. Первая — сцена, которую программный конвейер нарисовал в том порядке, в каком её отправила бы игра: квад на весь экран с градиентом цвета (интерполяция по четырём углам цветового растеризатора), треугольник с интерполяцией цветов вершин, красный квад, который ближе треугольника — блок Z отбрасывает выборки за ним — и квад, тексели которого читаются из TMEM.

Сцена, отрисованная программным конвейером GFX

Вторая — тот же кадр после GXCopyDisp: блок копирования превратил прямоугольник EFB в упакованный YUV 4:2:2 в основной памяти, и это тот XFB, декодированный обратно в RGB. Хрома каждой пары пикселей усредняется при переходе к 4:2:2, поэтому на границах двух прямоугольников видно смешение хромы.

XFB, записанный блоком копирования, декодированный в RGB

Тесты работают через аппаратный API, а не через бэкенд

testing/gfx_soft_test.cpp программирует конвейер так, как программируют консоль: регистровое пространство XF (матрица геометрии, объединение с проекцией и регистры viewport — ровно те, что пишут GXSetProjection и GXSetViewport), bypass-пространство регистров (общие регистры GEN, привязки текстур растеризатора, команды загрузки текстур, окружения ступеней TEV и состояние пиксельного движка) и вершины в объектном пространстве. Читается обратно собственный вывод аппаратуры: память EFB пиксельного движка и XFB, записанный блоком копирования. Ни одного вызова OpenGL — программный конвейер вообще не открывает GL-контекст.

cd scripts/VS2026
MSBuild pureikyubu_test.vcxproj -p:Configuration=Debug -p:Platform=x64
vstest.console.exe x64/Debug/pureikyubu_test.dll /Tests:Soft_

Чего пока нет

Реализовано

Трансформация и viewport XF, setup (плоскости и рёбра, отсечение, zfreeze), обход квадами с 12-битными масками покрытия и scissor, перспективно-корректная интерполяция цветов и текстурных координат, расчёт LOD и точечная / билинейная / трилинейная фильтрация из TMEM (все форматы текселей, TLUT, CMPR), 16-ступенчатый TEV с константами K, окружение Z-текстуры, туман и альфа-функция, Z-тест / смешивание / логические операции / маски записи / константная альфа в EFB, а также очистка, display-копия (XFB) и texture-копия блока копирования.

Не реализовано (пока)

Косвенное (bump) текстурирование TEV; анизотропная фильтрация и уточнения diag_lod / lodclamp; режимы компенсации движения round и field_predict; сглаженный EFB (12-битная маска покрытия выбирает выборку для затенения, но EFB хранит один цвет на пиксель) и типы пикселей EFB кроме RGB8 — поэтому же не применяется матрица дизеринга: для RGB8 она единичная; коэффициенты вертикального фильтра display-копии и режимы копирования YUV/4:2:0; и окно EFB для CPU (Cpu2Efb).

Документация

Wiki: программный GFX

Вся страница: блоки, спецификации, по которым написан каждый из них, осознанные решения модели и то, чего ещё нет.

Wiki: GFX

Шейдерный бэкенд: вершинная и фрагментная программы, текстуры, косвенное текстурирование и команды JDI.

Спецификации

Аппаратные страницы, по которым написан программный конвейер: gfx-xf.md, gfx-su.md, gfx-ras0/1/2.md, gfx-tc.md, gfx-tf.md, gfx-tev.md, gfx-pe.md и video-interface.md.