Mapping FVF Codes to a Direct3D 9 Declaration
This table maps FVF codes to a D3DVERTEXELEMENT9 structure.
FVF |
Data type |
Usage |
Usage index |
D3DFVF_XYZ |
D3DDECLTYPE_FLOAT3 |
D3DDECLUSAGE_POSITION |
0 |
D3DFVF_XYZRHW |
D3DDECLTYPE_FLOAT4 |
D3DDECLUSAGE_POSITIONT |
0 |
D3DFVF_XYZW |
D3DDECLTYPE_FLOAT4 |
D3DDECLUSAGE_POSITION |
0 |
D3DFVF_XYZB5 and D3DFVF_LASTBETA_UBYTE4 |
D3DVSDT_FLOAT3, D3DVSDT_FLOAT4, D3DVSDT_UBYTE4 |
D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES |
0 |
D3DFVF_XYZB5 and D3DFVF_LASTBETA_D3DCOLOR |
D3DVSDT_FLOAT3, D3DVSDT_FLOAT4, D3DVSDT_D3DCOLOR |
D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES |
0 |
D3DFVF_XYZB5 |
D3DDECLTYPE_FLOAT3, D3DDECLTYPE_FLOAT4, D3DDECLTYPE_FLOAT1 |
D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES |
0 |
D3DFVF_XYZBn (n=1..4) |
D3DDECLTYPE_FLOAT3, D3DDECLTYPE_FLOATn |
D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT |
0 |
D3DFVF_XYZBn (n=1..4) and D3DFVF_LASTBETA_UBYTE4 |
D3DDECLTYPE_FLOAT3, D3DDECLTYPE_FLOAT(n-1), D3DDECLTYPE_UBYTE4 |
D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES |
0 |
D3DFVF_XYZBn (n=1..4) and D3DFVF_LASTBETA_D3DCOLOR |
D3DDECLTYPE_FLOAT3, D3DDECLTYPE_FLOAT(n-1), D3DDECLTYPE_D3DCOLOR |
D3DDECLUSAGE_POSITION, D3DDECLUSAGE_BLENDWEIGHT, D3DDECLUSAGE_BLENDINDICES |
0 |
D3DFVF_NORMAL |
D3DDECLTYPE_FLOAT3 |
D3DDECLUSAGE_NORMAL |
0 |
D3DFVF_PSIZE |
D3DDECLTYPE_FLOAT1 |
D3DDECLUSAGE_PSIZE |
0 |
D3DFVF_DIFFUSE |
D3DDECLTYPE_D3DCOLOR |
D3DDECLUSAGE_COLOR |
0 |
D3DFVF_SPECULAR |
D3DDECLTYPE_D3DCOLOR |
D3DDECLUSAGE_COLOR |
1 |
D3DFVF_TEXCOORDSIZEm(n) |
D3DDECLTYPE_FLOATm |
D3DDECLUSAGE_TEXCOORD |
n |
Vertex Declarations with D3DDECLUSAGE_POSITIONT
The presence of a vertex element with (D3DUSAGE_POSITIONT, 0) is used to indicate to the device that the vertex data coming in has already been through vertex processing (like an FVF with D3DFVF_XYZRHW bit set). At draw time, if the currently set declaration has an element with the (D3DUSAGE_POSITIONT, 0) semantic, the entire vertex processing is skipped (just as if an FVF with D3DFVF_XYZRHW bit has been set).
There are some restrictions on vertex declarations with (D3DDECLUSAGE_POSITIONT, 0):
- Only stream zero can be used in such declarations.
- Vertex elements must be sorted by increasing stream offset.
- The stream offset must be DWORD aligned.
- The same (Usage, Usage Index) pair should be listed only once.
- Only the D3DDECLMETHOD_DEFAULT method can be used.
- Other vertex elements cannot have the (D3DDECLUSAGE_POSITION, 0) semantic.
In addition, there are some restrictions on such declaration related to the device driver version. These restrictions are in effect because Direct3D sends such declarations directly to the driver without doing any conversion.
Vertex Declarations without D3DDECLUSAGE_POSITIONT
Runtime validates the creation of declarations. Following are the general rules for what declarations are legal.
- All vertex elements for a stream must be consecutive and sorted by offset.
- The stream offset must be DWORD aligned.
- The same (Usage, Usage Index) pair should be listed only once.
- If the D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET is set then
- Multiple vertex elements can share the same offset in a stream.
- The vertex elements can all be of different types which can be of different sizes.
- The vertex elements can overlap arbitrarily. For example, one element can start at a location of a stream that is, at the same time, in the middle of another element.
- Vertex elements are allowed to have stream offset in any order.
- The number of vertex elements cannot be greater than 64.
- UsageIndex should be in the range [0-15].
- Declaration, used with the DrawPrimitive API, should not have vertex elements other than D3DDECLMETHOD_DEFAULT, D3DDECLMETHOD_LOOKUPPRESAMPLED, or D3DDECLMETHOD_LOOKUP.
- Declaration, which contains D3DDECLMETHOD_LOOKUP or LOOKUPPRESAMPLED, should be used only with the programmable vertex pipeline.
- Declaration, used with the DrawRectPatch/DrawTriPatch API, cannot have vertex elements with D3DDECLMETHOD_LOOKUPPRESAMPLED or D3DDECLMETHOD_LOOKUP.
- Declaration should have only one element with D3DDECLMETHOD_LOOKUP or D3DDECLMETHOD_LOOKUPPRESAMPLED method.
- Declaration with D3DDECLMETHOD_LOOKUP or D3DDECLMETHOD_LOOKUPPRESAMPLED should not have elements other than D3DDECLMETHOD_DEFAULT, because displacement mapping is done only for N-patches.
- Vertex elements with D3DDECLMETHOD_LOOKUP or D3DDECLMETHOD_LOOKUPPRESAMPLED can only be used with the (D3DDECLUSAGE_SAMPLE, n) semantic and vice versa.
- If a vertex element with D3DDECLMETHOD_LOOKUP method has a stream index and offset of an already existing vertex element, this vertex element should have the same data type.
- A vertex element with the D3DDECLMETHOD_LOOKUP method should have the D3DDECLTYPE_FLOAT2/3/4 data type
- Vertex elements with types D3DDECLMETHOD_CROSSUV, D3DDECLMETHOD_PARTIALU, and D3DDECLMETHOD_PARTIALV should have an offset of a vertex element with a compatible data type.
- A vertex element with the method D3DDECLMETHOD_UV or D3DDECLMETHOD_LOOKUPPRESAMPLED must have type D3DDECLTYPE_UNUSED, stream index zero, and stream offset zero.
- Declarations with methods D3DDECLMETHOD_UV, D3DDECLMETHOD_PARTIALU, and D3DDECLMETHOD_PARTIALV can only be used with DrawRectPatch.
- Usage D3DDECLUSAGE_TESSFACTOR should be used only with data type D3DDECLTYPE_FLOAT1 and usage index 0.
- When a declaration is used for tessellation (DrawRectPatch, DrawTriPatch, N-patches), data type must be less than or equal to D3DDECLTYPE_SHORT4.
- Declarations that contain methods requiring certain device capabilities (for example, displacement mapping, RT-patches) can only be created if the device supports them.
- A vertex declaration used to draw points and lines cannot have methods other than D3DDECLMETHOD_DEFAULT.
- The declarations that can be created also depends on the driver capabilities.
Driver Considerations
Pre-Direct3D 9 Drivers
- The input declaration must be translatable to a valid FVF (have the same order of vertex elements and their data types).
- Gaps in texture coordinates are not allowed. This means that if there is a vertex element with (D3DDECLUSAGE_TEXCOORD, n) then there also should be a vertex element with (D3DDECLUSAGE_TEXCOORD, n-1).
Direct3D 9 Drivers without Pixel Shader Version 3 Support
- The input declaration must be translatable to a valid FVF (have the same order of vertex elements and their data types).
- Gaps in texture coordinates are allowed.
Direct3D 9 Drivers with Pixel Shader Version 3 Support
More general declarations are allowed.
- Vertex elements can be in arbitrary order and can have any data types.
- Multiple vertex elements can share the same stream offset and be of a different type in the same time if D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET is set by device.
Vertex Declaration Usage with the Programmable Vertex Pipeline
- At draw time, Direct3D looks for the same "usage - usage index" combination in the current vertex declaration and the current vertex shader function. When the combination is found, the register from shader function DCL is used as the destination for the vertex element.
- When a vertex element in the current vertex declaration has a usage which is not found in the current vertex shader, that vertex element is ignored.
- When using a vertex shaders version less than 2.0, all semantics mentioned in the shader code need to be present in the declaration bound at draw time. When using vertex shaders 2.0 and above, this restriction that allows applications to use different vertex declarations with the same vertex shader does not exist. This is useful when a vertex shader reads input data based on static conditions. Vertex shader registers not initialized because of this will have undefined values.
There are additional restrictions when using with hardware vertex processing on a DirectX 8 driver:
- Vertex elements cannot overlap or share the same offset.
- Data types are limited to what the DirectX 8 driver can understand.
The CreateVertexDeclaration might fail if the declaration provided cannot be converted to a DirectX 8-style declaration. For a mixed mode device, this failure will happen at Draw* time because that is the only time it can be known whether this shader is being used with hardware or software vertex processing.
Vertex Declaration Usage with the Fixed Function Pipeline
Only declarations that adhere to the following rules can be used:
- There should be no gaps between vertex elements (SKIP was not allowed in a DirectX 8
declaration, which is used for the fixed function pipeline).
- Semantic (D3DDECLUSAGE_POSITION, 0) must be specified and should have D3DDECLTYPE_FLOAT3 data type.
- A vertex element with method D3DDECLMETHOD_UV must specify usage D3DDECLUSAGE_TEXCOORD or D3DDECLUSAGE_BLENDWEIGHT.
- A vertex element with method D3DDECLMETHOD_PARTIALU, _PARTIALV, or _CROSSUV can only be used with D3DDECLUSAGE_POSITION, _NORMAL, _BLENDWEIGHT, or _TEXCOORD, and must use input type D3DDECLTYPE_FLOAT3.
When a declaration is used with hardware vertex processing on a DirectX 8 driver, the Direct3D runtime converts it to a DirectX 8-style declaration with the following rules:
- Vertex elements cannot share the same offset in a stream and they cannot overlap.
- Data type must be less or equal D3DDECLTYPE_SHORT4.
- Only the following methods are allowed: D3DDECLMETHOD_DEFAULT, D3DDECLMETHOD_CROSSUV, and D3DDECLMETHOD_UV
- Mapping between a Direct3D 9 Declaration and a Direct3D 8 Declaration shows which Direct3D 9 semantics could be converted to DirectX 8-style declaration. Usage and UsageIndex are converted to a register value.
- If there are n vertex elements in a declaration and 0 - m (m < n) maps to an FVF (elements described in the Mapping between a Direct3D Declaration and FVF Codes), but m + 1 does not, then:
- If any of m + 2 until n - 1 vertex elements map to FVF/dx8decl, the declaration is invalid.
- The elements 0 to m are converted (by the runtime for DirectX 8 and older drivers, and by the Direct3D 9 drivers) using the Mapping between a Direct3D Declaration and FVF Codes, m + 1, m + 2 until n - 1 become mapped to contiguous texcoord(k), texcoord(k+1), starting from any texcoord in elements 0 - m.
- The data type at a mapped texcoord is assumed to be float[1234] replacing whatever data type the current element contains (but the same size). Therefore, the existing data type can be something that is not in Mapping between a Direct3D Declaration and FVF Codes.
- If k reaches 8, the declaration is invalid for FVF/dx8decl.
- If any mappings to texcoords have occurred, the entire declaration is required to have no elements with generation method other than DEFAULT or the declaration is invalid for FVF/dx8decl.
Using Vertex Declarations with ProcessVertices
A vertex declaration could be used to describe the output of ProcessVertices. Such declaration should adhere to the following rules:
- Only stream 0 must be used.
- Only D3DDECLMETHOD_DEFAULT methods are allowed.
- Only D3DDECLTYPE_FLOATn or D3DDECLTYPE_D3DCOLOR data types can be used.
- Vertex elements cannot share the same offset or overlap with each other.
- Vertex elements with (D3DDECLUSAGE_POSITION, 0) or (D3DDECLUSAGE_POSITIONT,0) are not required.
- Vertex elements with (D3DDECLUSAGE_POSITION, 0) and (D3DDECLUSAGE_POSITIONT,0) cannot be present in the same declaration.
- The current vertex shader must be version 3.0 or higher when such declaration is used.