Hi
This snippet gives you a good string identifier for each adapter


     mov edi, $ICall(.pID3D::IDirect3D9.GetAdapterCount)
     xor ebx, ebx
     .while ebx < edi
       ICall .pID3D::IDirect3D9.GetAdapterIdentifier, ebx, 0, addr AdapterInfo
       @invoke wsprintf, addr bBuffer, "%u - %s", ebx, addr AdapterInfo.Description
       invoke SendDlgItemMessage, .hWnd, IDC_DXS_ADAPTERS, CB_ADDSTRING, 0, addr bBuffer
        ...
       inc ebx
     .endw


Regards

Biterider
Posted on 2009-07-11 04:20:30 by Biterider
Thanks Biterider, but that is what I'm doing... The problem ti_mo_n describes is when you have one adapter, with two outputs. D3D9 doesn't really have a distinction between adapter and display, so it enumerates the same adapter twice, so you get the same description. The difference is the monitor attached, but I don't know how to get that info. It seems they 'forgot' this in the API :)
In D3D10 you get one adapter, with two displays. The only problem I have there is that it returns \\DISPLAY1 rather than the actual device name. But I suppose if you have \\DISPLAY1, you could get the actual name from the registry somehow, with the SetupAPI or something. With D3D9 I have no idea what to do.
Posted on 2009-07-11 05:00:52 by Scali
Tried prior to the DX update, nothing. After, nothing... methinks some error-handling is in order. ;)

AMD 4000+ Dual, WinXP Pro x64 SP2, GeForce 8600GTS, dual monitors.
Posted on 2009-07-11 10:08:39 by MarkJ

Tried prior to the DX update, nothing. After, nothing... methinks some error-handling is in order. ;)

AMD 4000+ Dual, WinXP Pro x64 SP2, GeForce 8600GTS, dual monitors.


Thing is, I wasn't really planning on doing any work on XP/D3D9 anymore :P
Posted on 2009-07-11 10:25:27 by Scali
You should. Majority of people don't have Vista and wait for Windows 7 (or don't plan to switch at all in the nearest furute). And even after Windows 7 is out there will still be many users using XP. D3D9 isn't going to die very soon :)

About monitor: I don't remember exactly (and for some strange reason I can't find my app where I do it -- Murphy doesn't like me) but from what I do remember is that you have to use D3D9->GetAdapterMonitor and Winapi's GetMonitorInfo and EnumDisplayMonitors. Then you have to play correctly with RECT structures, IIRC. The names you get aren't guaranteed to be real names of outputs but at least they give users some way to distinguish between the options they get.
Posted on 2009-07-11 10:46:30 by ti_mo_n

You should. Majority of people don't have Vista and wait for Windows 7. And even after Windows 7 is out there will still be many users using XP. D3D9 isn't going to die very soon :)


Problem is, if we don't stop supporting them, we'll NEVER get rid of XP/DX9.
I have to develop and test my code for both DX9 and DX10, and test it on XP and Vista. The differences are just too large, and it takes too much effort.
I prefer spending all my time on DX10/11. The DX9 code is pretty old by now, so it should work on most systems anyway, haven't really had troubles in years. I wasn't planning on doing much work on it anymore.


About monitor: I don't remember exactly (and for some strange reason I can't find my app where I do it -- Murphy doesn't like me) but from what I do remember is that you have to use D3D9->GetAdapterMonitor and Winapi's GetMonitorInfo and EnumDisplayMonitors. Then you have to play correctly with RECT structures, IIRC. The names you get aren't guaranteed to be real names of outputs but at least they give users some way to distinguish between the options they get.


Thanks, I'll see if I can make that work for me :)
Posted on 2009-07-11 10:58:29 by Scali
I know that rendering stops when it's minimized, but it should start again when it's resized to anything else...

It works in windowed mode but not in fullscreen. When in fullscreen mode, minimizing and then maximizing stops the rendering.

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

I have found the app. I have also attached the image showing how it looks like on my machine.

Here is the relevant code:
INT __cdecl _tmain(INT argc, _TCHAR* argv[]) {
 union {
   MONITORINFOEX mie;
   TCHAR dummy[(sizeof(MONITORINFOEX)+1)];
 };
 IDirect3D9 *d3d9;
 UINT adcnt, i;
 HMONITOR hm;

 if (!(d3d9 = Direct3DCreate9(D3D_SDK_VERSION))) {
   _tprintf(TEXT("Direct3DCreate9 failed!\n"));
   return 1;
 }

 if ((adcnt = d3d9->GetAdapterCount())) {
   for (i = 0; i < adcnt; i++) {
     _tprintf(TEXT("adapter %u: "), i);
     if ((hm = d3d9->GetAdapterMonitor(i))) {
       mie.cbSize = sizeof(mie);
       dummy = 0;
       if (GetMonitorInfo(hm, &mie)) {
         _tprintf(TEXT("%s"), &mie.szDevice);
         if (mie.dwFlags & MONITORINFOF_PRIMARY) {
           _tprintf(TEXT(" (PRIMARY)"));
         }
         _tprintf(TEXT("\n"));
       }
       else {
         _tprintf(TEXT("(GetMonitorInfo failed!)\n"));
       }
     }
     else {
       _tprintf(TEXT("<null>\n"));
     }
   }
 }

 d3d9->Release();
 d3d9 = NULL;

return 0;
}



Note that the primary display doesn't have to be the first one.
Attachments:
Posted on 2009-07-11 11:47:33 by ti_mo_n
Ah okay...
What I was wondering... how can you get the names of the actual displays as you see them in Control Panel or Device Manager for example?
Eg, in the Display Settings I actually see "Samsung 770P on GeForce 8800GTS..."
I wonder how I can get from "\\DISPLAY1" and such to the actual devicename. I think that's the best possible information for letting a user decide which display to use.
Posted on 2009-07-11 12:16:01 by Scali
I guess your only option is WMI but this is completely black magic to me. I've seen some examples on the Internet showing nice monitor names retrieved using WMI.
Posted on 2009-07-11 12:31:48 by ti_mo_n
I have done some research into the subject. There is an easy way to get useful info about all display outputs in the system. You can use Nvidia Control Panel API. Unfortunately it works only with NVIDIA drivers (but I guess ATI has a similar library). Another problem is that you only get only 64-bit version of the dll with 64-bit drivers and only 32-bit version with 32-bit ones. So on 64-bit system (with 64-bit drivers) a 32-bit app can't use it. It's possible to work this around by having a dummy 64-bit process and communicating with it via any IPC mechanism.

A sample and pdf can be downloaded here: NVIDIA Control Panel API.

I have also attached my own example.
Attachments:
Posted on 2009-07-15 19:23:06 by ti_mo_n
Thanks, but vendor-specific solutions are exactly what I want to avoid.
I think the answer lies somewhere in this part of the registry:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY
That's where the known monitors are listed, with their descriptive names. Now I have to somehow relate that to the DX info.
Posted on 2009-07-16 06:58:04 by Scali
It requires monitor drivers to be installed and it won't tell you anything about TVs and physical resolutions, etc. Since 2 vendors control, like, 99% of the graphics card market, I guess it's not a big problem to use their APIs ^^
Posted on 2009-07-16 08:38:32 by ti_mo_n

It requires monitor drivers to be installed and it won't tell you anything about TVs and physical resolutions, etc. Since 2 vendors control, like, 99% of the graphics card market, I guess it's not a big problem to use their APIs ^^


Well, I often develop on my laptop, with an Intel graphics chip :)
If monitor drivers aren't installed, I guess it's fine to just have 'default monitor' or just '\\DISPLAY1' or such. But in most cases, drivers are installed, because lots of them are either bundled with Windows, or available on Update.

Intel has the biggest marketshare, and will get even bigger when Larrabee is out. And then there are S3 and Matrox. I want to support them all.
Posted on 2009-07-16 09:14:12 by Scali
Oh, I was talking about desktops. So, well, You can always write this like I did in the application I attached earlier: It uses Nvidia CPL and (in case of error) defaults to "\\.\DisplayX". I personally prefer to know more than less about the hardware my app is running on ^^
Posted on 2009-07-16 10:14:49 by ti_mo_n
Well, I've found something...

With EnumDisplayDevices() you can get the monitor name. Normally you'd use it to enumerate by index. Then it will just give you all \\.\DISPLAYx device names and corresponding adapter names.
However, if you pass the device name, and pass index 0, it will instead give you more info about that device, including the actual monitor name in the DeviceString, rather than the adapter name.

So what I do now is simple: I first get the hMonitor, then use GetMonitorInfo() to get the \\.\DISPLAYx device name, then use EnumDisplayDevices() to resolve it to the actual monitor name.

Works for both D3D9 and D3D10/11, because with DXGI you also get the \\.\DISPLAYx name of the output, which you'll plug into EnumDisplayDevices().
Posted on 2009-07-18 07:54:35 by Scali
Nice ^^ I'll see if it works with TVs.
Posted on 2009-07-18 08:03:58 by ti_mo_n

Nice ^^ I'll see if it works with TVs.


It should return the exact same monitor names as what you see in the display properties in Control Panel (the regular Windows control panel that is).
My TV uses standard s-video, so I only get "Generic P&P monitor" or something.
I suppose if your TV has a VGA, DVI or HDMI connector, it can use the DDC protocol to identify itself, and have Windows automatically install the proper .inf file for the monitor, to give it a descriptive name.
So I don't think there's any way that a hardware-specific solution would get more info than standard Windows.
Posted on 2009-07-18 17:02:19 by Scali
From what I see, Windows doesn't query for physical resolution (in case of Digital Flat Panels) or optimal resolution (in case of CRTs).
Posted on 2009-07-18 19:36:25 by ti_mo_n

1) It shows 2 exactly same strings for 2 different display outputs (I have 1 monitor and 1 HDTV attached to a GeForce 9600 GT -- see attached image). You should enumerate available monitors attached to the selected adapter and include their names in the selection strings.


This is solved now, with the name that EnumDisplayDevices() displays.


2) Minimizing then maximizing stops the rendering (displays black screen).


I've had a small look at this problem, and it seems to be specifically related to DX9 and multiple displays.
In DX10, the rendering stops when the window loses focus. This is by design (originally I wrote the code for a single display, and losing focus meant that you alt-tabbed away from the application, at which point I didn't want my application to hog the CPU. Alt-tabbing back into the application would bring it back to life). If the window regains focus, it continues rendering again.

In DX9 however, it seems that there's more going on. If I so much as click on the desktop on the other monitor, the window loses its fullscreen state and goes back to windowed mode. It doesn't know how to recover from this situation, because it should never happen (it doesn't, on a single display. The window is still 'fullscreen', even though it's not visible).
In short, I don't know what causes it, or how to fix it. There is code in my application to automatically reset the device when required. This is why resizing and alt-enter to switch between fullscreen and windowed mode just works. But somehow it doesn't recover from this situation.

I don't feel like wasting more time on it, because it only happens in DX9. I want to concentrate on DX11 from now on, DX9 is only there for legacy support and for that it's 'good enough' right now, the problem can easily be avoided. But if someone knows a fix, I might implement it.


3) There is no acpect-ratio compensation. The ring is elliptic at 16:9. It would be even more elliptic at 2.39:1.


Solved, the aspect-ratio fields in the initialization dialog are now used to create a perspective matrix.
Posted on 2009-07-21 03:17:08 by Scali
Can I test it? ^^
Posted on 2009-07-21 10:34:45 by ti_mo_n