For games that use d3dim.dll, how can I check which exact version of Direct3D is used?

eddman

Newcomer
I've been maintaining pages on PCGamingwiki, and for a while have been focusing on checking older games' Direct3D version.

For games that use D3D7 up to 9, it's not too difficult since each variant corresponds to its own dll file, d3dim700.dll, d3d8.dll and d3d9.dll (Also, 8 and 9 can be easily checked with something like RTSS).

For D3D2 to 6, that method doesn't work since all of them are contained in the d3dim.dll file.

Does anyone know a way to find out the exact version?
 
I have practically zero coding knowledge and don't really know what exported symbols is. I've never worked with Visual Studio. PE Explorer is a paid app.

I did open the game exe with Dependency Walker but there doesn't seem to be a d3dim.dll in the list of modules. I don't know how to figure out which file is the renderer DLL.
 
Sorry for posting again; there's no edit for me yet.

Could you please write a step-by-step guide, perhaps using an old game as an example?
 
I have practically zero coding knowledge and don't really know what exported symbols is.

"Symbols" are the text names of global variables and functions, embedded in the "Portable Executable" code object file. These are either required by the executable or DLL file (Dynamic-link_library) to be dynamically linked from other files (i.e. like a renderer DLL will use, or "import", external functions from the Direct3D API) , or those available to external executable files or DLLs for dynamic linking from this file (like the D3D9.DLL lists its functions to provide, or "export", for external games/applications).

The idea is to look for functions/methods or QueryInterface for interfaces added in each new version of Direct3D, like the "7" methods specific to Direct3D 7.x:

Direct3D 2.0/3.0
Direct3D 5.0​
Direct3D 6.x​
Direct3D 7.x​
Jun/Sep 1996Aug 1997Aug 1998Sep 1999
IDirect3D
IDirect3DDevice
IDirect3DMaterial
IDirect3DTexture
IDirect3DViewport
IDirect3DExecuteBuffer

IDirectDraw
IDirectDraw2
IDirectDrawSurface
IDirectDrawSurface2

IDirect3D::Initialize
IDirect3DDevice::Initialize
IDirect3DDevice::Execute
IDirect3DDevice::SetMatrix
IDirect3D2
IDirect3DDevice2
IDirect3DMaterial2
IDirect3DTexture2
IDirect3DViewport2

IDirectDrawSurface3

IDirect3D2::CreateDevice
IDirect3DDevice2::DrawPrimitive
IDirect3DDevice2::DrawIndexedPrimitive
IDirect3DDevice2::SetRenderTarget
IDirect3DDevice2::SetTransform
IDirect3D3
IDirect3DDevice3
IDirect3DMaterial3
IDirect3DViewport3
IDirect3DVertexBuffer

IDirectDraw4
IDirectDrawSurface4

IDirect3D3::CreateVertexBuffer
IDirect3D3::EnumZBufferFormats
IDirect3DDevice3::CreateVertexBuffer
IDirect3DDevice3::DrawPrimitiveVB
IDirect3DDevice3::DrawIndexedPrimitiveVB
IDirect3DDevice3::SetTextureStageState
IDirect3D7
IDirect3DDevice7
IDirect3DVertexBuffer7

IDirectDraw7
IDirectDrawSurface7

I don't know how to figure out which file is the renderer DLL.

Typically the file that contains 'render', 'd3d', 'direct3d' etc. in the name. It would also export some symbols from ddraw.dll.

Could you please write a step-by-step guide, perhaps using an old game as an example?

Unfortunately I do not currently have any older games or tests/demos/benchmarks that use Direct3D 3, 5 or 6.x - I did play Star Wars: Jedi Knight I/II, Star Wars: Shadows of the Empire, Unreal/Unreal Tournament, and Grim Fandando, and some really weird tests/benchmarks too, but this was like 25 years and 4 dead HDDs ago :(
 
Last edited:
Generally a game would be using DX version specified as a minimum in its requirements - which are distributed in readme/manuals in GOG for example.
Sometimes you could find the required/used DX version by doing a simple text search for "direct" string in either the game's EXE or in some renderer DLL.
You could also try using various translation libraries like DXVK, dgVoodoo2, 3DMiGoto, etc - these usually output log files where you can find what DX version a game is requesting. There is no universal tool for this however and finding something for older games can be tricky.
 
I've found some early and quirky Direct3D 3/5 demos, like the "PC Player Direct3D Benchmark 1.10", "Tirtanium 1.90" and "Final Reality 1.01" and tried to run DUMPBIN on the executables.
Unfortunately they only export a few functions from DDRAW.dll, such as DirectDrawEnumerateA and DirectDrawCreate / DirectDrawCreateEx, while the bulk of Direct3D function calling is made through the COM interface - so to see the COM methods mentioned in the post above, you'd need to use a kernel-mode debugger to analyze the function call stack.


A good start would be the Sysinternals Process Explorer, which can analyze the call stack if you configure it to load the debug symbols :



A heavyweight solution would be the Windows Performance Toolkit (WPT), which includes the Windows Performance Recorder (WPR) to capture the program event trace and the graphical Windows Performance Analyzer (WPA) tool to inspect the captured call stack:


 
@eddman Did you try using dgVoodoo2 with debug layer btw? It should output rather verbose information on what a game you're trying to launch is requesting from the API:

Special release version of dgVoodoo contains an additional validator andreport layer. Its purpose is
  • 1) giving feedback to the user about potential error conditions, what currently is happening, and, how dgVoodoo is driven by the application at all
  • 2) helping debugging a given application/game by the (extensive) feedback and opening the possibility to break into the debugger

dgVoodoo currently has 2 main types for debug feedback

Simple messages with 3 subtypes which can be disabled or associatedwith a debugger break

  • INFO: harmless message about various events like creating/releasing an API object, reading a config file, loading a module, etc.
  • WARNING: a message about a potential error condition
  • ERROR: a message about an API driving error or an internal error of dgVoodoo. The latter is fatal, while the prior one may be normal.
Tracing - means the full logging of API calls made to dgVoodoo andsome additional information of dgVoodoo internals.
  • Level 0: Tracing disabled
  • Level 1: Logging of API calls
  • Level 2: Logging of API calls + some additional info
Messages and tracing are independent on each other. Tracing is mainlyfor devs, for quick and average usage only the messages arerecommended.
All of them are written to the debug output, logging to file is not yetimplemented.

So, I recommend you to useDebugViewor much moreDebugView++.They are very cool applications for cases when no any debugger isavailable. Also, if you have more than one monitors then you can watchthe log in realtime: put DebugView++ on one display and run the game onanother.
Haven't tried it myself but it looks promising for older games - considering that dgVoodoo2 is able to emulate as far back as DX1 and DD.
 
I'd tried logging with dgvoodoo2 in the past, but didn't know what to look for. I have a few logs from back then.

When checking this game with Process Explorer or System Informer, I only see d3dim700.dll being loaded, and no d3dim.dll, however, reading the log I can't really see anything that points to D3D7 interfaces, unless I'm not looking correctly.
 
I'd tried logging with dgvoodoo2 in the past, but didn't know what to look for. I have a few logs from back then.
I think you may need to look into setting up tracing with DebugView to see what the app requests from the API.

When checking this game with Process Explorer or System Informer, I only see d3dim700.dll being loaded, and no d3dim.dll, however, reading the log I can't really see anything that points to D3D7 interfaces, unless I'm not looking correctly.
Isn't the fact that the game loads d3dim700.dll enough to say that it's using D3D7?
 
Isn't the fact that the game loads d3dim700.dll enough to say that it's using D3D7?

Of course. The point is it isn't reflected in the log file. I do see Direct3D interfaces, but not D3D7 specific ones. That's why I uploaded the log, in case I'm misreading it.
 
Of course. The point is it isn't reflected in the log file. I do see Direct3D interfaces, but not D3D7 specific ones. That's why I uploaded the log, in case I'm misreading it.
I'm not sure what this means cause it may be just dgVoodoo2 saying something about its own function but it does specify DX7:
00000026 0.17593770 [17748] [dgVoodoo] INFO: DirectDraw (0A305B40) Object implementation is DX7 DirectDraw. Only D3D7 can be used via this one, old D3D device implementations are not available.
Anyway, I'll take a look at what the latest version reports later as it's an interesting problem.
 
Just to clarify, when I wrote "it isn't reflected", I meant in regard to interfaces. There are other indicators that point to D3D7, like the one you posted.
 
Wow, dgVoodoo does a much better job emulating pre-Direct3D9 APIs comparing to Microsoft's built-in emulation layer, which gives me the infamous "CreateSurface for Z-buffer failed. Action not supported" error when I try to run most of the demos mentioned above!

Also having a built-in logging/debug layer is certainly much easier to work with than setting a kernel-mode debugger to capture application stack traces.


not sure what this means

It's just a diagnostic message, a reminder that you can't create earlier Direct3D 3.0/5.0/6.x devices on the DirectDraw 7 interface (and the Direct3D 7 device can only be created with the matching DirectDraw 7 interface), because Direct3D 7 / DirectDraw 7 were a "clean-break API" (that's Microsoft speak for a rip-off from a more successful competitor, in this case SGI/OpenGL), so they didn't really match the previous program flow and data structures.

[dgVoodoo] INFO: DirectDraw (0A305B40) Object implementation is DX7 DirectDraw. Only D3D7 can be used via this one, old D3D device implementations are not available.


The point is it isn't reflected in the log file. I do see Direct3D interfaces, but not D3D7 specific ones
you may need to look into setting up tracing with DebugView to see what the app requests from the API.

These are just non-version specific messages from dgVoodoo itself - you need to enable API call tracing as mentioned above to see actual Direct3D interfaces and GUID references.

Download the dgVoodoo2 dbg release, copy dgVoodooCpl.exe and the DLLs from the MS/x86 subfolder to the game's folder (or the subfolder where the renderer DLL may reside), then run the Cpl to configure the debug layer - right-click on the tabs and choose "Show all sections of the configuration", scroll to the Debug tab and select Maximum trace level to be "+Additional trace info for internals" (the one below "API functions and methods").

Then download and run DebugView++ and you're all set to run the game with Direct3D API tracing enabled!
 
FYI, look for interfaces/methods IDirect3D (Direct3D 2.0/3.0), IDirect3D2 / IDirect3DViewport2 / IDirect3DHALDevice (Direct3D 5.0), IDirect3D3 / IDirectDraw4 / IDirect3DViewport3 (Direct3D 6.x), and IDirect3D7 / IDirectDraw7 etc. listed in the post above.

For example, this trace fom PC Player Direct3D Benchmark 2.10 reveals that Direct3D 2.0/3.0 is used and it renders with Direct3D 2.0/3.0-style ExecuteBuffers.

[dgVoodoo] INFO: DirectDraw (00785908) Object implementation is plain old pre-DX7 DirectDraw. D3D7 cannot be used via this one.
DirectDraw::GetDisplayMode (this = 00785908, lpDDSurfaceDesc2 = 0019FBB8)
DirectDraw::Release (this = 00785908)
DirectDraw::SetCooperativeLevel (this = 00785908, hWnd = 0, dwFlags = 8)
SetCooperativeLevel window: 0, threadId: 40816

[dgVoodoo] INFO: DirectDraw (028B3C60) Object implementation is plain old pre-DX7 DirectDraw. D3D7 cannot be used via this one.
DirectDraw::QueryInterface (this = 028B3C60, riid = {6c14db80-a733-11ce-a521-0020af0be560} (IID_IDirectDraw), ppvObject = 0041A7BC)
DirectDraw::QueryInterface (this = 028B3C60, riid = {3bba0080-2421-11cf-a31a-00aa00b93356} (IID_IDirect3D), ppvObject = 0041A7C0)
[dgVoodoo] INFO: GetD3DInterface: Trying to load D3DImm.
Direct3D::AddRef (this = 10596E50, rclsiid = IID_IDirect3D)
[dgVoodoo] INFO: DirectDraw (028B3C60)::QueryInterface: Aggregated Direct3D (10596E50) object is created and initialized.
Direct3D::QueryInterface (this = 10596E50, riid = IID_IDirect3D, ppvObject = 0041A7C0)


Direct3D::CreateViewport (this = 103AFF90, lplpViewPort = 0019FBB4, pUnkOuter = 00000000)
Direct3DViewport::Initialize (this = 1057CD18)
Direct3DViewport::QueryInterface (this = 1057CD18, riid = IID_IDirect3DViewport, ppvObject = 0019FBB4)
[dgVoodoo] INFO: Direct3D (103AFF90)::CreateViewport: Direct3DViewport (1057CD18) is created.
Direct3DDevice::AddViewport (this = 109D8530, lpDirect3DViewport = 1057CD18)
Direct3DViewport::AddRef (this = 1057CD18)


This one from Tirtanium 1.40 means Direct3D 6.x is used (IDirect3D3 device type and DrawPrimitive method calls):

[dgVoodoo] INFO: DirectDraw (007C8E10) Object implementation is plain old pre-DX7 DirectDraw. D3D7 cannot be used via this one.
DirectDraw::QueryInterface (this = 007C8E10, riid = {6c14db80-a733-11ce-a521-0020af0be560} (IID_IDirectDraw), ppvObject = 024723AC)
DirectDraw::QueryInterface (this = 007C8E10, riid = {9c59509a-39bd-11d1-8c4a-00c04fd930c5} (IID_IDirectDraw4), ppvObject = 024723B0)
[dgVoodoo] INFO: DirectDraw (007C8E10)::QueryInterface: Aggregated Direct3D (1199AEF8) object is created and initialized.
Direct3D::QueryInterface (this = 1199AEF8, riid = IID_IDirect3D3, ppvObject = 024723C4)
[dgVoodoo] INFO: GetD3DInterface: Trying to load D3DImm.
Direct3D::CreateDevice (this = 1199AEF8, deviceClassId = IID_IDirect3DHALDevice, lpRenderTarget = 1198ED10, lplpDevice3D = 024723C8)
Direct3D::AddRef (this = 1199AEF8)
Direct3DDevice::QueryInterface (this = 11A15CD8, riid = IID_IDirect3DDevice3, ppvObject = 024723C8)
Direct3DDevice::SetRenderTarget (this = 11A15CD8, lpRenderTarget = 1198ED10, dwFlags = 0)
DirectDrawSurface::AddRef (this = 1198ED10)
DirectDrawSurface::AddRef (this = 119D4E80)

[dgVoodoo] INFO: Direct3D (1199AEF8)::CreateDevice: Direct3DDevice (11A15CD8) is created on render target DirectDrawSurface (1198ED10), depth/stencil DirectDrawSurface (119D4E80), device ClassID: IID_IDirect3DHALDevice
Direct3D::CreateViewport (this = 1199AEF8, lplpViewPort = 024723CC, pUnkOuter = 00000000)
Direct3D::AddRef (this = 1199AEF8)
Direct3DViewport::Initialize (this = 11A4AAD0)
Direct3DViewport::QueryInterface (this = 11A4AAD0, riid = IID_IDirect3DViewport3, ppvObject = 024723CC)

And this trace from Tirtanium 1.90 means Direct3D 7.x is used (IDirect3D7 device type):

[dgVoodoo] INFO: DirectDraw (00828F00) Object implementation is DX7 DirectDraw. Only D3D7 can be used via this one, old D3D device implementations are not available.
DirectDraw::QueryInterface (this = 00828F00, riid = {15e65ec0-3b9c-11d2-b92f-00609797ea5b} (IID_IDirectDraw7), ppvObject = 02542E9C)
DirectDrawSurface::QueryInterface (this = 126DF2B0, riid = {IID_IDirectDrawSurface7}, ppvObject = 02542EA0)

[dgVoodoo] INFO: DirectDraw (00828F00)::QueryInterface: Aggregated Direct3D (127336A8) object is created and initialized.
Direct3D::QueryInterface (this = 127336A8, riid = IID_IDirect3D7, ppvObject = 02542EB0)
Direct3D::EnumZBufferFormats (this = 127336A8, riidDevice = IID_IDirect3DHALDevice, lpCallback = 004151B0, lpContext = 19ecc4)
Direct3D::CreateDevice (this = 127336A8, deviceClassId = IID_IDirect3DHALDevice, lpRenderTarget = 12727ED8, lplpDevice3D = 02542EB4)
Direct3D::AddRef (this = 127336A8)
Direct3DDevice::QueryInterface (this = 1286F3B8, riid = IID_IDirect3DDevice7, ppvObject = 02542EB4)
Direct3DDevice::SetRenderTarget (this = 1286F3B8, lpRenderTarget = 12727ED8, dwFlags = 0)
DirectDrawSurface::AddRef (this = 12727ED8)
DirectDrawSurface::AddRef (this = 127C25F0)
[dgVoodoo] INFO: Direct3D (127336A8)::CreateDevice: Direct3DDevice (1286F3B8) is created on render target DirectDrawSurface (12727ED8), depth/stencil DirectDrawSurface (127C25F0), device ClassID: IID_IDirect3DHALDevice
Direct3DDevice::SetViewport (this = 1286F3B8, lpViewport = 02542EB8)
 
Last edited:
Yeah, I've played with this for a bit and tracing level 2 (maybe 1 also, didn't check) provide the needed info - even if the resulting log is quite a bit messy and it take some time to parse through it:

Code:
26    0.847614    17028    DungeonSiege.exe    [dgVoodoo] INFO: DirectDraw (05097418) Object implementation is DX7 DirectDraw. Only D3D7 can be used via this one, old D3D device implementations are not available.
29    221.166995    11884    DungeonSiege.exe    DirectDraw::QueryInterface (this = 05094A58, riid = {15e65ec0-3b9c-11d2-b92f-00609797ea5b} (IID_IDirectDraw7), ppvObject = 0019F560)
30    221.167017    11884    DungeonSiege.exe    DirectDraw::QueryInterface (this = 05094A58, riid = {f5049e77-4861-11d2-a407-00a0c90629a8} (IID_IDirect3D7), ppvObject = 0019F554)
33    221.171298    11884    DungeonSiege.exe    Direct3D::AddRef (this = 0B11DC58, rclsiid = IID_IDirect3D7)
35    221.173771    11884    DungeonSiege.exe    Direct3D::QueryInterface (this = 0B11DC58, riid = IID_IDirect3D7, ppvObject = 0019F554)

25    5.403811    15864    go_start.exe    [dgVoodoo] INFO: DirectDraw (0B16A490) Object implementation is plain old pre-DX7 DirectDraw. D3D7 cannot be used via this one.
65    5.484830    15864    go_start.exe    DirectDraw::QueryInterface (this = 0B16A490, riid = {bb223240-e72b-11d0-a9b4-00aa00c0993e} (IID_IDirect3D3), ppvObject = 01185768)

94    89.240434    17708    MM8-Rel.exe    [dgVoodoo] INFO: DirectDraw (095B0728) Object implementation is plain old pre-DX7 DirectDraw. D3D7 cannot be used via this one.
97    89.240552    17708    MM8-Rel.exe    DirectDraw::QueryInterface (this = 095B0728, riid = {6c14db80-a733-11ce-a521-0020af0be560} (IID_IDirectDraw), ppvObject = 0019F4E0)
98    89.240581    17708    MM8-Rel.exe    DirectDraw::QueryInterface (this = 095B0728, riid = {9c59509a-39bd-11d1-8c4a-00c04fd930c5} (IID_IDirectDraw4), ppvObject = 0019F4E4)
131    89.241696    17708    MM8-Rel.exe    DirectDraw::QueryInterface (this = 095B0728, riid = {bb223240-e72b-11d0-a9b4-00aa00c0993e} (IID_IDirect3D3), ppvObject = 0019F4B0)
134    89.244580    17708    MM8-Rel.exe    Direct3D::AddRef (this = 0F229148, rclsiid = IID_IDirect3D3)
136    89.246658    17708    MM8-Rel.exe    Direct3D::QueryInterface (this = 0F229148, riid = IID_IDirect3D3, ppvObject = 0019F4B0)

Deciphering this isn't quite straight forward though.
IID_IDirect3D3 doesn't mean that the game is using D3D3.
Depending on what the game is requesting from the API alongside the IID_IDirect3D3 interface it can be either D3D3, D3D5 or D3D6.

Download the dgVoodoo2 dbg release, copy dgVoodooCpl.exe and the DLLs from the MS/x86 subfolder to the game's folder (or the subfolder where the renderer DLL may reside), then run the Cpl to configure the debug layer - right-click on the tabs and choose "Show all sections of the configuration", scroll to the Debug tab and select Maximum trace level to be "+Additional trace info for internals" (the one below "API functions and methods").
Can be done much easier - just copy the dgVoodoo.conf file from dgVoodoo2's folder into the game folder and change the MaxTraceLevel variable to 2 in it. You can then just copy the same file to folders of games you want to check (alongside the dgVoodoo2's DLLs of course).
 
Depending on what the game is requesting from the API alongside the IID_IDirect3D3 interface it can be either D3D3, D3D5 or D3D6.

IID is 'interface ID', a predefined GUID (globally unique identifier) for this specific interface version.

Yes, you can also look for rendering methods that were specific to each new release, like Execute vs DrawPrimitive / SetRenderTarget and CreateVertexBuffer / DrawPrimitiveVB / SetTextureStageState - though in practice, if the game is querying for a specific device interface, you'd invariably find that it uses at least some methods from that interface.


But that's largely of academic interest though, because Direct3D 5.0/6.x were arguably point releases of Direct3D 2.0/3.0 (which was derived from a software-based 3D renderer by RenderMorphics). There are few 'native' Direct3D 2.0/3.0 titles, since most games from that era have been updated with subsequent game patches to use Direct3D 5.0 DrawPrimitive and Direct3D 6.x vertex buffers and texture stages, and even 'competing' APIs like Glide and miniGL/OpenGL, so they could make a better use of emerging 3D rendering hardware like 3dfx Voodoo, Rendition Verite V2200, and Nvidia Riva TNT, as they were much faster than early 'Direct3D accelerators' like Rendition Verite V1000 (Creative 3D Blaster PCI) and S3 ViRGE DX (Diamond Stealth3D 2000) which didn't support these new features.

Some of these games evolved quite radically in the process, like id software Quake, which went through iterations like the original DOS application with a software renderer in mid-1996, to VQuake for DOS by end of 1996, a cancelled Direct3D 3.0 port, GLQuake for Windows 9x (miniGL/OpenGL) in early 1997, and finally WinQuake for Windows9x (software rendering, again) in mid-1997.


BTW we had an earlier discussion of Direct3D 2.0/3.0 game lists on PCGamingWiki:


just copy the dgVoodoo.conf file from dgVoodoo2's folder into the game folder and change the MaxTraceLevel variable to 2 in it.
Yes, that's also an option.
 
Wow, dgVoodoo does a much better job emulating pre-Direct3D9 APIs comparing to Microsoft's built-in emulation layer, which gives me the infamous "CreateSurface for Z-buffer failed. Action not supported" error when I try to run most of the demos mentioned above!

Yea, it does a great job. It's practically the only wrapper that can wrap D3D2-7 into D3D11/12. I just wish there was an XP compatible release for wrapping into D3D9.

These are just non-version specific messages from dgVoodoo itself - you need to enable API call tracing as mentioned above to see actual Direct3D interfaces and GUID references.

Damn, I thought I had it properly set up back when I did all those tests. So I had it wrong all along; spent days testing dozens of games without realizing it. *facepalm*

BTW we had an earlier discussion of Direct3D 2.0/3.0 game lists on PCGamingWiki:

The Direct3D lists are a mess, specially the ones for D3D2 up to 8. I've been trying to clean them up, starting with D3D8.

They were determining the Direct3D version based on which DirectX version the is listed in the requirements, or which one the game installs. That's just a terrible way of going about it.

For example, there are quite a few games that require or come with DirectX 8 or 8.1 installers, and yet do not even touch d3d8.dll.

I had to have a long conversation before they accepted to change how it's determined.
 
But that's largely of academic interest though, because Direct3D 5.0/6.x were arguably point releases of Direct3D 2.0/3.0 (which was derived from a software-based 3D renderer by RenderMorphics). There are few 'native' Direct3D 2.0/3.0 titles, since most games from that era have been updated with subsequent game patches to use Direct3D 5.0 DrawPrimitive and Direct3D 6.x vertex buffers and texture stages, and even 'competing' APIs like Glide and miniGL/OpenGL, so they could make a better use of emerging 3D rendering hardware like 3dfx Voodoo, Rendition Verite V2200, and Nvidia Riva TNT, as they were much faster than early 'Direct3D accelerators' like Rendition Verite V1000 (Creative 3D Blaster PCI) and S3 ViRGE DX (Diamond Stealth3D 2000) which didn't support these new features.
Yes but still worth remembering that all D3D2-6 games will request the same IID_IDirect3D3 interface. As you've wrtitten above one should look at what devices are being created/initialized after that to figure out which specific D3D version is being used.
 
Back
Top