Help with Device Enumeration

Started by
10 comments, last by Biggles 22 years, 5 months ago
Does anyone know of any tutorials available that explain finding out which devices are available on a system and what modes and stuff they support? I think that it''s called Device Enumeration but I''m not sure. I''ve tried going through the code in the d3dapp.cpp file and I understand some of it, but there is much that I don''t understand, especially about multiple devices, etc. If there arn''t any tutorials, could someone explain the concept here please? -------------------- Never eat anything bigger than your own head.
--------------------Never eat anything bigger than your own head.
Advertisement
Sorry to Biggles if you''ve got e-mail notification of a reply and come here hoping for an answer, but I''d just like to say that I''m curious about this too. Most D3D tutorials don''t go into device enumeration too much and I''ve yet to find a decent book that explains it properly.

RM.



Tron Software

-=Kicking Butt and Writing Code=-
Did you guys take a look at DirectX 7 Enumeration
?
I must have missed that when I did my search. It''s quite a good article, but some of the function calls and methods for doing things appear to have changed between 7 and 8. Does anyone know of a similar article based on DirectX 8?


--------------------

Never eat anything bigger than your own head.
--------------------Never eat anything bigger than your own head.
I find that the DirectX SDK help file is very adequate for this. It provides complete descriptions of the necessary functions, structures and expected behaviors. I'll post some code that I wrote just from dealing with it (I ripped it out of my own code and cleaned it up a little so it's easier to understand):

    // Direct3D8 "Device Enumeration"static LPDIRECT3D8		lp_D3D = NULL;static LPDIRECT3DDEVICE8	lp_D3DDevice = NULL;static unsigned int		s_nAdapters;//...static vector<string>		s_vecDeviceNames;static vector<string>		s_vecDriverNames;static vector<int>		s_vecAdapterModes;//...s_nAdapters = lp_D3D->GetAdapterCount();//...for(int n = 0; n < s_nAdapters; ++n){	D3DADAPTER_IDENTIFIER8 id;	lp_D3D->GetAdapterIdentifier(n, D3DENUM_NO_WHQL_LEVEL, &id);	s_vecDeviceNames.push_back(id.Description);	s_vecDriverNames.push_back(id.Driver);	s_vecAdapterModes.push_back(lp_D3D->GetAdapterModeCount(n));}//...for(int n = 0; n < s_nAdapters; ++n){	cout << s_vecDeviceNames[n] << endl;	cout << s_vecDriverNames[n] << endl;	for(int m = 0; m < s_vecAdapterModes[n]; ++m)	{		lp_D3D->EnumAdapterModes(n, m, &d3ddm);		cout << d3ddm.Width << 'x'			<< d3ddm.Height << 'x'			<< d3ddm.Format << '@'			<< d3ddm.RefreshRate << endl;	}}  


  // DirectInput Device Enumerationstatic LPDIRECTINPUT8	lp_DI = NULL;//...static vector<string>			s_vecDeviceNames;static vector<DIDEVICEINSTANCE>		s_vecDevices;static vector<DIDEVICEOBJECTINSTANCE>	s_vecDeviceObjects;//...HRESULT EnumDevices(DWORD dwDevType, DWORD dwFlags){	// currently I pass nothing to the callback	// I can pass data through the void *	int nDevice = 0;	return lp_DI->EnumDevices(dwDevType, EnumDevicesCallback,		(void *)&nDevice, dwFlags);}//...BOOL CALLBACK EnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, void *pvRef){	s_vecDeviceNames.push_back(lpddi->tszProductName);	// just to show how the passed data can be used, I'll	// increment the passed integer	int i = (int)*pvRef;	++i;	return DIENUM_CONTINUE;}  


I hope you find that useful.
[Edit:] formatting.

Edited by - Oluseyi on November 18, 2001 1:34:03 PM
Thanks, that''s very helpful. I know it sounds stupid, but where in the help files is the stuff about D3D enumeration? I looked around but couldn''t find anything, and when I tried doing a search I found lots for things like DirectPlay and Input, but nothing for D3D.
--------------------Never eat anything bigger than your own head.
If you think about it, you''re not really enumerating devices under D3D (which is why I wrote "device enumeration" in quotes). You query the interface for the number of available adaptors and then query those for their capabilities.

In the Contents panel:
DirectX 8.1 (I''ve migrated)  ->DirectX Graphics    ->Programmer''s Guide      ->Using Direct3D        ->About Devices          ->Using Devices            ->Determining Hardware Support            ->Selecting a Device 
OK, the next thing I''m confused about is where to do this and where to store the info I get out. If I have a D3DDevice class, should I store the info in there? That makes sense to me since a d3ddevice should know what adapters, devices and modes it has available to it. Once I know where, when should it be done? I would assume it should be done before or while creating the device. And finally, how is the info used to select a good default adapter, and what is the best way to save the information needed to select a customised configuration in a config file so that it will load with the user''s preffered option the next time the game loads?


--------------------

Never eat anything bigger than your own head.
--------------------Never eat anything bigger than your own head.
In our (DX8) engine we have an array of D3DAdapterInfo structures. One for each graphics card found in the system. A direct cut & paste:

  typedef struct{    bool                    bValid;             // is this device valid for Paradox use    UINT                    uiAdapterOrdinal;   // required to create device under DX8    D3DADAPTER_IDENTIFIER8  identifier;         // nice name and driver information    D3DCAPS8                caps;               // capabilities of this device    long                    lRating;            // how good is device (score can be -ve)    HMONITOR                hMonitor;           // which monitor is this connected to    UINT                    uiModeCount;        // number of valid modes in the array    UINT                    uiDefaultMode;      // initial default mode    UINT                    uiCurrentMode;      // current mode for this screen    D3DDISPLAYMODE*         modes;              // list of usable modes for device    DWORD                   dwShaderVPUsage;    // usage flags for shader vertex processing ops    DWORD                   dwFixedVPUsage;     // usage flags for fixed vertex processing ops    DWORD                   dwCreationFlags;    // flags for the creation of this adapter}D3DAdapterInfo;  



Depending on the application we either automatically choose a device to start the application with (usually based on it''s rating field *). Or we bring up a dialog box where the user can choose which device and mode to use.

The selection which the user makes is best stored into the registry. The best location will be under HKEY_CURRENT_USER, *NOT* HKEY_LOCAL_MACHINE (remember the computer may have multiple users, each may want to play your game at different resolutions, on a different adapter etc. This is also the reason you shouldn''t just save the settings to a file).

A few hints about storing device selections to the registry:

a. Save the selection just before the application is about to exit, DON''T save it just after the selection has been made. If the setting someone chose crashed your game before it started, the settings won''t get saved so the user will be given the choice again (the correct way).

b. Always have a command line switch or some other method to ignore the settings in the registry and go back to the configuration screen. We do this by installing an extra shortcut which has a command line of -config.

c. When storing selections to the registry, also store some sort of check to see which devices are installed and how many there are (we take a checksum (CRC32) of all their device identifiers and store that), if the checksum doesn''t match what you enumerate at startup, you bring up the settings dialog. This way if the user installs a new graphics card, removes a graphics card, updates their drivers etc they get a new settings dialog.


* We work out a rating for each device when enumerating. Essentially we check all the device caps which affect our engine and add a score to the rating for them. Any caps which indicate problematic cards or functionality we have a negative score for (i.e. subtract from the rating). Other factors such as whether the driver is WHQL certified, which modes and texture formats are available etc are also taken into account. We use the rating to decide which adapter is chosed as default. In situations where there''s a tie, we pick the adapter with the lowest ordinal (since it''s likely to be the primary AGP adapter).
In an ideal world we''d also include some sort of runtime profiling of each device in the rating, but in practice the above seems ok in all the situations it''s been tested in).


--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

I think I may be missing something in the heirarchy here. Correct me if I''m wrong, but is it:

Adapters -> (many) Devices -> (many) Display modes

So for each adapter you find out which devices it has, and for each device which compatible display modes it can run it? Then you let the user choose which adapter to use, which device on that adapter, and which display mode?


--------------------

Never eat anything bigger than your own head.
--------------------Never eat anything bigger than your own head.

This topic is closed to new replies.

Advertisement