First Contact
How do you say “We come in peace” when the very words are an act of war?
– Peter Watts, Blindsight
In the last, rather theoretical, tutorial we learned about the Component Object Model architecture and that DirectX is a collection of such COM objects. In this tutorial we will jump right into the action and initialize Direct3D! Are you ready for
First Contact?
Fortunately, COM makes use of smart pointers, called COM Pointers, which easily handle the life cycle of COM objects.
With that being said, creating and using a COM object is surprisingly simple:
The pointer to the desires COM interface is acquired by a call to the CreateObject function. Each COM object type has its own way of being created, and we will learn about a few of those as we move forward with the tutorials.
The Device and its Context
At the very core of Direct3D are two COM objects: the device and the device context.
The device object is a virtual representation of the video adapter, and it can be used to access the memory of the GPU and to create other Direct3D related COM objects.
The device context is a structure that defines a set of graphic objects and their associated attributes, as well as the graphic modes that affect output. The graphic objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colours, a region for clipping and other operations, and a path for painting and drawing operations. Thus, the device context can be considered the control panel for the GPU. Through it, the transformation of a three-dimensional model to a final two-dimensional image, and the process of rendering that image to the screen, can be controlled.
The interfaces for these objects are called ID3D11Device and ID3D11DeviceContext. To create and initialize them, the D3D11CreateDevice function must be called:
IDXGIAdapter *pAdapter
This is a pointer to an interface that describes the GPU that Direct3D should use. For now, we shall simply let Direct3D take care of the details, as in most cases, there is only one GPU anyway. To do that, we input a nullptr here.
D3D_DRIVER_TYPE DriverType
The DriverType represents the driver type to create. There are six possible values for this parameter, but we are only going to be concerned with one of them: D3D_DRIVER_TYPE_HARDWARE which tells Direct3D to use the hardware accelerated graphics chip to process graphics.
HMODULE Software
A handle to a DLL that implements a software rasterizer. If the DriverType is D3D_DRIVER_TYPE_SOFTWARE, Software must not be NULL. However, as we want to directly work with the hardware, we will just use NULL here.
UINT Flags
This parameter defines the runtime layers to enable. We will use the D3D11_CREATE_DEVICE_BGRA_SUPPORT flag to enable interoperability between Direct2D and Direct3D. While debugging, it might be a good idea to also use the D3D11_CREATE_DEVICE_DEBUG flag, which creates a device that supports the debug layer.
const D3D_FEATURE_LEVEL *pFeatureLevels
This is a pointer to an array of D3D_FEATURE_LEVELs, which determine the order of feature levels to attempt to create. This can be set to NULL to get the greatest feature level available.
UINT FeatureLevels
The number of elements in pFeatureLevels. We will obviously put 0 here.
UINT SDKVersion
The SDK version; use D3D11_SDK_VERSION.
ID3D11Device **ppDevice
This is a pointer to a pointer to an ID3D11Device object that represents the device created.
D3D_FEATURE_LEVEL *pFeatureLevel
If successful, the first D3D_FEATURE_LEVEL from the pFeatureLevels array which succeeded is stored in this parameter. Otherwise, 0 is returned.
ID3D11DeviceContext **ppImmediateContext
This is a pointer to a pointer to the ID3D11DeviceContext object that represents the device context.
Putting It All Together
To work with Direct3D, we created a new class, the Direct3D class.
The first thing to do, obviously, is to include a number of import libraries which include the COM wrappers, such that calls to DirectX can be made using those wrappers.
Using the code from above, creating the actual device and its context is rather straightforward:
You can download the source code from here.
And here is the log file:
Well, this wasn’t so difficult, was it? We have successfully added a Direct3D device and its context to our application. In the upcoming tutorials, we will learn how to use these two to actually render objects to the screen; we will start with the swap chain, in the next tutorial.
References
(in alphabetic order)
- Microsoft Developer Network (MSDN)
- Tricks of the Windows Game Programming Gurus, by André LaMothe
#gamedev #directx