The DirectX Tool Kit (DirectXTK)
The tool kit's GitHub repository has a wiki with good documentation and tutorials to learn from. It is a little disorganized in that a table of contents is lacking and there is no path through the content like a book. You have to construct that yourself, or, pick the first tutorial and follow the "next lesson" links at the end of each page. Even then, you reach a point where there are multiple "next lessons". So, I have organized the content below, and rewritten a framework using the sample code so that it is easier to learn and try things out. As you read through them, keep in mind that
- DirectX 11 code needs slight modifications for the three different platforms: Windows 10 Desktop, Xbox One and UWP Applications. Each tutorial points out those changes in "notes" blocks that may impede readability. It will be easier to learn if you think of developing for the desktop because that's the target of the tutorials and ignore the "notes" diversions. I have collected them in separate "Xbox" and "UWP" sections below.
- On the DirectXTK wiki, these two pages are equivalent: The basic game loop ≡ Using DeviceResource. Both of them introduce the game loop. In my notes here, what I title The Game Loop, points to the page titled Using DeviceResources on the wiki. The reason is:
- The title "Using DeviceResources" as a name of this topic is distracting.
- The page titled Using DeviceResources introduce the DeviceResources class that makes your code more readable. There is no advantage in reading the simpler treatment in the The basic game loop page just because it has one less of a class.
- The wiki pages seem to follow the simpler variant (as opposed to the "DR", or DeviceResources variant). Here is a list of things from the code and their equivalent usage in my DirectXTK code:
- CreateDevice ≡ create_device_dependent_resources
- CreateResources ≡ create_window_size_dependent_resources
- m_d3dDevice.Get() ≡ device_resources_->GetD3DDevice()
- m_d3dContext.Get() ≡ device_resources_->GetD3DDeviceContext()
- Obtain the back buffer dimensions using deviceresources_->GetOutputSize()
- Obtain the back buffer count using deviceresources_->GetBackBufferCount()
- As you can see from the function names and variable names above, my code follows the Google C++ Style Guide. This helps me (and probably the reader) visually separate code I have written from DirectXTK and DirectX API code.
From the Wiki †
- Adding DirectX Tool Kit to a Visual Studio Solution || Use NuGet Package Manager to add the tool kit. Add the tool kit as a reference to the project. Install a VSIX package of templates: Direct3DUWPGame.vsix ||
- The Game Loop || Setting up a Visual Studio Project. Running the application. Using the DeviceResources class. Initialize, Update, Render, Clear, Present. ||
- In this tutorial DXGI_FORMAT_B8G8R8A8_UNORM is used, which does not gamma-correct but is easier to set up.
- UWP apps require use of flip style swap effects, and so is the recommendation for Win32 desktop applications on Windows 10: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL or DXGI_SWAP_EFFECT_FLIP_DISCARD. These DXGI swap chains can not be created with an DXGI_FORMAT_x_UNORM_SRGB format or use MSAA. Both sRGB gamma-correction and MSAA require special handling.1
- Previously the viewport was set in CreateDeviceResources and was assumed it wouldn't change until a window-resize. This is not true any more because ClearState can overwrite or clear the viewport. Therefore reset the viewport state at the start of each frame. When dealing with deferred contexts, Xbox One fast semantics, or the Direct3D 12 API, assumptions of device state persisting frame-to-frame is wrong.
- Device loss/reset: The application gets a DXGI_ERROR_DEVICE_RESET if the driver crashes or the video hardware hangs, a DXGI_ERROR_DEVICE_REMOVED if a new driver is installed midway, or docked-GPU-laptop is undocked. The removed event can be artificially broadcast to all running Direct3D applications using the command dxcap -forcetdr at a Developer Command Prompt for Visual Studio. The loss/reset event doesn't occur often because the GPU is not an exclusive resource any more, but shared. This was the reason Direct3D 9 would lose the device every time the used ALT+TAB-ed away from the application.
- Threading Model: The DeviceResources object methods are meant to be called from the main presenting thread, not from other threads. The device context associated with DeviceResources is the immediate context, and is intended for use by this main thread. Per DXGI Best Practices2 the presenting thread should also be the same thread where the main window's message processing happens.
- Use DXGI_FORMAT_UNKNOWN if you don't want a depth/stencil buffer. This is useful for 2D-only rendering or when using MSAA on UWP apps which require handling your own render target and depth buffer with Sample.Count > 1.
- The DR version always uses D3D11_CREATE_DEVICE_BGRA_SUPPORT which is required for Direct2D/DirectWrite interop if that's desired.
Sprites & Textures || Load and render image files (sprites) as textures. Set up Visual Studio assets pipeline to convert images to DDS format. Operations on sprites: change alpha mode, tint, rotate, scale, stretch, tile. ||
- FINDOUT: Disambiguate SpriteBatch::Begin() parameters; states: LineWrap(), LinearClamp().
- SpriteBatch defaults: premultiplied alpha blending, no depth buffer, counter-clockwise culling, linear filtering with clamp texture addressing.
Parameters to SpriteBatch::Begin()
void XM_CALLCONV Begin(SpriteSortMode sortMode = SpriteSortMode_Deferred, _In_opt_ ID3D11BlendState* blendState = nullptr, _In_opt_ ID3D11SamplerState* samplerState = nullptr, _In_opt_ ID3D11DepthStencilState* depthStencilState = nullptr, _In_opt_ ID3D11RasterizerState* rasterizerState = nullptr, _In_opt_ std::function<void __cdecl()> setCustomShaders = nullptr, FXMMATRIX transformMatrix = MatrixIdentity);
- sortMode: Sort sprites in a a number of different modes:
- SpriteSortMode_Deferred, SpriteSortModeImmediate - When _Deferred, the drawing is deferred until SpriteBatch::End() is called or when you exceed the internal vertex buffer size, otherwise, in Immediate mode, the sprite is drawn immediately on the SpriteBatch::Draw() call.
- SpriteSortMode_Texture - Use when drawing lots of different textures.
- SpriteSortMode_BackToFront, SpriteSortMode_FrontToBack - Use for correct sorting when using layerDepth parameter in the Draw call.
- samplerState: Use for special effects utilizing texture addressing.2
- WHY: Use CommonStates::PointClamp for a 'pixel art' look.
- setCustomShaders: Override shader settings and other Direct3D state to implement things like post-processing, chroma-key conversion to alpha, or normal-map based effects.
- transformMatrix: Provide custom transformation for sprite rendering, which is combined with the viewport-based final view transform. If SetRotation(DXGI_MODE_ROTATION_UNSPECIFIED) is called, this is disabled.
Parameters to SpriteBatch::Draw() (Here I show one of the overloaded Draw calls long enough to cover all its parameters)
FINDOUT: Disambiguate SpriteBatch::Draw() parameters; in context of tile
void XM_CALLCONV Draw(_In_ ID3D11ShaderResourceView* texture, FXMVECTOR position, _In_opt_ RECT const* sourceRectangle, FXMVECTOR color, float rotation, FXMVECTOR origin, GXMVECTOR scale, SpriteEffects effects = SpriteEffects_None, float layerDepth = 0);
- SpriteEffects_None - The default.
- SpriteEffects_FlipHorizontally, SpriteEffects_FlipVertically, SpriteEffects_FlipBoth - Flips the texture image at runtime.
- sourceRectangle - Use this to specify parts of a large texture to draw in order to avoid loading individual sprites which is inefficient.1
- The concept of a rotation mode, meant for device orientation handling in UWP apps, can be used for special effects. Call SetRotation() with one of the DXGI_MODE_ROTATION settings to flip the output 90, 180 or 270 degrees. It defaults to no extra rotation with DXGI_MODE_ROTATION_IDENTITY.
- Animation 3, 4 - Use a layout of animation frames on a image file picking portions of it and rendering them, effectively, creating animation.
- Scrolling Background 3, 5 - Slide the source rectangle over a image, and wrap around when at the bottom of the image, to produce the effect of a scrolling background.
- Implementation (pimpl)
- Simple Rendering (A Triangle)
- Writing Custom Shaders
- HDR Rendering
- The BasicEffect family of shader classes uses shader code built in to the DirectXTK.lib as static data so there's no need to compile shaders at runtime or to load data files from disk.
- Internally, both SpriteBatch and PrimitiveBatch make use of a dynamic rather than static vertex buffer object which makes use of special memory shared between the CPU and GPU. Generally, we prefer when possible to use static vertex buffers as they can reside in the video memory directly that is only accessible by the GPU.
- Dynamic submission is a highly effective pattern for drawing procedural geometry, and convenient for debug rendering, but is not nearly as efficient as static buffers which is more suited to traditional meshes where the VBs and IBs do not change every frame. Excessive dynamic submission is a common source of performance problems in apps. Therefore, you should prefer to use Model, GeometricPrimitive, or your own VB/IB over PrimitiveBatch unless you really need the flexibility to regenerate the topology every frame.
- DXGIFORMATUNKNOWN, then no depth/stencil buffer is created. It usually defaults to DXGIFORMATD32_FORMAT.
Software Libraries and Tools
- Direct3DUWPGame.vsix - Ready-made Visual Studio templates with basic DirectXTK code.
- DirectX Texture Processing Library
- Test Suit