Tutorial 1: Direct3D 11 Basics
#include <windows.h> #include <d3d11.h> #include <d3dx11.h> #include "resource.h" #pragma comment(lib, "dxguid.lib") #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "d3dx11.lib") #pragma comment(lib, "winmm.lib") //-------------------------------------------------------------------------------------- // Global Variables //-------------------------------------------------------------------------------------- HINSTANCE g_hInst = NULL; HWND g_hWnd = NULL; D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL; D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;///Targets features supported by Direct3D 11.0 including shader shader model 5. ID3D11Device* g_pd3dDevice = NULL;///D3D11设备接口 ID3D11DeviceContext* g_pImmediateContext = NULL;///DC IDXGISwapChain* g_pSwapChain = NULL;///交换链接口 ID3D11RenderTargetView* g_pRenderTargetView = NULL;///渲染目标视图 //-------------------------------------------------------------------------------------- // Forward declarations //-------------------------------------------------------------------------------------- HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); HRESULT InitDevice(); void CleanupDevice(); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); void Render(); //-------------------------------------------------------------------------------------- // Entry point to the program. Initializes everything and goes into a message processing // loop. Idle time is used to render the scene. //-------------------------------------------------------------------------------------- int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hPrevInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); if( FAILED( InitWindow( hInstance, nCmdShow ) ) ) return 0; if( FAILED( InitDevice() ) ) { CleanupDevice(); return 0; } // Main message loop MSG msg = {0}; while( WM_QUIT != msg.message ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } CleanupDevice(); return ( int )msg.wParam; } //-------------------------------------------------------------------------------------- // Register class and create window //-------------------------------------------------------------------------------------- HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ) { // Register class WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(0, IDI_APPLICATION); wcex.hCursor = LoadCursor(0, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; wcex.hIconSm = LoadIcon(0, IDI_APPLICATION); if( !RegisterClassEx( &wcex ) ) return E_FAIL; // Create window g_hInst = hInstance; RECT rc = { 0, 0, 640, 480 }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 11 Tutorial 1: Direct3D 11 Basics", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL ); if( !g_hWnd ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); return S_OK; } //-------------------------------------------------------------------------------------- // Called every time the application receives a message //-------------------------------------------------------------------------------------- LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { PAINTSTRUCT ps; HDC hdc; switch( message ) { case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; case WM_KEYDOWN: { if( wParam == VK_ESCAPE ) ::DestroyWindow(hWnd); } break; default: return DefWindowProc( hWnd, message, wParam, lParam ); } return 0; } //-------------------------------------------------------------------------------------- // Create Direct3D device and swap chain //-------------------------------------------------------------------------------------- HRESULT InitDevice() { HRESULT hr = S_OK; RECT rc; GetClientRect( g_hWnd, &rc ); UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_DRIVER_TYPE driverTypes[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = ARRAYSIZE( driverTypes ); D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0,///Targets features supported by Direct3D 11.0 including shader shader model 5. D3D_FEATURE_LEVEL_10_1,///Targets features supported by Direct3D 10.1 including shader shader model 4. D3D_FEATURE_LEVEL_10_0, }; UINT numFeatureLevels = ARRAYSIZE( featureLevels ); /// create the swap chain DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof( sd ) ); sd.BufferCount = 1; sd.BufferDesc.Width = width; sd.BufferDesc.Height = height; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; /// we want to render to the back buffer sd.OutputWindow = g_hWnd; ///represents the window that the swap chain will use to present images on the screen sd.SampleDesc.Count = 1;///SampleDesc is used to enable multi-sampling.Here disable multi-sampling sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ) { g_driverType = driverTypes[driverTypeIndex]; ///创建device和swap chain hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &sd, &g_pSwapChain, ///a swap chain interface &g_pd3dDevice, ///a device interface &g_featureLevel, ///a pointer to the feature level &g_pImmediateContext ); ///an immediate context interface if( SUCCEEDED( hr ) ) break; } if( FAILED( hr ) ) return hr; // Create and set a render target view 创建并设置渲染目标视图 ID3D11Texture2D* pBackBuffer = NULL; hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );///get the back buffer object if( FAILED( hr ) ) return hr; hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );///create a default render target view pBackBuffer->Release(); if( FAILED( hr ) ) return hr; ///bind the render target view to the pipeline 将渲染目标视图绑定到渲染管线 g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL ); // Setup the viewport 设置视口大小,D3D11默认不会设置视口,此步骤必须手动设置 D3D11_VIEWPORT vp; vp.Width = (FLOAT)width; vp.Height = (FLOAT)height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; g_pImmediateContext->RSSetViewports( 1, &vp ); return S_OK; } //-------------------------------------------------------------------------------------- // Render the frame //-------------------------------------------------------------------------------------- void Render() { // Just clear the backbuffer float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; //red,green,blue,alpha g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor ); g_pSwapChain->Present( 0, 0 );///将交换链的后缓存内容显示到屏幕上 } //-------------------------------------------------------------------------------------- // Clean up the objects we've created //-------------------------------------------------------------------------------------- void CleanupDevice() { if( g_pImmediateContext ) g_pImmediateContext->ClearState(); if( g_pRenderTargetView ) g_pRenderTargetView->Release(); if( g_pSwapChain ) g_pSwapChain->Release(); if( g_pImmediateContext ) g_pImmediateContext->Release(); if( g_pd3dDevice ) g_pd3dDevice->Release(); }
In Direct3D 11, a device is separated into
(1)a device object for creating resources: contains methods to create resources
(2)and a device-context object which performs rendering: is used by the application to perform rendering onto a buffer
Set up the Direct3D 11 device
(1)The first thing to do is to create three objects: a device, an immediate context, and a swap chain.(The immediate context is a new object in Direct3D 11.)
(2)The next thing we need to do is to create a render target view.
(3)The last thing we need to set up before Direct3D 11 can render is initialize the viewport.
We need to create a render target view because we would like to bind the back buffer of our swap chain as a render target. This enables Direct3D 11 to render onto it.