Table 4.1. Possible Behavior Flags
CreateFlags.AdapterGroupDevice |
Used for multimon-capable adapters. Specifies that a single device will control each of the adapters on the system. |
CreateFlags.DisableDriverManagement
|
Tells Direct3D to handle the resource management rather than the driver. In most cases, you will not want to specify this flag. |
CreateFlags.MixedVertexProcessing |
Tells Direct3D that a combination of hardware and software vertex processing will be used. This flag cannot be combined with either the software or hardware vertex processing flags. |
CreateFlags.HardwareVertexProcessing |
Tells Direct3D that all vertex processing will occur in hardware. This flag cannot be combined with the software or mixed vertex processing flags. |
CreateFlags.SoftwareVertexProcessing |
Tells Direct3D that all vertex processing will occur in software. This flag cannot be combined with the hardware or mixed vertex processing flags. |
CreateFlags.PureDevice
CreateFlags.Multithreaded |
Specifies that this device will be a pure device.
Specifies that this device may be accessed for more than one thread simultaneously. Because the garbage collector runs on a separate thread, this option is turned on by default in Managed DirectX. Note that there is a slight performance penalty for using this flag. |
CreateFlags.FpuPreserve |
Tells Direct3D to preserve the current floating-point unit precision. |
For this game, you should stick with either software or hardware vertex processing only, which is what the enumeration code picked during the last chapter. The final parameter of the device constructor is a parameter array of the PresentParameters class. You only need more than one of these objects if you are using the CreateFlags.AdapterGroupDevice flag mentioned earlier, and then you need one for each adapter in the group.
Construction Cue
Before the device is actually created by the framework, you might notice that it turns off the event-handling mechanism for the Managed Direct3D libraries.
Before you go on, it's important to understand why turning off the event-handling model is a good idea. The default implementation of the Managed DirectX classes hooks certain events on the Direct3D device for every resource that is created. At a minimum, each resource (such as textures or a vertex buffer) hooks the Disposing event and more likely also hooks other events, such as the DeviceLost and DeviceReset events. This step happens for maintaining object lifetimes. Why wouldn't you want this great benefit in your application?
The main reason is that this benefit comes at a cost, and that cost could potentially be quite large. To understand this point, you must first have a sense of what is going on behind the scenes. You can look at this simple case, written here in pseudo-code:
SomeResource res = new SomeResource(device);
device.Render(res);
As you can see, this code looks harmless enough. You simply create a resource and render it. The object is obviously never used again, so the garbage collector should be smart enough to clean up the object. This thought is common, but this thought is incorrect. When the new resource is created, it hooks a minimum of one event on the device to allow it to clean up correctly. This hooking of the event is a double-edged sword.
One, there is an allocation of the EventHandler class when doing the actual hook. Granted, the allocation is small, but as you will see in a moment, even small allocations can add up quickly. Second, after the event is hooked, the resource has a hard link to the device. In the eyes of the garbage collector, this object is still in use and will remain in use for the lifetime of the device or until the events are unhooked. In the pseudo-code earlier, imagine if this code were run once every frame to render something. Imagine that your game was pushing around a thousand frames per second, and imagine it was running for two minutes. You've just created 120,000 objects that will not be collected while the device is around, plus another 120,000 event handlers. All these created objects can cause memory consumption to rise quickly, as well as extra garbage collections to be performed, which can hurt performance. If your resources are in video memory, you can be assured you will run out quickly.
This scenario doesn't even consider what happens when the device is finally disposed. In the preceding example, when the device is disposed, it fires the Disposing event, which has been hooked by 120,000 listeners. You can imagine that this cascading list of event handlers which must be called will take some time, and you'd be correct. It could take literally minutes and cause people to think the application has locked up.
You only want to use the event handling that is built in to Managed Direct3D in the simplest of cases. At any point where you care about memory consumption or performance (for example, in games), you want to avoid this process, as you've done in this example (or at the very least ensure that you are disposing of objects properly). The sample framework gives you the opportunity to do so.
You'll notice that last method you called in the Main method is the MainLoop method from the sample framework. This point is where you are telling the sample framework that you're ready to run your application now. This method will run and process Windows messages as well as call your rendering methods constantly until the application exits. This method will not return until it happens. From now on, all interaction with the sample framework comes from the events it fires and the callbacks it calls into.
A few times throughout the course of the code, you might need to know the name of the game. You can simply add this constant to your game engine class:
public const string GameName = "Blockers";
|