Программирование с Render to VB (R2VB) Обзор материала •Основы R2VB •Изменения в DX9 API •Хитрые приемы и оптимизации Основы R2VB •Идея: использовать текстуры и рендертекстуры как входныe данные вершинного конвеера VB IB VB VS Отрисовка в вершинный буфер RS PS Raster Backend Tex Render Target Depth/Stencil Отрисовка в текстуру Приемущества R2VB метода •Быстрота операций •На Х1900: 8 верш. АЛУ, 48 пиксел. АЛУ •Более совершенные динамические переходы в пиксельном шейдере •Очень быстрый доступ к текстурам •Гибкость задания данных •Все форматы текстур включая с компрессией •Использование текстур как больших буферов констант •Похоже на унифицированную архитектуру будущего Проверка на поддержку R2VB •Используется специальный Four-CC код •MAKEFOURCC('R','2','V','B') •Только для проверки, не для создания ресурсов bool supportsR2VB = false; if (d3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE, (D3DFORMAT) MAKEFOURCC('R','2','V','B')) == D3D_OK) { supportsR2VB = true; } Использование текстур как VB •С точки зрения GPU текстуры и VB – массивы в видео памяти •Теоретически можно установить указатель потока вершин на текстуру •Не любая текстура может быть подана на вход вершинного конвеера •«Swizzle» текстур не используется в VB •Необходим механизм задания замещения вершинных данных данными текстуры •В DX9 нет встроеных возможностей Интерпретация текстурных данных •Проблема со «swizzle» решается легко – при использовании D3DUSAGE_DMAP флага он отключатся •Линеаризация данных 0 3 4 8 0 1 2 3 4 11 5 6 7 8 9 10 11 Форматы •Соответствие текстурных и вершинных форматов Texture format Vertex declaration type D3DFMT_R32F D3DDECLTYPE_FLOAT1 D3DFMT_G32R32F D3DDECLTYPE_FLOAT2 D3DFMT_A32B32G32R32F D3DDECLTYPE_FLOAT4 D3DFMT_G16R16F D3DDECLTYPE_FLOAT16_2 D3DFMT_A16B16G16R16F D3DDECLTYPE_FLOAT16_4 D3DFMT_G16R16 D3DDECLTYPE_SHORT2 D3DDECLTYPE_SHORT2N D3DDECLTYPE_USHORT2N D3DFMT_A16B16G16R16 D3DDECLTYPE_SHORT4 D3DDECLTYPE_SHORT4N D3DDECLTYPE_USHORT4N D3DFMT_A8R8G8B8 D3DDECLTYPE_D3DCOLOR D3DDECLTYPE_UBYTE4 (BGRA) D3DDECLTYPE_UBYTE4N (BGRA) Продвинутая интерпретация текстурных данных •Нет необходимости использовать 1:1 соответствие текселей к вершинам •Пример 1 •2 пикселя на вершину – чередование позиций и нормалей Pos Norm Pos Norm ... D3DFMT_A32B32G32R32F D3DVERTEXELEMENT9 dwDecl[] = { {0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, {1, 0, /* ... other data */ }, D3DDECL_END() }; Продвинутая интерпретация текстурных данных •Нет необходимости использовать 1:1 соответствие текселей к вершинам •Пример 2 •1 пиксел на 4 вершины – одновременный вывод значений для 4 вершин квада Pixel 0 (FP32x4) Pixel 1 (FP32x4) ... D3DFMT_A32B32G32R32F D3DVERTEXELEMENT9 dwDecl[] = { {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD0, 0}, {1, 0, /* ... other data */ }, D3DDECL_END() }; Продвинутая интерпретация текстурных данных •Возможно даже интерпретировать текстуру как другой тип данных •Пример •Чтение FP32 как 4 байта – например для выявления «FP specials» U8 U8 U8 U8 Pixel 0 (FP32) Pixel 1 (FP32) ... D3DFMT_R32F D3DVERTEXELEMENT9 dwDecl[] = { {0, 0, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD0, 0}, {1, 0, /* ... other data */ }, D3DDECL_END() }; Создание R2VB текстур •Создается как обычная текстура или рендер-текстура •Используется D3DUSAGE_DMAP флаг dev->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET | D3DUSAGE_DMAP, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &d3drt, NULL); •Текстура работает как обычно «Улучшение» DX9 API •Нет возможности подменить VB текстурой в видео памяти через DX9 API •IDirect3DVertexBuffer9 и IDirect3DTexture9 – несовместимые интерфейсы API •Реальные указатели на данные сокрыты в глубине «runtime» и драйвера •Единственные неиспользуемые текстуры видимые вершинным процессором •D3DDDMAPSAMPLER • Доступен на всех ATI DX9 картах •D3DVERTEXTEXTURESAMPLER[0..3] • Доступны только он SM 3.0 картах «Улучшение» DX9 API •Стандартный вершинный конвеер Stream 0 VB … Stream N VB Textures DMAP VS VTF 0 … VTF 3 «Улучшение» DX9 API •Вершинный конвеер с R2VB •Отображение данных из DMAP в поток 0 Stream 0 VB … Stream N VB Textures DMAP VS VTF 0 … VTF 3 Отображение текстур в потоки •Не все потоки должны подменяться •Можно перемешивать VB и текстуры •Подмена указателей происходит в драйвере •«Runtime» ничего об этом не знает •Работает с отладочной версией «runtime» •Инструкции о подмене посылаются специальными R2VB маркерами через D3DRS_POINTSIZE рендер-стейт •Используется специальный диапазон значений Формат R2VB маркера F cmd F 0 – disable/enable 1 – set mapping F data F 0 F F 0 – disable, 1 – enable F 1 F F smp strm Stream # 0 – override with DMAP sampler 1 – override with VTF0 sampler 2 – override with VTF1 sampler 3 – override with VTF2 sampler 4 – override with VTF3 sampler 5 – disable override Вспомогательные функции •Всё в файле atir2vb.h из ATI SDK #define #define #define #define #define #define R2VB_VSMP_OVR_DMAP R2VB_VSMP_OVR_VTX0 R2VB_VSMP_OVR_VTX1 R2VB_VSMP_OVR_VTX2 R2VB_VSMP_OVR_VTX3 R2VB_VSMP_OVR_DIS 0 1 2 3 4 5 DWORD r2vbGlbEnable_Set(BOOL ena); DWORD r2vbVStrm2SmpMap_Set(DWORD str, DWORD smp); Пример использования R2VB •Поток 0 из VB, поток 1 из текстуры // Enable render to vertex buffer extension dev->SetRenderState(D3DRS_POINTSIZE, r2vbGlbEnable_Set(TRUE)); // Setup stream 0 – regular VB data dev->SetStreamSource(0, staticVertexBuffer, 0, 2 * sizeof(float)) // Setup stream 1 – R2VB data dev->SetTexture(D3DDMAPSAMPLER, renderTarget); dev->SetRenderState(D3DRS_POINTSIZE, r2vbVStrm2SmpMap_Set(1, R2VB_VSMP_OVR_DMAP)); // Setup stream 1 – dummy VB dev->SetStreamSource(1, dummy, 0, 4 * sizeof(float)) // Draw ... dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, nVertices, 0, nPrimitives); // Restore stream 1 to regular vertex buffer mode dev->SetRenderState(D3DRS_POINTSIZE, r2vbVStrm2SmpMap_Set(1, R2VB_VSMP_OVR_DIS)); dev->SetTexture(D3DDMAPSAMPLER, NULL); // Disable render to vertex buffer extension dev->SetRenderState(D3DRS_POINTSIZE, r2vbGlbEnable_Set(FALSE)); Особенности использования R2VB •Необходимо задать подменяемый буфер с помощью SetStreamSource •При отладочной версией «runtime» должен быть полного размера •Для обычной версии «runtime» буфер может быть любого размера (даже 1 байт) •Сэмплер не может быть соединен больше чем с одним потоком •Предыдущее отображение будет отменено •Не забудьте отключить отображение и глобальное R2VB включение «Хитрые» приёмы для SM 2.x •Только одна текстура доступна на Radeon 9500-Х850 •VTF только для SM 3.0 карт •Решение: чередование разных данных (позиция, нормаль и т.д.) •Вывод соответствующего значения пиксела из пиксельного шейдера •Отдельный проход чередующий данные •Упаковка данных «Хитрые» приёмы для SM 2.x •Упаковка нормали в вектор позиции •Используем .W для хранения •Точность около 7 бит (используется мантисса FP32 представления) •Упаковка •4 инструкции pos.w = dot(floor(normal*127.5+127.5), float3(1/256.0,1,256.0)); •Распаковка •3 инструкции normal = frac(pos.w * float3(1,1/256.0,1/65536.0)) * 2 - 1; Оптимизации R2VB •Пользуйтесь параллельностью пиксельного процессора •Расчет и вывод 4-х скаляных значений как один FP32x4 вектор •Используйте наименьшие форматы текстур •D3DFMT_A16B16G16R16(F) – 2 такта •D3DFMT_A32B32G32R32F – 4 такта •Используйте MRT для уменьшения кол-ва проходов Использование R2VB •Модификация геометрии •Карты смещения •Генерация геометрии на GPU •Тесселляция •Физика на GPU •IK, вода и т.д. •Расчет сталкновений •Сортировка частиц •И многое другое... Вопросы