Программирование одного или нескольких потоков (Direct3D 9)
В этом разделе описываются шейдеры, которые можно использовать для программируемой потоковой модели.
Использование потоков
В DirectX 8 введено понятие потока для привязки данных к входным регистрам для использования шейдерами. Поток — это универсальный массив данных компонентов, где каждый компонент состоит из одного или нескольких элементов, представляющих одну сущность, например положение, нормали, цвет и т. д. Потоки позволяют графическим микросхемам осуществлять прямой доступ к памяти из нескольких буферов вершин параллельно, а также обеспечивают более естественное сопоставление из данных приложения. Они также обеспечивают тривиальный мультитекстовый и многопроходный режим. Подумайте об этом следующим образом:
- Вершина состоит из n потоков.
- Поток состоит из m элементов.
- Элемент имеет значение [положение, цвет, нормали, координата текстуры].
Метод IDirect3DDevice9::SetStreamSource привязывает буфер вершин к потоку данных устройства, создавая связь между данными вершин и одним из нескольких портов потока данных, которые передают примитивные функции обработки. Фактические ссылки на потоковые данные не возникают до вызова метода рисования, например IDirect3DDevice9::D rawPrimitive.
Сопоставление входных элементов вершин с входными регистрами вершин для программируемых шейдеров вершин определяется в объявлении шейдера, но элементы входных вершин не имеют определенной семантики об их использовании. Интерпретация входных элементов вершин запрограммирована с помощью инструкций шейдера. Функция шейдера вершин определяется массивом инструкций, применяемых к каждой вершине. Регистры выходных данных вершин явно записываются в , используя инструкции в функции шейдера.
Для этого обсуждения, однако, следует меньше беспокоиться о семантическом сопоставлении элементов с регистрами и о причине использования потоков и о том, какая проблема решается с помощью потоков. Main преимущество потоков заключается в том, что они удаляют затраты на данные вершин, ранее связанные с многотекстовой обработкой. До потоков пользователь должен был либо дублировать наборы данных вершин для обработки одного и многотекстового регистра без неиспользуемых элементов данных, либо нести элементы данных, которые не будут использоваться, за исключением многотекстового случая.
Ниже приведен пример использования двух наборов данных вершин: один для одной текстуры, а второй для многотекстового анализа.
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));
В каждом случае достаточно следующего вызова IDirect3DDevice9::D rawPrimitive .
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);
Это показывает гибкость потоков при решении проблемы дублирования данных и избыточной передачи данных через шину (то есть излишние пропускной способности).
Связанные темы