Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9
      Miscellaneous

DirectX Graphics: Enumeration
Author : Jack Hoxley
Written : 2nd December 2000
Contact : [Email]
Download : Graph_02.Zip [11 Kb]


Contents of this lesson:
1. Introduction
2. Display Device, Adapter and resolution enumeration
3. Hardware Capability enumeration


1. Introduction

Enumeration is a fairly basic idea once you get used to it - and it's something that you're going to have to use if you intend to make a distributable application using DirectX. Enumeration is the process of capability detection - you ask it questions (about what it can do) and it will tell you if it can or cant do what you want it to do. As far as tutorials go it's fairly safe to hardcode the settings such as resolution and renderer - no ones really going to miss out if it wont work, but if you're writing a real-world application that lots of people will be using (such as a published game) you want to make your application as solid as a rock.

Enumeration is what games use to display a list of resolutions that you can play the game at, but it's also used in ways you may not notice. For example, a program can query your hardware for the possibility of using bump-mapping; if the enumeration returns true then you get in-game bump-mapping. If it returns false the game can either decide to not use bump-mapping or it can do something else (such as use software bump-mapping).

This lesson will introduce you to both of the main types of enumeration - display mode/renderer and hardware capabilities. But as there are so many possible hardware capabilites to check only the structure will be discussed here - enumeration will be used in later tutorials, and any relevent details will be discussed then. But if you happen to have the DirectX8 SDK help file you can examine their descriptions/information on all of the possible enumerations.


2. Display Device, Adapter and resolution enumeration

First up we want to know what modes we can initialise our application in. In windowed mode this doesn't matter a great deal, but in fullscreen mode you must prepare a correct display mode setup that the hardware supports - or you'll get an error when trying to create the device. There is a basic hierachy that you need to remember when enumerating for display modes and formats:

ADAPTER => DEVICE => RESOLUTIONS & CAPABILITIES

First we must query the adapters available, then selecting one of these adapters we query what device's it supports (HAL or REFERENCE) then we must query the adapter-device combination for the resolutions it supports and the hardware capabilities. So, first off I'll show you how to enumerate the adapters:

'//D3D should be a valid reference to a Direct3D8 object.
'//AdapterInfo should be a defined D3DADAPTER_IDENTIFIER8 variable

Private Sub EnumerateAdapters()
    
    Dim I As Integer, sTemp As String, J As Integer
    
    '//This'll either be 1 or 2
    nAdapters = D3D.GetAdapterCount
    
    For I = 0 To nAdapters - 1
        'Get the relevent Details
        D3D.GetAdapterIdentifier I, 0, AdapterInfo
        
        'Get the name of the current adapter - it's stored as a long
        'list of character codes that we need to parse into a string
        ' - Dont ask me why they did it like this; seems silly really :)
        sTemp = "" 'Reset the string ready for our use
        For J = 0 To 511
            sTemp = sTemp & Chr$(AdapterInfo.Description(J))
        Next J
        sTemp = Replace(sTemp, Chr$(0), " ")
        cmbAdapters.AddItem sTemp
    Next I
End Sub

You may well want to change the output control - currently it just dumps all the relevent information into the "cmbAdapters" combobox. The code above basically counts the number of available adapters (almost always 1) then it loops through them and collects the information on them (in the AdapterInfo variable). Should you want more than the name of the adapter you can also get the following (Useful) information:

Description : A brief description of the adapter, intended to be displayed to the user.
Driver : What driver the hardware is using - again, to be displayed to the user. (This is usually going to be the DLL name)
DeviceID : A number representing the chip-set type; could be 0 if unknown.
DeviceIdentifier : A set of 4 variables determining the hardware in use. This is the best variable to use should you want to identify a piece of hardware.

Now that we can identify the adapter we can look at what devices it'll support. Software renderers are an advanced topic and are unlikely to be relevent yet so we'll ignore them for now. Instead we'll check if the hardware supports HAL (Hardware Accelaration). The reference rasterizer should always be present so we'll just assume that we can access it.

Private Sub EnumerateDevices()
On Local Error Resume Next '//We want to handle the errors...
Dim Caps As D3DCAPS8

D3D.GetDeviceCaps cmbAdapters.ListIndex, D3DDEVTYPE_HAL, Caps
    If Err.Number = D3DERR_NOTAVAILABLE Then
        'There is no hardware acceleration
        cmbDevice.AddItem "Reference Rasterizer (REF)" 'Reference device will always be available
    Else
        cmbDevice.AddItem "Hardware Acceleration (HAL)"
        cmbDevice.AddItem "Reference Rasterizer (REF)" 'Reference device will always be available
    End If
End Sub


Above is a slightly sloppy way of detecting hardware support - but it works and is very simple. If we attempt to read stuff from a HAL device and it doesn't exist then we'll get the error code "D3DERR_NOTAVAILABLE", at which point we know that only the REF device is okay to use. The code outputs the results to a combobox, which you can change if you want...

The last thing that we want to be able to check is what display modes are supported. This can only be done when we've selected an adapter and a device.

Private Sub EnumerateDispModes(Renderer As Long)
cmbRes.Clear '//Remove any existing entries...

Dim I As Integer, ModeTemp As D3DDISPLAYMODE

nModes = D3D.GetAdapterModeCount(cmbAdapters.ListIndex)

For I = 0 To nModes - 1 '//Cycle through them and collect the data...
    Call D3D.EnumAdapterModes(cmbAdapters.ListIndex, I, ModeTemp)
    
    'First we parse the modes into two catergories - 16bit and 32bit
    If ModeTemp.Format = D3DFMT_R8G8B8 Or ModeTemp.Format = D3DFMT_X8R8G8B8 Or ModeTemp.Format = D3DFMT_A8R8G8B8 Then
        'Check that the device is acceptable and valid...
        If D3D.CheckDeviceType(cmbAdapters.ListIndex, Renderer, ModeTemp.Format, ModeTemp.Format, False) >= 0 Then
            'then add it to the displayed list
            cmbRes.AddItem ModeTemp.Width & "x" & ModeTemp.Height & " 32 bit" & "    [FMT: " & ModeTemp.Format & "]"
        End If
    Else
        If D3D.CheckDeviceType(cmbAdapters.ListIndex, Renderer, ModeTemp.Format, ModeTemp.Format, False) >= 0 Then
            cmbRes.AddItem ModeTemp.Width & "x" & ModeTemp.Height & " 16 bit" & "    [FMT: " & ModeTemp.Format & "]"
        End If
    End If
    
Next I

cmbRes.ListIndex = cmbRes.ListCount - 1
End Sub


Once we have retrieved the number of display modes we cycle through them and decide first what bit-depth catergory they go in (16 bit or 32 bit) then we check with Direct3D that the format is going to work with the current device and adapter selection. Once this is done it outputs it to a combo box ready for the user to select which one he/she wants to use. Note the "[FMT: ]" part at the end; this shows you what precise format it's in, 16/32 bit is not enough to base this on, so I've included the information on exactly what format it'll work in.

When you look at the sample code included with this tutorial you will notice that it recalculates the resolutions and devices each time you change the adapter, and it changes the display mode list each time you select a new renderer.


3. Hardware Capability enumeration

The final useful part is to determine what features the hardware supports. This is particularly useful if you want to use a special feature that is hardware dependant and not very common yet (ie, at the cutting edge of technology). Capability enumeration is very simple, but there are 100's (maybe 1000's) or things you can check for.

The first stage is to actually retrieve the information, this is incredibly simple:

'This code assumes that D3D is a valid reference to a Direct3D8 object.

Dim Caps As D3DCAPS8 '//Holds all our information...

D3D.GetDeviceCaps cmbAdapters.ListIndex, Renderer, Caps


Now that we have a structure holding all the information ("Caps") we can query it for what we would like to know. There are lots of different flags that you can look at, all of them listed in VB's Object browser, but it's unlikely that you can guess what they all mean. The DirectX 8 help file lists them all with descriptions if you have it - otherwise you're just going to have to wait until someone tells you (they will be explained as you need them in later lessons) or guess.

Following are some example of how to get information on the hardware capabilities:

If Caps.MaxActiveLights = -1 Then
    List1.AddItem "Maximum Active Lights: Unlimited"
Else
    List1.AddItem "Maximum Active Lights: " & Caps.MaxActiveLights
End If
List1.AddItem "Maximum Point Vertex size: " & Caps.MaxPointSize
List1.AddItem "Maximum Texture Size: " & Caps.MaxTextureWidth & "x" & Caps.MaxTextureHeight
List1.AddItem "Maximum Primatives in one call: " & Caps.MaxPrimitiveCount

If Caps.TextureCaps And D3DPTEXTURECAPS_SQUAREONLY Then
    List1.AddItem "Textures must always be square"
End If

If Caps.TextureCaps And D3DPTEXTURECAPS_CUBEMAP Then
    List1.AddItem "Device Supports Cube Mapping"
End If

If Caps.TextureCaps And D3DPTEXTURECAPS_VOLUMEMAP Then
    List1.AddItem "Device Supports Volume Mapping"
End If

There are more in the sample for this lesson; but the above should be enough - they're all the same apart from the specified flag.


It is recommended that you download the sample code for this lesson so that you can see how a working example looks. The download is at the top of this page.

Once you've understood this part you can proceed onto Lesson 03 : 2D Graphics part 1 - The Basics


Errata

Jill has been kind enough to provide the following tips:

The code in the first area

'Get the name of the current adapter - it's stored as a long
'list of character codes that we need to parse into a string
' - Dont ask me why they did it like this; seems silly really  :) 
sTemp = ""
For j = 0 To 511
    sTemp = sTemp & Chr$(AdapterInfo.Description(j))
Next j
sTemp = Replace(sTemp, Chr$(0), " ")

Can be replaced by this:

'Get the name of the current adapter: It's stored as a byte
'array.  This is probably because in C++ (which DirectX
'was written in), that is what strings really are.
sTemp = Trim$(Replace(StrConv(AdapterInfo.Description, vbUnicode), vbNullChar, " "))

Also by specifying D3DENUM_NO_WHQL_LEVEL (=2) in the flags parameter of Direct3D.GetAdapterIdentifier, you can avoid the 1 to 2 second delay for each adapter just to determine the "Windows Hardware Quality Lab" (WHQL) certification level for this driver and device pair. It really only returns a date, isn't of any real use for identifying the adapter, and as far as I can tell you do not use it in your presented code anyway. That's Seconds, not just milliseconds, off of the startup time.

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster