суббота, 7 июля 2012 г.

Render Target Compression

Некоторое время назад я заинтересовался компрессией текстур на лету. Типично в DXT (BC в D3D 10/11) формат преобразуются только статические текстуры, подготовленные художниками. Однако повсеместно в кишках графического движка семплируются и текстуры, которые являются динамическими render target-ами, и если кол-во выборок в пиксельном шейдере значительно, имеет смысл попробовать после отрисовки сжать такую текстуру (закрыв глаза на деградацию качества), и семплировать в сжатом формате.

В DirectX 10.0 такой возможности ещё не было, но до неё был буквально один шаг! Direct3D 10.0 позволял копировать в памяти только ресуры с одинаковым typeless форматом, например текстуру формата R32G32B32_FLOAT в текстуру формата R32G32B32_UINT. Direct3D 10.1 снял это ограничение и стало возможным копировать ресурсы с разными форматами при условии, что их размеры в памяти совпадают. Подробнее описано в разделе MSDN Format Conversion Using Direct3D 10.1.

Базой для моей работы послужило демо Хумуса GPU Texture Compression. Основной механизм преобразования формата прост: изображение из render target перебрасывается в текстуру формата R32G32_UINT, пиксельный шейдер используется для упаковки данных таким образом, чтобы после копирования в block compressed формат они интерпретировались как блоки 4x4, готовые к декомпрессии. Мне необходимо было сжать одноканальную текстуру формата R8_UNORM, поэтому в качестве целевого целесообразнее всего использовать формат BC4 (появился в DirectX 10.0). Разобравшись с демкой Хумуса, я немного оптимизировал её: например, он вычисляет текстурные координаты для gather выборок в вершинном шейдере, хотя для этого можно использовать опциональные целые смещения. Для ремаппинга в индексы блока 4x4 можно использовать индексируемый массив вместо замысловатого тернарного оператора (кол-во инструкций в шейдере уменьшается). Наконец используется статическая картинка большого размера, когда отличить сжатое изображение от оригинала невозможно - я же использовал динамический рендер в текстуру и последующее её сжатие.


Также разобравшись, как GPU осуществляет декомпрессию формата BC4, я написал экспериментальный шейдер, который в процессе упаковки пытается подобрать оптимальные индексы из таблицы, которую GPU строит по двум опорным значениям. Увы, качество сжатия едва ли отличимо, а вот кол-во инструкций в шейдере получилось на порядок больше. Впрочем, это была лишь попытка понять, как работает декомпрессор.

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

Ссылка на демо с исходным кодом на Google Code:
renderbc.zip

Комментариев нет:

Отправить комментарий