DX 10 post, part 2 – API changes
DX 10 post, part 1 – Infrastructure
DX 10 post, part 2 – API changes
DX 10 post, part 3 – New hardware features
Я так считаю, что пока DX11 не вышел, посты про DX10 еще считаются актуальными. Посему радуйтесь, я буду вам рассказывать про изменения вышедшего год назад API.
Тем более, не спится.
В DX10 очень много изменений в API, наверное, это одни из самых больших изменений за историю D3D.
Большинство из них направлено на то, чтобы сделать интерфейс более общим и уменьшить количество работы драйверу и рантайму, некоторые необходимы для новых фич.
Например, буфер вершин, буфер индексов и буфер констант – это один и тот же ID3D10Buffer, так как это набор байтов в памяти, и API к ним один и тот же. При создании буфера все равно нужно указывать, как он будет использоваться, так что все это в некотором смысле остается type safe.
Для ресурсов введены отдельные объекты для биндинга к пайплайну, так называемые resource views. Т.е. сначала создаешь текстуру как объект в памяти, а потом ее resource view как инпут для шейдера или как render target, и уже с этим view зовешь PSSetShaderResources (вместо SetTexture) и OMSetRenderTargets (вместо SetRenderTarget). Разумеется, у одного ресурса view может быть несколько.
Это нужно для общности подхода с новыми фичами – typeless resources, то есть ресурс, который при создании не имеет четко определенного типа (например, DXGI_FORMAT_R32G32B32_TYPELESS), тип выбирается во время создания view (например, DXGI_FORMAT_R32G32B32_UINT или DXGI_FORMAT_R32G32B32_FLOAT), и выбора элемента/слайса из texture array/volume texture.
Все 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.
Set*ShaderConstant заменены на Constant Buffers – группы констант, устанавливающихся за раз. Т.е. создаешь буфер на n констант, который можно локать и записывать как и обычный буфер, и биндишь его к шейдеру начиная с какого-то слота. Помните, в D3D9 рекомендовали устанвливать константы не по одной, а блоками подряд для перформанса? Это более формализованный способ делать то же самое. То есть, разделяешь константы на несколько групп по частоте обновления – per-object, per-material, per-pass, per-scene, для каждой заводишь свой Constant Buffer, и обновляешь их по мере необходимости. Таким образом, разделение на блоки апдейтов констант, необходимое для перформанса, происходит автоматически, ну и вообще, дает драйверу высокоуровневую картину и больше возможностей для оптимизации.
Для полноты – с VertexDeclaration произошла в общем-то похожая фигня. Теперь Input Layout (бывшый Vertex Decl) требует при создании Shader Input Signature, т.е. списка input-параметров шейдера. Полученный объект можно использовать как Vertex Declaration с любым шейдером, имеющим такой же список input-параметров. В D3D9 Vertex Declaration устанавливался независимо от шейдера при рендере, и поэтому драйверам приходилось серьезно модифицировать сетап при смене vdecl. Сейчас vdecl жестко привязан к инпуту шейдера, что опять же позволяет предвычислять это все заранее.
Ну, основная идея понятна, да? Как можно больше выносить в создание-инициализацию, как можно больше предвычислять и заранее валидировать, чтобы при рендере делать как можно меньше, и таким образом уменьшать DIP cost.
Кроме этого, из изменений стоит отметить, что шейдеры больше нельзя писать на асме, нужно пользоваться HLSL. Хотя ассемблер для shader model 4.x есть и можно смотреть результат компиляции шейдеров в него, больше нет возможности получить бинарный код шейдера из текста асма (то что делали psa.exe/vsa.exe). Отреверсинженирить бинарный код, впрочем, никто не мешает :)
Чтобы было легче портировать код шейдеров, компилятор умеет компилять HLSL-шейдеры старых версий (SM2.0, SM 3.0) в SM4.0. В новом HLSL, кстати, добавили атрибуты для хинтов компилятору – unroll для лупов и выбор dynamic vs static branching для условных переходов.
И, конечно, мы всегда радуемся компиляторным багам, присылайте нам их всегда.
По-большому счету, пожалуй, и все. Осталось рассказать про самое вкусное – сами новые хардверные фичи, в следующий раз дойдем и до них. Глядишь к DX11 успею.
Pingback: highly professional scums » Blog Archive » DX10 post, part 1 - Infrastructure()
Pingback: highly professional scums » Blog Archive » DX 10 post, part 3 - New hardware features()