Differences between Direct3D 9 and Direct3D 10:

The following page provides a basic outline of key differences between Direct3D 9 and Direct3D 10. This documentation is preliminary and incomplete; it serves as a prelude to a comprehensive Direct3D 9 to Direct3D 10 porting and cross-platform development guide which will be provided in a future release of the DirectX SDK. The outline below provides some initial insight to assist developers with Direct3D 9 experience to explore and relate to Direct3D 10.

 

Overview of the Major Structural Changes in Direct3D 10

The general API usage for Direct3D 10 is in its basic structure not unlike previous versions of Direct3D. The process of rendering using the Direct3D 10 device is structurally similar to Direct3D 9 where you follow the flow of a pipeline:

Set a vertex stream source,
Set input layout (Vertex Stream Decl in Direct3D 9 speak),
Declare primitive topology,
Set textures,
Set state objects,
Set shaders,
Draw

Where the Draw command is the call that ties the operations of the Set calls together and the ordering of Sets is arbitrary so long as they occur before the Draw. The major differences in the Direct3D 10 API design are as follows:

  • Removal of Fixed Function
  • Removal of CAPS bits - Direct3D 10's base feature set is guaranteed
  • Stricter management of
    • resource access,
    • device state,
    • shader constants,
    • shader linkage (inputs and outputs to shaders) between stages
  • API entry point names changed to reflect the virtualization of GPU memory (Map() instead of Lock()).
  • Provision of a Debug Layer which may be added to the device at creation time
  • Primitive Topology broken out from the Draw Call, this is now an explicit device state
  • Constant buffer slots on the device instead of explicit constants
  • Shader authoring is done entirely in HLSL. The HLSL compiler now resides in the primary Direct3D 10 DLL.
  • New programmable stage - the Geometry Shader (GS)
  • Shorter stage names in the API
    • VS - Vertex Shader, GS - Geometry Shader, PS - Pixel Shader
  • Removal of Begin Scene / End Scene
  • Common 2D, focus and adapter-management functionality refactored into a new component: DXGI

We will discuss many of the items listed above in more detail during the rest of this document.

Removal of Fixed Function

It is sometimes surprising that even in a Direct3D 9 engine that fully exploits the programmable pipeline, there remains a number of areas that depend on the Fixed Function (FF) pipeline. The most common areas are usually related to screen space aligned rendering for UI. It is for this reason that you are likely to need to build a FF emulation shader or set of shaders which provide the necessary replacement behaviors.

This documentation contains a whitepaper containing replacement shader sources for the most common FF behaviors.

Fixed Function EMU Sample

Note that some Fixed Function pixel behavior including Alpha Test has been moved into shaders.

Device Object Creation Time Validation

The Direct3D 10 pipeline has been redesigned from the ground up in hardware and software with a primary intention of reducing the amount of CPU overhead (at Draw time) to a minimum. To reduce costs, all types of device data have been assigned an object with explicit creation methods provided by the device itself. This design point enables strict data validation to occur at object creation time and not during the Draw call as it often does with Direct3D 9.

Engine Abstractions / Separation

Applications, including Games, that wish to support both Direct3D 9 and Direct3D 10 at the same time need to have the rendering layers abstracted from the rest of the code base. There are many ways to achieve this but key to all of them is the design of the abstraction layer for the lower level Direct3D device. All systems should communicate to the hardware through the common layer which is designed to provide GPU resource and low level type management.

Direct Removal of Direct3D 9 Dependencies

When porting large, previously tested code bases, it is important to minimize the amount of code changes to those which are absolutely necessary to preserve previously tested behaviors in the code. Best practices include clearly documenting where items change using comments. It's often useful to have a commenting standard for this work which enables quick navigation through the code base and provides measures to determine the amount of code still needing updating.

The following is an example list of standard single line / start block comments which could be used for this work.

// D3D10 REMOVED
Use this where lines / blocks of code are removed
// D3D10 NEEDS UPDATE

It helps to added additional notes to the NEED UPDATE comment that suggests what work / new API should be used for later visits to the code for behavior conversion.

Heavy use of assert(false) should also be used where \\ D3D10 NEEDS UPDATE occurs to ensure you do not unknowingly run errant code

// D3D10 CHANGED
Areas where major changes have occurred should be kept for future reference but commented out
// D3D10 END
End code block qualifier

For multiple lines of source you should use the C style /* */ comments too but add the relevant start / end comments around these areas.

Tricks for Quickly Resolving Application Build Issues

Overriding Direct3D 9 Types

It may be useful to insert a high level header file containing type definitions / overrides for Direct3D 9 base types which are no longer supported by the Direct3D 10 headers. This will help you minimize the amount of changes in the code and interfaces where there is a direct mapping from a Direct3D 9 type to the newly defined Direct3D 10 type. This approach is also useful for keeping code behaviors together in one source file. In this case, it is a good idea to define version neutral / generally named types which describe common constructs used for rendering yet span both Direct3D 9 and Direct3D 10 APIs. For example:

#if defined(D3D9) typedef IDirect3DIndexBuffer9 IDirect3DIndexBuffer; typedef IDirect3DVertexBuffer9 IDirect3DVertexBuffer; #else //D3D10 typedef ID3D10Buffer IDirect3DIndexBuffer; typedef ID3D10Buffer IDirect3DVertexBuffer #endif 

Other Direct3D 10 specific examples of this include:

typedef ID3D10TextureCube IDirect3DCubeTexture; typedef ID3D10Texture3D IDirect3DVolumeTexture; typedef D3D10_VIEWPORT D3DVIEWPORT; typedef ID3D10VertexShader IDirect3DVertexShader; typedef ID3D10PixelShader IDirect3DPixelShader; 

Resolving Link Issues

We advise that you should develop Direct3D 10 and Windows Vista applications using the latest version of Microsoft Visual Studio (version 8 at the time of writing). However, it is possible to build a Windows Vista application which depends on Direct3D 10 using the earlier 2003 version of Visual Studio. Direct3D 10 is a Windows Vista platform component which has dependencies (as with the Server 2003 SP1 platform SDK) on the following lib: BufferOverflowU.lib is needed to solve any buffer_security check linker issues.

Simulating Device CAPs

Many applications including games contain areas of code which depend on device CAPS data being available. This can be worked around by overriding enumeration and forcing device CAPS to sensible values, you should aim to re-visit the areas where there are dependencies on CAPS later for full removal of CAPS where possible.

Driving the Direct3D 10 API

The next section of this article focuses on specific areas for driving the Direct3D 10 API and notes ways to deal with the changes in behavior that Direct3D 10 brings.

Resource Creation

The Direct3D 10 API has designed resources as generic buffer types which have specific bind flags according to the planned usage. This design point was chosen to facilitate near ubiquitous access of resources in the Pipeline for scenarios such as rendering to a vertex buffer then instantly drawing the results without interrupting the CPU. The following example demonstrates allocation of vertex buffers and index buffer where you can see that the resource description only differs by the GPU resource bind flags.

The Direct3D 10 API has provided texture helper methods for explicitly creating texture type resources but as you can imagine, these are really helper functions.

CreateTexture2D()
CreateTextureCube()
CreateTexture3D()

When targeting Direct3D 10, you are likely to want to allocate more items during resource creation time than you are used to with Direct3D 9. This will become most apparent with the creation of Render Target buffers and Textures where you need to also create a view for accessing the buffer and setting the resource on the device.

Tutorial 1: Direct3D 10 Basics

Views

A view is a specifically typed, interface to data stored in a pixel buffer. A resource can have several views allocated on it at once and this feature is highlighted in the Single Pass Render to Cubemap sample contained in this SDK.

Programmers Guide page on Resource Access

CubeMap Sample

Static versus Dynamic Resource Access

For best performance, applications should partition their data use in terms of the static vs dynamic nature of the data. Direct3D 10 has been designed to take advantage of this approach and as such, the access rules for resources have been tightened up over Direct3D 9. For static resources you should ideally create it as IMMUTABLE and populate the resource with its data during creation time.

Direct3D 10 Effects

Use of the Direct3D 10 Effects system is outside the scope of this article. The system has been written to take full advantage of the architectural benefits that Direct3D 10 provides. See the following section more detail on its use:

[ Link unavailable at this time ]

HLSL without Effects

The Direct3D 10 Shader pipeline may be driven without the use of the Direct3D 10 Effects system. Note that in this instance, all constant buffer, shader, sampler and texture binding must be managed by the application itself. See the sample link and following sections of this document for more detail:

Direct3D 10 without Effects sample

Shader Compilation

The Direct3D 10 HLSL compiler brings enhancements to the HLSL language definition and therefore has the ability to operate in 2 modes. For complete support of Direct3D 9 style intrinsics and semantics, compilation should be invoked using the COMPATIBILITY MODE flag which can be specified on a per compile basis.

More information about compatibility mode can be found here:HLSL Compatibility mode

The Direct3D 10 shader model 4.0 specific HLSL language semantics and intrinsics can be found at the link referenced below. Major changes in syntax from Direct3D 9 HLSL to take the most notice of are in the area of texture access. The new syntax is the only form supported by the compiler outside of compatibility mode.

[ Link unavailable at this time ]

Creation of Shader Resources

The creation of compiled shader instances outside of the Direct3D 10 Effects system is done in a very similar manner to Direct3D 9 however, in Direct3D 10, it is important to keep the Shader Input signature around for later use. The signature is returned by default as part of the shader blob but may be extracted to reduce the memory requirements if needed.

[ Link unavailable at this time ]

Shader Reflection Layer Interface

The shader reflection layer is the interface by which information about the shader requirements may be obtained. This is particularly useful when creating Input Assembly linkages (see below) where you may need to traverse the shader input requirements to ensure you are supplying the correct input structure to the shader. You can create an instance of the reflection layer interface at the same time as creating an instance of a compiled shader.

Input Assembler Layouts - Vertex Shader / Input Stream Linkage

The Input Assembler (IA) replaces the Direct3D 9 style Vertex Stream Declaration and its description structure is very similar in form. The main difference that the IA brings is that the IA layout object created must directly map to a specific format of shader input signature. The mapping object created to link the input stream to shader may be used across any number of shaders where the shader input signature matches that of the shader used to create the Input Layout.

To best drive the pipeline with static data, you should consider the permutations of input stream format to possible shader input signatures and create the IA layout object instances as early as is possible and reuse them where possible.

Impact of Shader Dead Code Removal

The following section details a significant difference between Direct3D 9 and Direct3D 10 that is likely to require careful handling in your engine code. Shaders which contain conditional expressions often have certain code paths removed as part of the compilation process. In Direct3D 9, any input elements that match the associated code removed are also from their shader input structure. This no longer occurs in Direct3D 10 as the intention is to allow the same Input Signature to be used across all possible permutations of the shader code without invoking the rather costly change of Input Layout. This has an impact on the engine when handling large shaders and creating Input Layouts. Elements which are removed by dead code optimizations in the compiler must still be declared in the Input Structure. The following example demonstrates this situation:

Vertex Shader Input Structure Example

typedef struct { float4 pos: SV_Position; float2 uv1 : Texcoord1; float2 uv2 : Texcoord2; * } VS_INPUT; 

* Direct3D 9 dead code removal would remove the declaration in the shader due to conditional dead code removal

float4x4 g_WorldViewProjMtx; bool g_bLightMapped = false; VS_INPUT main(VS_INPUT i) { VS_INPUT o; o.pos = mul( i.pos, g_ WorldViewProjMtx); o.uv1 = i.uv1; if ( g_bLightMap ) { o.uv2 = i.uv2; } } 

In the above example, under Direct3D 9, the uv2 element would be removed due to dead code optimizations in the compiler. Under Direct3D 10, the dead code will still be removed but the shader Input Assembler layout requires the definition of the input data to exist. The shader reflection layer provides the means to handle this situation in a generic manner whereby you can traverse the Shader Input requirements and ensure that you provide a full description of the Input Stream to shader signature mapping. The following code snippet demonstrates use of the reflection layer to determine shader requirements during Input Assembler layout specification:

// This example helper function checks the Shader Signature to see if // it expects a particular semantic // The HardwareShader_t input structure contains a pointer to a // previously acquired shader reflection layer as follows: // // typedef struct HardwareShader_s // { // ID3D10Blob *pShaderBlobwithSignature; // ID3D10ShaderReflection *IReflect; // // // DEBUG - helps to keep the shader filename around for debugging // #ifdef _DEBUG // char filename[MAX_PATH]; // #endif // // } HardwareShader_t; // bool CheckShaderSignatureExpectations(const HardwareShader_t *pShader, const LPCSTR pSemantic) { D3D10_SHADER_DESC shaderDesc; D3D10_SIGNATURE_PARAMETER_DESC paramDesc; Assert(pShader); Assert(pSemantic); Assert(pShader->IReflect); pShader->IReflect->GetDesc(&shaderDesc); for (UINT k=0; k<shaderDesc.InputParameters; k++) { pShader->IReflect->GetInputParameterDesc( k, &paramDesc); if (wcscmp( pSemantic, paramDesc.SemanticName)==0) return true; } return false; } 

State Object Creation

When porting engine code, it may help to initially use a default set of state objects and disable all Direct3D 9 device render state / texture state setting. This will cause rendering artifacts but is the quickest way to get things up and running. You can later construct a state object management system which can use a compound key to enable maximum reuse of the number of state objects being used.

Porting Content

Texture Formats

The format names for Direct3D 9s DXT* texture formats have been changed and are now part of the DXGI headers. The DXGI component is responsible for allocating and managing buffer data Direct3D 10 provides wrapper functions for ease of use purposes. As such DXGI has the responsibility of defining the supported color format types in Direct3D 10. Mapping of Direct3D 9 format names are listed in the following chart:

Link to Chart which should be added as another page in the docs:

Direct3D 9 Texture/Vertex/Index Format Equivalent Direct3D 10 Format.
D3DFMT_UNKNOWN DXGI_FORMAT_UNKNOWN
D3DFMT_R8G8B8 Not available
D3DFMT_A8R8G8B8 Not available
D3DFMT_X8R8G8B8 Not available
D3DFMT_R5G6B5 Not available
D3DFMT_X1R5G5B5 Not available
D3DFMT_A1R5G5B5 Not available
D3DFMT_A4R4G4B4 Not available
D3DFMT_R3G3B2 Not available
D3DFMT_A8 DXGI_FORMAT_A8_UNORM
D3DFMT_A8R3G3B2 Not available
D3DFMT_X4R4G4B4 Not available
D3DFMT_A2B10G10R10 DXGI_FORMAT_R10G10B10A2
D3DFMT_A8B8G8R8 DXGI_FORMAT_R8G8B8A8_UNORM & DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
D3DFMT_X8B8G8R8 Not available
D3DFMT_G16R16 DXGI_FORMAT_R16G16_UNORM
D3DFMT_A2R10G10B10 Not available
D3DFMT_A16B16G16R16 DXGI_FORMAT_R16G16B16A16_UNORM
D3DFMT_A8P8 Not available
D3DFMT_P8 Not available
D3DFMT_L8 DXGI_FORMAT_R8_UNORM Note: Use .r swizzle in shader to duplicate red to other components to get D3D9 behavior.
D3DFMT_A8L8 Not available
D3DFMT_A4L4 Not available
D3DFMT_V8U8 DXGI_FORMAT_R8G8_SNORM
D3DFMT_L6V5U5 Not available
D3DFMT_X8L8V8U8 Not available
D3DFMT_Q8W8V8U8 DXGI_FORMAT_R8G8B8A8_SNORM
D3DFMT_V16U16 DXGI_FORMAT_R16G16_SNORM
D3DFMT_W11V11U10 Not available
D3DFMT_A2W10V10U10 Not available
D3DFMT_UYVY Not available
D3DFMT_R8G8_B8G8 DXGI_FORMAT_G8R8_G8B8_UNORM (in DX9 the data was scaled up by 255.0f, but this can be handled in shader code).
D3DFMT_YUY2 Not available
D3DFMT_G8R8_G8B8 DXGI_FORMAT_R8G8_B8G8_UNORM (in DX9 the data was scaled up by 255.0f, but this can be handled in shader code).
D3DFMT_DXT1 DXGI_FORMAT_BC1_UNORM & DXGI_FORMAT_BC1_UNORM_SRGB
D3DFMT_DXT2 DXGI_FORMAT_BC1_UNORM & DXGI_FORMAT_BC1_UNORM_SRGB Note: DXT1 and DXT2 are the same from an API/hardware perspective... only difference was premultiplied alpha, which can be tracked by an application and doesn't need a separate format.
D3DFMT_DXT3 DXGI_FORMAT_BC2_UNORM & DXGI_FORMAT_BC2_UNORM_SRGB
D3DFMT_DXT4 DXGI_FORMAT_BC2_UNORM & DXGI_FORMAT_BC2_UNORM_SRGB Note: DXT3 and DXT4 are the same from an API/hardware perspective... only difference was premultiplied alpha, which can be tracked by an application and doesn't need a separate format.
D3DFMT_DXT5 DXGI_FORMAT_BC3_UNORM & DXGI_FORMAT_BC3_UNORM_SRGB
D3DFMT_D16 & D3DFMT_D16_LOCKABLE DXGI_FORMAT_D16_UNORM
D3DFMT_D32 Not available
D3DFMT_D15S1 Not available
D3DFMT_D24S8 Not available
D3DFMT_D24X8 Not available
D3DFMT_D24X4S4 Not available
D3DFMT_D16 DXGI_FORMAT_D16_UNORM
D3DFMT_D32F_LOCKABLE DXGI_FORMAT_D32_FLOAT
D3DFMT_D24FS8 Not available
D3DFMT_S1D15 Not available
D3DFMT_S8D24 DXGI_FORMAT_D24_UNORM_S8_UINT
D3DFMT_X8D24 Not available
D3DFMT_X4S4D24 Not available
D3DFMT_L16 DXGI_FORMAT_R16_UNORM Note: Use .r swizzle in shader to duplicate red to other components to get D3D9 behavior.
D3DFMT_INDEX16 DXGI_FORMAT_R16_UINT
D3DFMT_INDEX32 DXGI_FORMAT_R32_UINT
D3DFMT_Q16W16V16U16 DXGI_FORMAT_R16G16B16A16_SNORM
D3DFMT_MULTI2_ARGB8 Not available
D3DFMT_R16F DXGI_FORMAT_R16_FLOAT
D3DFMT_G16R16F DXGI_FORMAT_R16G16_FLOAT
D3DFMT_A16B16G16R16F DXGI_FORMAT_R16G16B16A16_FLOAT
D3DFMT_R32F DXGI_FORMAT_R32_FLOAT
D3DFMT_G32R32F DXGI_FORMAT_R32G32_FLOAT
D3DFMT_A32B32G32R32F DXGI_FORMAT_R32G32B32A32_FLOAT
D3DFMT_CxV8U8 Not available
D3DDECLTYPE_FLOAT1 DXGI_FORMAT_R32_FLOAT
D3DDECLTYPE_FLOAT2 DXGI_FORMAT_R32G32_FLOAT
D3DDECLTYPE_FLOAT3 DXGI_FORMAT_R32G32B32_FLOAT
D3DDECLTYPE_FLOAT4 DXGI_FORMAT_R32G32B32A32_FLOAT
D3DDECLTYPED3DCOLOR Not available
D3DDECLTYPE_UBYTE4 DXGI_FORMAT_R8G8B8A8_UINT Note: Shader gets UINT values, but if Direct3D 9 style integral floats are needed (0.0f, 1.0f... 255.f), UINT can just be converted to float32 in shader.
D3DDECLTYPE_SHORT2 DXGI_FORMAT_R16G16_SINT Note: Shader gets SINT values, but if Direct3D 9 style integral floats are needed, SINT can just be converted to float32 in shader.
D3DDECLTYPE_SHORT4 DXGI_FORMAT_R16G16B16A16_SINT Note: Shader gets SINT values, but if Direct3D 9 style integral floats are needed, SINT can just be converted to float32 in shader.
D3DDECLTYPE_UBYTE4N DXGI_FORMAT_R8G8B8A8_UNORM
D3DDECLTYPE_SHORT2N DXGI_FORMAT_R16G16_SNORM
D3DDECLTYPE_SHORT4N DXGI_FORMAT_R16G16B16A16_SNORM
D3DDECLTYPE_USHORT2N DXGI_FORMAT_R16G16_UNORM
D3DDECLTYPE_USHORT4N DXGI_FORMAT_R16G16B16A16_UNORM
D3DDECLTYPE_UDEC3 Not available
D3DDECLTYPE_DEC3N Not available
D3DDECLTYPE_FLOAT16_2 DXGI_FORMAT_R16G16_FLOAT
D3DDECLTYPE_FLOAT16_4 DXGI_FORMAT_R16G16B16A16_FLOAT

For uncompressed formats, DXGI has limited the support for arbitrary pixel format patterns; all uncompressed formats must be of type RGBA. This may require swizzling of existing assets pixel formats which we advise that you compute as an offline pre-process pass where possible.

Porting Shaders

Direct3D 10 Shaders are Authored in HLSL

Direct3D 10 limits the use of assembly language to that of debugging purposes only, therefore any hand written assembly shaders used in Direct3D 9 will need to be converted to HLSL.

Shader Signatures and linkage

We have already discussed the requirements for Input Assembly linkages to Vertex shader input signatures earlier in this document (see above). Note that the Direct3D 10 runtimes have also tightened the requirements for stage to stage linkage between shaders. This change will affect shader sources where the binding between stages may not have been fully described under Direct3D 9. For example:

VS_OUTPUT PS_INPUT float4 pos : SV_POSITION; float4 pos : SV_POSITION; float4 uv1 : TEXCOORD1; float4 uv1 : TEXCOORD1; float4x3 tangentSp : TEXCOORD2; float4 tangent : TEXCOORD2; * float4 Color : TEXCOORD6; float4 color : TEXCOORD6; 

* Broken VS - PS Linkage - even though the Pixel Shader may not be interested in the full matrix, the linkage must specify the full float4x3.

Note, the linkage semantics between stages must match exactly however, the target stages inputs may be a prefix of the values being output. In the example above, the pixel shader could have position and texcoord1 as the only inputs, but it could not have the position and texcoord2 as the only inputs due to the ordering constraints.

HLSL Shader Stage linkages

Linkages between shaders may occur at any of the following points in the pipeline:

Input Assembler to Vertex Shader
Vertex to Pixel Shader
Vertex to Geometry Shader
Geometry Shader to Pixel Shader
Geometry Shader to Stream Out

Constant Buffers

For ease of porting content from Direct3D 9 an initial approach to constant management outside of the Effects system might involve the creation of a single constant buffer containing all the required constants. It is important for performance to order constants into buffers by the expected frequency of update. This organization will reduce the amount of redundant constant sets to a minimum.

[ Link unavailable at this time ]

Additional Direct3D 10 Differences to Watch For

Integers as Input

In Direct3D 9, there was no real hardware support for integer data types, however in Direct3D 10 hardware supports explicit integer types. If you have floating point data in your vertex buffer, then you must have a float input. Otherwise the int will be the bit pattern representation of the floating point value. Integer inputs are also not allowed as input to a pixel shader unless the value is marked constinterp which is due to the interpolation for the pixel shader not being an integer interpolation.

Reference Counting Behavior Changes

Unlike previous Direct3D versions, the various Set functions will not hold a reference to the devices objects. This means that the application must ensure that it holds a reference on the object for as long as it would like that object to be bound to the pipeline. When the ref count of the object drops to zero, then the object will be unbound from the pipeline as it is destroyed. This style of reference holding is also known as weak-reference holding, so therefore each bind location on the Device object holds a weak-reference to the interface/ object. Unless explicitly mentioned otherwise, this behavior should be assumed for all Set methods. Whenever destruction of an object causes a bind point to be NULLed out, the Debug Layer will issue a warning. Note, calls to device Get methods such as OMGetRenderTargets() will increase the reference count of objects being returned.

Test Cooperative Level

The functionality of the D3D9 API IDirect3DDevice9::TestCooperativeLevel is analogous to setting the DXGI_PRESENT_TEST flag in the Flags parameter of IDXGISwapChain::Present.

'Or.......... > Work' 카테고리의 다른 글

Scalform - GFx [Prologue]  (1) 2010.08.09
Shader Tree  (0) 2009.11.05
Scene Graph Rendering  (0) 2009.08.27
kd-tree Introduction  (0) 2009.08.27
Grass Rendering  (0) 2009.08.27
,