Чтение пользовательского формата текстуры во фрагментном шейдере

Я создаю эмулятор NES и экспериментирую с идеей разгрузки функциональности (где это необходимо) на GPU. Одна идея, которая поразила меня, - выводить пиксели экрана в буфер в настраиваемом формате таким образом, чтобы кодировать свойства для каждого пикселя, чтобы шейдер мог определять, как их отображать. Это разгрузит довольно много логики / ветвления от одной из самых популярных функций в эмуляторе.

Вот пример того, как может выглядеть кодировка для одного пикселя с использованием 2 байтов на пиксель:

Байт 1 (индексы палитры): bbbb ssss

  • b: Индекс палитры пикселей фона
  • s: Индекс палитры пикселей спрайта

Байт 2 (свойства пикселя): bbss rgbp

  • b: 2-битное значение фонового пикселя
  • s: 2-битное значение пикселя спрайта
  • r: выделить красный
  • g: выделить зеленый
  • b: выделить синий
  • p: приоритет пикселей спрайта

Я относительно новичок в написании шейдеров, поэтому мои первые вопросы: возможно ли это вообще? В проведенном мною исследовании выяснилось, что текстуры должны быть в определенном формате, чтобы считывать информацию о цвете из них в каждом пикселе, а мой собственный двухбайтовый «цветовой» формат даже не представляет цвет в и само по себе. Если это возможно, то какой высокоуровневый подход можно использовать для этого? Я планирую использовать vulkan, но любой подход, который применяется в более общем плане (в отношении шейдеров), приветствуется.


person w.brian    schedule 11.06.2018    source источник


Ответы (1)


Графика изменилась с 2000 года. Шейдеры - это (в основном) произвольные программы, вычисляющие значения. То, что эти значения могут иногда интерпретироваться как цвета, не имеет значения. Шейдеры - это программы; они делают то, что вы от них хотите.

Точно так же текстуры не содержат цветов, если ваш шейдер не интерпретирует их как цвета. Текстуры - это не что иное, как таблицы поиска значений. Опять же, эти значения могут быть цветами, а могут и не быть. Все зависит от того, как ваш шейдер использует эти значения.

Вы можете создавать текстуры, которые используют целочисленные форматы (в отличие от нормализованных целых чисел). Затем вы можете выполнять любые битовые манипуляции в своем шейдере. Ничего из того, что вы описали выше, не было бы особенно сложным для шейдеров.

В вашем случае текстура, вероятно, будет двухканального формата с 8 битами на канал с использованием целочисленных значений без знака. В OpenGL этот формат будет записан GL_RG8UI: красный / зеленый (имя двух каналов), 8 бит на канал и целые числа без знака. OpenGL может называть эти каналы «красным» и «зеленым», но важно то, что ваш шейдер делает с ними, а не то, как они называются.

В Vulkan этот формат обозначается VK_FORMAT_R8G8_UINT: два 8-битных канала беззнаковых целочисленных значений.

Основная проблема, с которой вы столкнетесь, не в формате изображения или шейдере. Это эффективная передача данных в графический процессор.

В OpenGL у вас нет другого выбора, кроме как постоянно передавать данные DMA из доступной для процессора памяти в текстуры, доступные для графического процессора. В Vulkan вам, возможно, не придется этого делать.

Реализации Vulkan могут сказать, что линейные текстуры могут храниться в памяти, доступной как для CPU , так и GPU. От них не требуется это предоставлять, но многие могут это сделать. В таких реализациях нет необходимости в DMA; GPU может напрямую читать то, что написал CPU. Вам все равно придется дважды буферизовать такие изображения (чтобы минимизировать синхронизацию GPU / CPU. Вы пишете в один, пока GPU считывает данные предыдущего кадра), но это должно улучшить производительность по сравнению с версией DMA.

Конечно, вам все равно понадобится кодовый путь для реализаций, где это невозможно.

person Nicol Bolas    schedule 11.06.2018