Direct3D 10

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

Direct3D 10 — набор API функций для взаимодействия с видеокартой; поддерживается аппаратно видеокартами класса NV GeForce 8x00, ATI Radeon 2x00 и выше. Direct3D 10 (D3D10) — компонент интерфейса программирования приложений (англ. API) DirectX 10, 10-я версия Direct3D, преемник Direct3D 9. Direct3D 10 обеспечивает функции для взаимодействия операционной системы и приложений с драйверами видеокарты. Эти функции привязаны к операционной системе в линейке Windows и доступны в Windows Vista и Windows 7 . Частично D3D10 работает на видеокартах уровня Direct3D 9.

Официальная финальная версия вышла 10 ноября 2006 года в составе Windows Vista.


Далее приведены ключевые особенности и отличия от Direct3D версии 9.

Возможности и особенности[править | править исходный текст]

Новая модель драйвера[править | править исходный текст]

В Windows Vista совершенно новая модель драйвера — WDDM (Windows Display Driver Model, ранее называемая LDDM — Longhorn Display Driver Model) — серьезное изменение в модели видеодрайвера со времен появления аппаратного ускорения. В XDDM (Windows XP Display Driver Model) каждый вызов DirectX добавлял указатель команды (токен) в буфер команд в независимом от видеокарты формате. Когда DX Runtime решал, что буфер достаточно заполнен, вызывалась функция драйвера (в режиме ядра), которая получала этот буфер. После этого драйвер разбирал этот буфер и передавал данные видеокарте. То есть никаких функций драйвера в пользовательском режиме не было. Развитие видеокарт и, как следствие, усложнение буфера команд привело к тому, что драйвер стал немыслимо большим и в случае любой ошибки провоцировал BSOD. Также в XDDM у операционной системы нет способов установления приоритета, управления видеопамятью, планирования вызовов DX, что затрудняет разделение видеокарты между несколькими процессами — причина «потери устройства».

В новой модели драйвера сделано разделение между пользовательской и работающей в режиме ядра частью драйвера. Все вызовы DX напрямую идут в пользовательский драйвер, который готовит сразу буфер с содержимым, зависящим от оборудования. Этот буфер передаёт данные в ядро операционной системы, откуда они идут на видеокарту. Таким образом вся тяжёлая работа выполняется в пользовательской части, а в ядре - пересылка собранного буфера в DMA-трансфер видеокарты. Как итог, если пользовательский драйвер упадет, ничего страшного не случится — закроется конкретное приложение (но не BSOD). И у драйвера больше контроля (когда и сколько вызовов функций ядра делать). Также DX Runtime становится совсем тонкий — нет буферов команд, напрямую вызываются функции драйвера. Кроме этого между пользовательскими и ядерными частями есть планировщик заданий, который выбирает какие собранные буфера отправлять видеокарте (разделение GPU на много процессов).

Виртуализация видеопамяти[править | править исходный текст]

Теперь если не хватает видеопамяти, то ресурсы переносятся в системную (откуда могут быть отсвоплены). За счёт наличия у Windows Vista контроля выделения видеопамяти (ранее, у драйвера) можно распределять её более эффективно, чем POOL_MANAGED в XDDM. На данном этапе это работает на программном уровне — планировщик GPU перед передачей DMA-пакета карте загружает все нужные текстуры в видеопамять (умеет подгружать их заранее, пока GPU занят другим и свободна шина). Если приложение полноэкранное, все лишнее из видеопамяти будет перенесено в системную память по мере необходимости; если в оконном режиме, то происходит разделение памяти между текущими процессами. Если требуется гарантировать 100 % наличие ресурса в видеопамяти, то необходимо использовать полноэкранный режим и контроль над размером выделений.

Отсутствие ситуации «потери устройства» (Device Lost)[править | править исходный текст]

В предыдущих версиях по различным причинам мог происходить Device Lost, после чего требовалось загружать все ресурсы в видеопамять заново и производить восстановление объектов. С новой моделью драйвера этой проблемы больше не существует. Возможна ситуация Device Removed, которая означает, что видеокарта была физически удалена из системы или что видеодрайвер был обновлён. Ситуация встречается очень редко.

Убраны списки возможностей (D3D caps)[править | править исходный текст]

В DX10 больше нет капсов, как таковых. Гарантируется наличие всей функциональности, то есть если карта поддерживает DX10, то она обязана поддерживать последнюю версию шейдеров в полном объёме, поддерживать все форматы текстур, все возможные режимы фильтрации, шаблона (stencil) и всего остального. Более того, для DX10 написали спецификацию правил растеризации, то есть теперь картинка на разных видеокартах на одинаковом коде всегда должна быть одинаковой и совпадать с эталонным программным растеризатором. Если это не так, то это баг производителя видеокарты. В дальнейшем функциональность будет расширяться (пакет DX10.1, DX11 и т.д.).

Уменьшено время вызова функций DirectX[править | править исходный текст]

Уменьшено время вызова функций (в том числе DIP) на CPU. По данным презентаций Microsoft можно наблюдать 10x уменьшение времени. Это существенно, так как тяжёлая игра может проводить около 10+ миллисекунд в вызовах DX. Большую часть времени вызова ранее уходило на Runtime и Driver. теперь driver model фактически ничего не делает, а сразу предоставляет исполнение драйверу.

State Objects и Constant Buffers[править | править исходный текст]

Появились State Objects — объекты, которые можно предварительно собрать при создании и потом быстро устанавливать на видеокарте. Добавлены Constant Buffers, позволяющие более эффективно выставлять константы шейдеров.

Использование объектов-состояний[править | править исходный текст]

Все Set*State заменены на объекты-состояния (State Objects). Состояния разделены по нескольким группам:

  • Rasterizer State — fill mode, cull mode, depth bias, multisample, scissor и т. д.
  • Blend State — alpha blend, color write mask, blend op и т. д.
  • Depth State — depth func, stencil func и т. д.
  • SamplerState — tex filtering, clamping и т. д.

Состояния для каждой группы ставятся целиком, а не каждый по отдельности, как в D3D9. Для каждой группы можно создать State Object, которому при создании указывается полный набор состояний группы, и «установить» можно только его. Создание State Object — дорогая и медленная операция и должна вызываться редко. Мотивация этого нововведения — такой API позволяет драйверу сгенерировать набор команд видеокарте заранее (при создании State Object) и не генерировать его каждый раз во время рендера при вызовах Set*State.

Буфера и биндинг[править | править исходный текст]

Для основных типов данных (вершин, индексов, констант) введён единый буфер — ID3D10Buffer — набор байтов в памяти. Type safe обеспечивается за счёт указания при создании содержимого буфера. Для ресурсов введены отдельные объекты для биндинга к конвейеру — resource views. То есть сначала создаем текстуру как объект в памяти, а потом её resource view как инпут для шейдера или как render target, и уже с этим view вызываем PSSetShaderResources (вместо SetTexture) и OMSetRenderTargets (вместо SetRenderTarget). Стоит отметить, что у одного ресурса может быть несколько resource views.

Такой принцип позволяет работать обобщенно. Существуют «бестипные» (typeless) ресурсы, то есть ресурсы, которые не имеют определённого типа (не указан при создании) — например, DXGI_FORMAT_R32G32B32_TYPELESS. Тип таких ресурсов выбирается во время создания view (например, DXGI_FORMAT_R32G32B32_UINT или DXGI_FORMAT_R32G32B32_FLOAT) и выбора элемента/слайса из массива текстур/объёмной текстуры.

Использование буферов констант[править | править исходный текст]

Set*ShaderConstant заменены на Constant Buffers — группы констант (буфер на n констант), устанавливающихся за раз. Группу можно локать и записывать как обычный буфер. Биндинг к шейдеру производится начиная с некоторого слота.

Таким образом использование констант сводится к разделению их на несколько групп по частоте обновления (per-object, per-material, per-pass, per-scene) и созданию для каждой группы Constant Buffer. Помимо дополнительной производительности такой подход даёт драйверу высокоуровневую картину — больше возможностей для оптимизации.

Параметры шейдеров[править | править исходный текст]

VertexDeclaration заменён на Input Layout. Он требует при создании Shader Input Signature, то есть список input-параметров шейдера. Созданный объект можно использовать как Vertex Declaration с любым шейдером, имеющим такой же список input-параметров. В D3D9 Vertex Declaration устанавливался независимо от шейдера при рендере и поэтому драйверам приходилось серьёзно модифицировать сетап при смене vdecl. Сейчас vdecl жёстко привязан ко входу шейдера, что позволяет драйверу предвычислять все заранее.

Убраны asm-шейдеры[править | править исходный текст]

Шейдеры больше нельзя писать на ассемблере — нужно пользоваться HLSL. Хотя ассемблер для shader model 4.x есть и можно смотреть результат компиляции шейдеров в него, но больше нет возможности получить бинарный код шейдера из текста ассемблера (то что делали psa.exe/vsa.exe). Отреверсинженирить бинарный код, впрочем, никто не мешает.

Компилятор HLSL 4.0[править | править исходный текст]

Чтобы было легче портировать код шейдеров, компилятор умеет компилировать HLSL-шейдеры старых версий (SM2.0, SM 3.0) в SM4.0. В новом HLSL добавили атрибуты для хинтов компилятору — размотку циклов и выбор dynamic vs static branching для условных переходов.

Эволюционные изменения в шейдерах[править | править исходный текст]

В Shader Model 4 добавлены целочисленные инструкции и битовые операции (можно считать в честном fixed point и передавать булевые флажки), убрано ограничение на количество инструкций (но очень длинный шейдер может упереться в ограничение по времени выполнения пакета на GPU, до 10 сек)

Геометрические шейдеры (Geometry Shader)[править | править исходный текст]

Геометрический шейдер — дополнительный шейдер между вершинным (Vertex Shader) и пиксельным (Pixel Shader), который может генерировать примитивы. На вход ему подается примитив с информацией о соседях, на выход — можно сгенерировать несколько (не фиксированное число).

Stream Out[править | править исходный текст]

Это возможность записывать результат работы Vertex Shader/Geometry Shader в память. Например, кешировать обработку геометрии или вообще геометрию, созданную GS. Можно считать итеративные эффекты, типа Cloth/Water. То есть теперь можно напрямую трансформить и записывать геометрию на GPU, не только рисовать пиксели в Render Target. Также есть возможность читать в шейдере из буфера в памяти по индексу, то есть иметь достаточно большую read-only shared memory. NV например предлагает там константы анимации хранить для инстансинга.

Уменьшение количества draw calls и переключений состояний[править | править исходный текст]

Появились массивы текстур, то есть контейнер одинаковых по размеру и формату текстур, из которого шейдер может выбирать по индексу (в DX10.1 — можно и cubemap arrays). Это тот самый atlasing done right — раньше когда в одной текстуре хранили несколько разных, приходилось беспокоиться за мип-левелы, оставлять зазор между текстурами и т. д. Теперь не надо. В шейдер приходят primitive/instance id, в зависимости от instance ID можно использовать другой набор текстур/координат/whatever. Ожидается, что dynamic branch в шейдере быстрый (лучше, чем в DX9-hardware), поэтому можно передавать Material ID и бранчиться по материалам в шейдере. То есть, в теории, можно за один вызов генерировать большое количество геометрии с разными параметрами, текстурами и вообще материалами. На практике, больше всего мешает таки стоимость dynamic branch и проблем, с ним связанных (вычисление градиентов текстурных координат). А остальное — вполне можно и нужно использовать.

Multi-sampling antialiasing features[править | править исходный текст]

Небольшая фича, ради одной которой можно переходить на DX10. Теперь в шейдере можно читать каждый MSAA-семпл отдельно, то есть писать свой собственный AA-фильтр, вменяемо семплить при процессинге и вообще использовать MSAA RT как текстуру. Ещё и AlphaToCoverage вместе с этим теперь официально присутствует. В D3D10.1 это можно делать и с depth textures.

Поддержка depth textures[править | править исходный текст]

Теперь depth buffer можно использовать как текстуру. Можно сказать, чтобы при семплинге сравнивал со значением и делал фильтрацию соседей, можно достать чистый depth value. Можно даже stencil value достать.

Другие интересные возможности[править | править исходный текст]

  • есть рендер в volume texture
  • в DX10.1 можно скопировать из обычной текстуры в сжатую на GPU
  • есть настоящий conditional render, то есть возможность выкидывать целый draw call по результатам работы GPU асинхронно (можно делать occlusion culling полноценно)

Дополнительные факты[править | править исходный текст]

Операционная система Windows XP не поддерживает DX10. Причина в том, что перенос новой драйверной модели невозможен — требуется слишком много изменений в ядре операционной системы. Если же переносить только набор новых функциональных возможностей DX10, то тоже возникают проблемы: виртуализацию и шедулинг невозможно осуществить в старой модели драйвера, перенос аппаратных возможностей — слишком большой объём работы для Microsoft и IHV.

Ссылки[править | править исходный текст]

См. также[править | править исходный текст]