4.2 Initializing Direct3D

4.2 Initializing Direct3D

The following subsections show how to initialize Direct3D. Our process of initializing Direct3D can be broken down into the following steps:

  1. Describe the characteristics of the swap chain we are going to create by filling out an instance of the DXGI_SWAP_CHAIN_DESC structure.

  2. Create the ID3D10Device and IDXGISwapChain interfaces using the D3D10CreateDeviceAndSwapChain function.

  3. Create a render target view to the swap chain’s back buffer.

  4. Create the depth/stencil buffer and its associated depth/stencil view.

  5. Bind the render target view and depth/stencil view to the output merger stage of the rendering pipeline so that they can be used by Direct3D.

  6. Set the viewport.

4.2.1 Describe the Swap Chain

Initializing Direct3D begins by filling out an instance of the DXGI_SWAP_CHAIN_DESC structure, which describes the characteristics of the swap chain we are going to create. This structure is defined as follows:

 
    
1 typedef struct DXGI_SWAP_CHAIN_DESC {
2 DXGI_MODE_DESC BufferDesc;
3 DXGI_SAMPLE_DESC SampleDesc;
4 DXGI_USAGE BufferUsage;
5 UINT BufferCount;
6 HWND OutputWindow;
7 BOOL Windowed;
8 DXGI_SWAP_EFFECT SwapEffect;
9 UINT Flags;
10 } DXGI_SWAP_CHAIN_DESC;

 

The DXGI_MODE_DESC type is another structure, defined as:
 
      
1 typedef struct DXGI_MODE_DESC
2 {
3 UINT Width; // desired back buffer width
4   UINT Height; // desired back buffer height
5 DXGI_RATIONAL RefreshRate; // display mode refresh rate
6 DXGI_FORMAT Format; // back buffer pixel format
7 DXGI_MODE_SCANLINE_ORDER ScanlineOrdering; // display scanline mode
8 DXGI_MODE_SCALING Scaling; // display scaling mode
9 } DXGI_MODE_DESC;

Note 

In the following data member descriptions, we only cover the common flags and options that are most important to a beginner at this point. For a description of other flags and options, refer to the SDK documentation.

  • BufferDesc: This structure describes the properties of the back buffer we want to create. The main properties we are concerned with are the width and height and the pixel format; see the SDK documentation for details on the other properties.

  • SampleDesc: The number of multisamples and quality level (see §4.1.7). In the demos of this book, we do not use multisampling. To indicate this, we set the sample count to 1 and the quality level to 0.

  • BufferUsage: Specify DXGI_USAGE_RENDER_TARGET_OUTPUT since we are going to be rendering to the back buffer (i.e., use it as a render target).

  • BufferCount: The number of back buffers to use in the swap chain; we usually only use one back buffer for double buffering, although you could use two for triple buffering.

  • OutputWindow: A handle to the window we are rendering into.

  • Windowed: Specify true to run in windowed mode or false for full-screen mode.

  • SwapEffect: Specify DXGI_SWAP_EFFECT_DISCARD in order to let the display driver select the most efficient presentation method.

  • Flags: Optional flags. If you specify DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH, when the application is switching to full-screen mode it will choose a display mode that best matches the current back buffer settings. If this flag is not specified, when the application is switching to full-screen mode it will use the current desktop display mode. In our sample framework, we do not specify this flag, as using the current desktop display mode in full-screen mode works fine for our demos.

The following code shows how we fill out the DXGI_SWAP_CHAIN_DESC structure in our sample framework:

 
    
1 DXGI_SWAP_CHAIN_DESC sd;
2 sd.BufferDesc.Width = mClientWidth; // use window's client area dims
3 sd.BufferDesc.Height = mClientHeight;
4 sd.BufferDesc.RefreshRate.Numerator = 60 ;
5 sd.BufferDesc.RefreshRate.Denominator = 1 ;
6 sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
7 sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
8 sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
9
10 // No multisampling.
11 sd.SampleDesc.Count = 1 ;
12 sd.SampleDesc.Quality = 0 ;
13
14 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
15 sd.BufferCount = 1 ;
16 sd.OutputWindow = mhMainWnd;
17 sd.Windowed = true ;
18 sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
19 sd.Flags = 0 ;

4.2.2 Create the Device and Swap Chain

After we describe the swap chain we want to create by filling out a DXGI_SWAP_CHAIN_DESC structure, we are ready to create the Direct3D 10 device (ID3D10Device) and swap chain (IDXGISwapChain). The ID3D10Device interface is the chief Direct3D interface and can be thought of as our software controller of the physical graphics device hardware; that is, through this interface we can interact with the hardware and instruct it to do things (such as clear the back buffer, bind resources to the various pipeline stages, and draw geometry). The device and swap chain can be created with the following function:

 
     
1 HRESULT WINAPI D3D10CreateDeviceAndSwapChain(
2 IDXGIAdapter * pAdapter,
3 D3D10_DRIVER_TYPE DriverType,
4 HMODULE Software,
5 UINT Flags,
6 UINT SDKVersion,
7 DXGI_SWAP_CHAIN_DESC * pSwapChainDesc,
8 IDXGISwapChain ** ppSwapChain,
9 ID3D10Device ** ppDevice);
  • DriverType: In general, you will always specify D3D10_DRIVER_TYPE_HARDWARE for this parameter to use 3D hardware acceleration for rendering. Specifying D3D10_DRIVER_TYPE_REFERENCE creates a so-called reference device. The reference device is a software implementation of Direct3D with the goal of correctness (it is extremely slow since it is a software implementation). There are two reasons to use the reference device:

    • To test code your hardware does not support; for example, to test Direct3D 10.1 code when you do not have a Direct3D 10.1-capable graphics card.

    • To test for driver bugs. If you have code that works correctly with the reference device, but not with the hardware, then there is probably a bug in the hardware drivers.

  • Software: This is used for supplying a software rasterizer. We always specify null since we are using hardware for rendering. Moreover, one must have a software rasterizer available in order to use one.

  • Flags: Optional device creation flags. For release mode builds, this will generally be 0 (no extra flags); for debug mode builds, this should be D3D10_CREATE_DEVICE_DEBUG to enable the debug layer. When the debug flag is specified, Direct3D will send debug messages to the VC++ output window; Figure 4.5 shows an example of some of the error messages that can be output.

     
    Figure 4.5: An example of Direct3D 10 debug output.

  • SDKVersion: Always specify D3D10_SDK_VERSION.

  • pSwapChainDesc: A pointer to the filled out DXGI_SWAP_CHAIN_DESC structure describing the swap chain we want to create.

  • ppSwapChain: Returns the created swap chain.

  • ppDevice: Returns the created device.

Here is an example call of this function:

 
     
1 DXGI_SWAP_CHAIN_DESC sd;
2
3 /* Initialize sd */
4
5 UINT createDeviceFlags = 0 ;
6 #if defined(DEBUG) || defined(_DEBUG)
7 createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
8 #endif
9 ID3D10Device * md3dDevice;
10 IDXGISwapChain * mSwapChain;
11 D3D10CreateDeviceAndSwapChain( 0 , D3D10_DRIVER_TYPE_HARDWARE,
12 0 , createDeviceFlags, D3D10_SDK_VERSION,
13 & sd, & mSwapChain, & md3dDevice);
4.2.3 Create the Render Target View
pAdapter: Specifies the display adapter we want the created device to represent. Specifying null for this parameter uses the primary display adapter. We always use the primary adapter in the sample programs of this book.

As noted in §4.1.6, we do not bind a resource to a pipeline stage directly; instead, we must create a resource view to the resource and bind the view to the pipeline stage. In particular, in order to bind the back buffer to the output merger stage of the pipeline (so Direct3D can render onto it), we need to create a render target view to the back buffer. The following example code shows how this is done:

 
    
1 ID3D10RenderTargetView * mRenderTargetView;
2 ID3D10Texture2D * backBuffer;
3 mSwapChain -> GetBuffer( 0 , __uuidof(ID3D10Texture2D),
4 reinterpret_cast < void **> ( & backBuffer));
5 md3dDevice -> CreateRenderTargetView(backBuffer, 0 , & mRenderTargetView);
6 ReleaseCOM(backBuffer);

 

  • A pointer to the swap chain’s back buffer is obtained using the IDXGISwapChain::GetBuffer method. The first parameter of this method is an index identifying the particular back buffer we want to get (in case there is more than one). In our demos, we only use one back buffer, and it has index 0. The second parameter is the inter face type of the buffer, which is usually always a 2D texture ( ID3D10Texture2D). The third parameter returns a pointer to the back buffer.
  • To create the render target view, we use the ID3D10Device::CreateRenderTargetView method. The first parameter specifies the resource that will be used as the render target, which, in the example above, is the back buffer. The second parameter is a pointer to a D3D10_RENDER_TARGET_VIEW_DESC. Among other things, this structure describes the data type of the elements in the resource. If the resource was created with a typed format (i.e., not typeless), then this parameter can be null, which indicates to use the format the resource was created with. The third parameter returns a pointer to the create render target view object.

  • The call to IDXGISwapChain::GetBuffer increases the COM reference count to the back buffer, which is why we release it (ReleaseCOM) at the end of the code fragment.

4.2.4 Create the Depth/Stencil Buffer and View

We now need to create the depth/stencil buffer. As described in §4.1.5, the depth buffer is just a 2D texture that stores the depth information (and stencil information if using stenciling). To create a texture, we need to fill out a D3D10_TEXTURE2D_DESC structure describing the texture to create, and then call the ID3D10Device::CreateTexture2D method. The D3D10_TEXTURE2D_DESC structure is defined as follows:

 
    
1 typedef struct D3D10_TEXTURE2D_DESC {
2 UINT Width;
3 UINT Height;
4 UINT MipLevels;
5 UINT ArraySize;
6 DXGI_FORMAT Format;
7 DXGI_SAMPLE_DESC SampleDesc;
8 D3D10_USAGE Usage;
9 UINT BindFlags;
10 UINT CPUAccessFlags;
11 UINT MiscFlags;
12 } D3D10_TEXTURE2D_DESC;
  • Width: The width of the texture in texels.
  • Height: The height of the texture in texels.

  • MipLevels: The number of mipmap levels. Mipmaps are covered in Chapter 7, “Texturing.” For creating the depth/stencil buffer, our texture only needs one mipmap level.

  • ArraySize: The number of textures in a texture array. For the depth/stencil buffer, we only need one texture.

  • Format: A member of the DXGI_FORMAT enumerated type specifying the format of the texels. For a depth/stencil buffer, this needs to be one of the formats shown in §4.1.5.

  • SampleDesc: The number of multisamples and quality level; see §4.1.7. In the demos of this book, we do not use multisampling. To indicate this, we set the sample count to 1 and the quality level to 0.

  • Usage: A member of the D3D10_USAGE enumerated type specifying how the texture will be used. The four usage values are:

    • D3D10_USAGE_DEFAULT: Specify this usage if the GPU (graphics processing unit) will be reading and writing to the resource. The CPU cannot read or write to a resource with this usage. For the depth/stencil buffer, we specify D3D10_USAGE_DEFAULT since the GPU will be doing all the reading and writing to the depth/stencil buffer.

    • D3D10_USAGE_IMMUTABLE: Specify this usage if the content of a resource never changes after creation. This allows for some potential optimizations, as the resource will be read-only by the GPU. The CPU cannot write to an immutable resource, except at creation time to initialize the resource. The CPU cannot read from an immutable resource.

    • D3D10_USAGE_DYNAMIC: Specify this usage if the application (CPU) needs to update the data contents of the resource frequently (e.g., on a per-frame basis). A resource with this usage can be read by the GPU and written to by the CPU.

    • D3D10_USAGE_STAGING: Specify this usage if the application (CPU) needs to be able to read a copy of the resource (i.e., the resource supports copying data from video memory to system memory).

  • BindFlags: One or more flags ORed together, specifying where the resource will be bound to the pipeline. For a depth/stencil buffer, this needs to be D3D10_BIND_DEPTH_STENCIL. Some other bind flags for textures are:

    • D3D10_BIND_RENDER_TARGET: The texture will be bound as a render target to the pipeline.

    • D3D10_BIND_SHADER_RESOURCE: The texture will be bound as a shader resource to the pipeline.

  • CPUAccessFlags: Specifies how the CPU will access the resource. If the CPU needs to write to the resource, specify D3D10_CPU_ACCESS_WRITE. A resource with write access must have usage D3D10_USAGE_DYNAMIC or D3D10_USAGE_STAGING. If the CPU needs to read from the buffer, specify D3D10_CPU_ACCESS_READ. A buffer with read access must have usage D3D10_USAGE_STAGING. For the depth/stencil buffer, only the GPU writes and reads to the depth/buffer; therefore, we can specify 0 for this value, as the CPU will not be reading or writing to the depth/stencil buffer.

  • MiscFlags: Optional flags, which do not apply to the depth/stencil buffer, so set to 0.

 

Note 

Throughout this book, we will see different examples of creating resources with different options; for example, different usage flags, bind flags, and CPU access flags. For now, just concentrate on the values we need to specify to create the depth/stencil buffer, and do not worry about every single option.

In addition, before using the depth/stencil buffer, we must create a depth/stencil view to be bound to the pipeline. This is done similarly to creating the render target view. The following code example shows how we create the depth/stencil texture and its corresponding depth/stencil view:

 
   
1 D3D10_TEXTURE2D_DESC depthStencilDesc;
2 depthStencilDesc.Width = mClientWidth;
3 depthStencilDesc.Height = mClientHeight;
4 depthStencilDesc.MipLevels = 1 ;
5 depthStencilDesc.ArraySize = 1 ;
6 depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
7 depthStencilDesc.SampleDesc.Count = 1 ; // multisampling must match
8 depthStencilDesc.SampleDesc.Quality = 0 ; // swap chain values.
9 depthStencilDesc.Usage = D3D10_USAGE_DEFAULT;
10 depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
11 depthStencilDesc.CPUAccessFlags = 0 ;
12 depthStencilDesc.MiscFlags = 0 ;
13
14 ID3D10Texture2D * mDepthStencilBuffer;
15 ID3D10DepthStencilView * mDepthStencilView;
16
17 HR(md3dDevice -> CreateTexture2D(
18 & depthStencilDesc, 0 , & mDepthStencilBuffer));
19 HR(md3dDevice -> CreateDepthStencilView(
20 mDepthStencilBuffer, 0 , & mDepthStencilView));
 

Note 

The second parameter of CreateTexture2D is a pointer to initial data to fill the texture with. However, since this texture is to be used as the depth/stencil buffer, we do not need to fill it ourselves with any data. Direct3D will write to the depth/stencil buffer directly when performing depth buffering and stencil operations. Thus, we specify null for the second parameter.

4.2.5 Bind the Views to the Output Merger Stage

Now that we have created views to the back buffer and depth buffer, we can bind these views to the output merger stage of the pipeline to make the resources the render target and depth/stencil buffer of the pipeline:

md3dDevice->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);

The first parameter is the number of render targets we are binding; we bind only one here, but more can be bound to render simultaneously to several render targets (an advanced technique). The second parameter is a pointer to the first element in an array of render target view pointers to bind to the pipeline. The third parameter is a pointer to the depth/stencil view to bind to the pipeline.

 Note 

We can set an array of render target views, but only one depth/stencil view.

4.2.6 Set the Viewport

Usually we like to draw the 3D scene to the entire back buffer. However, sometimes we only want to draw the 3D scene into a subrectangle of the back buffer, as shown in Figure 4.6.

 
Figure 4.6: By modifying the viewport, we can draw the 3D scene into a subrectangle of the back buffer. The back buffer then gets presented to the client area of the window.

The subrectangle of the back buffer we draw into is called the viewport and it is described by the following structure:

 
     
1 typedef struct D3D10_VIEWPORT {
2 INT TopLeftX;
3 INT TopLeftY;
4 UINT Width;
5 UINT Height;
6 FLOAT MinDepth;
7 FLOAT MaxDepth;
8 } D3D10_VIEWPORT;
The first four data members define the viewport rectangle relative to the client area rectangle of the window we are drawing into. The MinDepth member specifies the minimum depth buffer value and MaxDepth specifies the maximum depth buffer value. Direct3D uses a depth buffer range of 0 to 1, so MinDepth and MaxDepth should be set to those values, respectively, unless a special effect is desired.

Once we have filled out the D3D10_VIEWPORT structure, we set the viewport with Direct3D with the ID3D10Device::RSSetViewports method. The following example creates and sets a viewport that draws onto the entire back buffer:

 
     
1 D3D10_VIEWPORT vp;
2 vp.TopLeftX = 0 ;
3 vp.TopLeftY = 0 ;
4 vp.Width = mClientWidth;
5 vp.Height = mClientHeight;
6 vp.MinDepth = 0.0f ;
7 vp.MaxDepth = 1.0f ;
8
9 md3dDevice -> RSSetViewports( 1 , & vp);
You could use the viewport to implement split screens for two-player game modes, for example. You would create two viewports, one for the left half of the screen and one for the right half of the screen. Then you would draw the 3D scene from the perspective of player one into the left viewport and draw the 3D scene from the perspective of player two into the right viewport.

转载于:https://www.cnblogs.com/seanyou/archive/2010/09/20/1831420.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值