Программирование одного или нескольких потоков (Direct3D 9)
В этом разделе описаны шейдеры, которые можно использовать для программируемой модели потока.
Использование потоков
DirectX 8 представила понятие потока для привязки данных к входным регистрам для использования шейдерами. Поток — это универсальный массив данных компонентов, где каждый компонент состоит из одного или нескольких элементов, представляющих одну сущность, например положение, обычный, цвет и т. д. Потоки позволяют графическим чипам выполнять прямой доступ к памяти из нескольких буферов вершин параллельно, а также обеспечить более естественное сопоставление из данных приложения. Они также обеспечивают тривиальную многотекстовую и многострадную. Подумайте об этом следующим образом:
- Вершина состоит из n потоков.
- Поток состоит из элементов m.
- Элемент — [положение, цвет, обычная, координата текстуры].
Метод IDirect3Device9::SetStreamSource привязывает буфер вершин к потоку данных устройства, создавая связь между данными вершин и одним из нескольких портов потока данных, которые передают примитивные функции обработки. Фактические ссылки на потоковые данные не происходят до тех пор, пока не вызывается метод рисования, например IDirect3Device9::D rawPrimitive.
Сопоставление входных элементов вершины с регистрами входных данных вершин для программируемых шейдеров вершин определяется в объявлении шейдера, но входные элементы вершин не имеют определенной семантики об их использовании. Интерпретация входных элементов вершин запрограммирована с помощью инструкций шейдера. Функция шейдера вершин определяется массивом инструкций, применяемых к каждой вершине. Выходные регистры вершин явно записываются, используя инструкции в функции шейдера.
Однако для этого обсуждения следует менее беспокоиться о семантической сопоставлении элементов с регистрами и более обеспокоенными причиной использования потоков и решением проблемы с помощью потоков. Основное преимущество потоков заключается в том, что они удаляют затраты на данные вершин, ранее связанные с мультитекстированием. Прежде чем потоки, пользователю пришлось либо дублировать наборы данных вершин для обработки одного и многотекстового дела без неиспользуемых элементов данных, либо содержать элементы данных, которые не будут использоваться, за исключением случая с несколькими текстами.
Ниже приведен пример использования двух наборов данных вершин, один для одной текстуры и один для многотекстовой обработки.
struct CUSTOMVERTEX_TEX1
{
FLOAT x, y, z; // The untransformed position for the vertex
DWORD diffColor; // The vertex diffuse color
DWORD specColor; // The vertex specular color
float tu_1, tv_1; // Texture coordinates for a single texture
};
struct CUSTOMVERTEX_TEX2
{
FLOAT x, y, z; // The untransformed position for the vertex
DWORD diffColor; // The vertex diffuse color
DWORD specColor; // The vertex specular color
float tu_2, tv_2; // Texture coordinates for multitexturing
};
Альтернативой является один элемент вершины, содержащий оба набора координат текстуры.
struct CUSTOMVERTEX_TEX2
{
FLOAT x, y, z; // The untransformed position for the vertex
DWORD diffColor; // The vertex diffuse color
DWORD specColor; // The vertex specular color
float tu_1, tv_1; // Texture coordinates for a single texture
float tu_2, tv_2; // Texture coordinates for multitexturing
};
При использовании этих данных вершин только одна копия позиций и цветных данных переносятся в память за счет переноса обоих наборов координат текстуры для отрисовки даже в одном регистре текстуры.
Теперь, когда компромисс четкий, потоки обеспечивают элегантное исправление этой дилеммы. Ниже приведен набор определений вершин для поддержки трех потоков: один с позицией и цветом, один с первым набором координат текстуры и один со вторым набором координат текстуры.
// Multistream vertex
// Stream 0, pos, diffuse, specular
struct POSCOLORVERTEX
{
FLOAT x, y, z;
DWORD diffColor, specColor;
};
#define D3DFVF_POSCOLORVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_SPECULAR)
// Stream 1, tex coord 0
struct TEXC0VERTEX
{
FLOAT tu1, tv1;
};
#define D3DFVF_TEXC0VERTEX (D3DFVF_TEX1)
// Stream 2, tex coord 1
struct TEXC1VERTEX
{
FLOAT tu2, tv2;
};
#define D3DFVF_TEXC1VERTEX (D3DFVF_TEX0)
Объявление вершин будет следующим образом:
// Multitexture - multistream
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 0},
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 1},
D3DDECL_END()
};
Теперь создайте объект объявления вершин и задайте его, как показано ниже.
LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration(dwDecl3, &m_pVertexDeclaration);
m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);
Примеры сочетаний
Один поток диффузный цвет
Объявление вершин и параметры потока для диффузной отрисовки цвета будут выглядеть следующим образом:
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0 ,
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
D3DDECL_END()
};
m_pd3dDevice->SetStreamSource(0, m_pVBVertexShader0, 0,
sizeof(CUSTOMVERTEX));
m_pd3dDevice->SetStreamSource(1, NULL, 0, 0);
m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);
Два потока с цветом и текстурой
Объявление вершин и параметры потока для отрисовки одной текстуры будут выглядеть следующим образом:
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 0},
D3DDECL_END()
};
m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0,
sizeof(POSCOLORVERTEX));
m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0,
sizeof(TEXC0VERTEX));
m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);
Два потока с цветом и двумя текстурами
Объявление вершин и параметры потока для отрисовки двух текстур с несколькими текстурами будут выглядеть следующим образом:
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_COLOR, 1},
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 0},
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
D3DDECLUSAGE_TEXCOORD, 1},
D3DDECL_END()
};
m_pd3dDevice->SetStreamSource(0, m_pVBPosColor, 0,
sizeof(POSCOLORVERTEX));
m_pd3dDevice->SetStreamSource(1, m_pVBTexC0, 0,
sizeof(TEXC0VERTEX));
m_pd3dDevice->SetStreamSource(2, m_pVBTexC1, 0,
sizeof(TEXC1VERTEX));
В каждом случае достаточно следующего вызова IDirect3Device9::D rawPrimitive.
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);
Это показывает гибкость потоков при решении проблемы дублирования и избыточности данных через шину (т. е. от использования пропускной способности).
Связанные разделы