Programmazione di uno o più flussi (Direct3D 9)
Questa sezione descrive gli shader che possono essere usati per il modello di flusso programmabile.
Uso di flussi
DirectX 8 ha introdotto la nozione di un flusso per associare i dati ai registri di input da usare da shader. Un flusso è una matrice uniforme di dati del componente, in cui ogni componente è costituito da uno o più elementi che rappresentano un'unica entità, ad esempio posizione, normale, colore e così via. I flussi consentono ai chip grafici di eseguire un accesso diretto alla memoria da più buffer vertici in parallelo e forniscono anche un mapping più naturale dai dati dell'applicazione. Abilitano anche la multitexture banale rispetto al multipass. Pensa a questo:
- Un vertice è costituito da n flussi.
- Un flusso è costituito da m elements.
- Un elemento è [posizione, colore, normale, coordinata trama].
Il metodo IDirect3DDevice9::SetStreamSource associa un buffer dei vertici a un flusso di dati del dispositivo, creando un'associazione tra i dati del vertice e una delle diverse porte di flusso di dati che generano le funzioni di elaborazione primitiva. I riferimenti effettivi ai dati del flusso non si verificano finché non viene chiamato un metodo di disegno, ad esempio IDirect3DDevice9::D rawPrimitive.
Il mapping degli elementi del vertice di input ai registri di input dei vertici per i vertex shader programmabili è definito nella dichiarazione shader, ma gli elementi del vertice di input non dispongono di semantiche specifiche sull'uso. L'interpretazione degli elementi del vertice di input è programmata usando le istruzioni del shader. La funzione vertex shader è definita da una matrice di istruzioni applicate a ogni vertice. I registri di output dei vertici vengono scritti in modo esplicito, usando istruzioni nella funzione shader.
Per questa discussione, tuttavia, essere meno interessati al mapping semantico degli elementi ai registri e più interessato al motivo dell'uso dei flussi e del problema risolto tramite flussi. Il vantaggio principale dei flussi è che rimuove i costi dei dati dei vertici precedentemente associati al multitexturing. Prima dei flussi, un utente deve duplicare i set di dati dei vertici per gestire il caso singolo e multitexture senza elementi dati inutilizzati o inserire elementi di dati inutilizzati, ad eccezione del caso multitexture.
Ecco un esempio di uso di due set di dati vertex, uno per una trama singola e una per il multitexturing.
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
};
L'alternativa era quella di avere un singolo elemento vertice che contiene entrambi i set di coordinate della trama.
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
};
Con questi dati di vertice, viene eseguita una sola copia dei dati di posizione e colore in memoria, a spese del trasporto di entrambi i set di coordinate della trama intorno per il rendering anche nel caso di trama singola.
Ora che il compromesso è chiaro, i flussi forniscono una soluzione elegante a questo dilemma. Ecco un set di definizioni di vertice per supportare tre flussi: uno con posizione e colore, uno con il primo set di coordinate della trama e uno con il secondo set di coordinate della trama.
// 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)
La dichiarazione del vertice sarà la seguente:
// 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()
};
Creare ora l'oggetto dichiarazione del vertice e impostarlo come illustrato:
LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration(dwDecl3, &m_pVertexDeclaration);
m_pd3dDevice->SetVertexDeclaration(m_pVertexDeclaration);
Esempi di combinazioni
Colore di diffusione di un flusso
La dichiarazione dei vertici e le impostazioni di flusso per il rendering dei colori diffusi sono simili al seguente:
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);
Due flussi con colore e trama
La dichiarazione del vertice e le impostazioni di flusso per il rendering di trame singole sono simili al seguente:
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);
Due flussi con colore e due trame
La dichiarazione dei vertici e le impostazioni di flusso per il rendering multi-trama a due trame sarà simile al seguente:
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));
In ogni caso, le chiamate IDirect3DDevice9::D rawPrimitive sono sufficienti.
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, NUM_TRIS);
In questo modo viene illustrata la flessibilità dei flussi nella risoluzione del problema della trasmissione dei dati/ridondanza dei dati nel bus, ovvero della larghezza di banda di larghezza di banda.
Argomenti correlati