GPU Name

Windows specific forum
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

GPU Name

Post by IdeasVacuum »

How to find (programmatically) the Graphics Card/GPU Manufacturer/Name/Model and, if OpenGL is supported, the OpenGL version?

Performed a manual search of the registry, nothing man readable in the Hardware list but in the Software list some graphics apps have recorded this info - how did they find it though?

Edit: Possibly using WMI
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4997
Joined: Sun Apr 12, 2009 6:27 am

Re: GPU Name

Post by RASHAD »

Hi

Code: Select all

#COINIT_MULTITHREAD=0 
#RPC_C_AUTHN_LEVEL_CONNECT=2 
#RPC_C_IMP_LEVEL_IDENTIFY=2 
#EOAC_NONE=0 
#RPC_C_AUTHN_WINNT=10 
#RPC_C_AUTHZ_NONE=0 
#RPC_C_AUTHN_LEVEL_CALL=3 
#RPC_C_IMP_LEVEL_IMPERSONATE=3 
#CLSCTX_INPROC_SERVER=1 
#wbemFlagReturnImmediately=16 
#wbemFlagForwardOnly=32 
#IFlags = #wbemFlagReturnImmediately + #wbemFlagForwardOnly 
#WBEM_INFINITE=$FFFFFFFF 
#WMISeparator="," 

Procedure.l ansi2bstr(ansi.s) 
  size.l=MultiByteToWideChar_(#CP_ACP,0,ansi,-1,0,0) 
  Dim unicode.w(size) 
  MultiByteToWideChar_(#CP_ACP, 0, ansi, Len(ansi), unicode(), size) 
  ProcedureReturn SysAllocString_(@unicode()) 
EndProcedure 

Procedure bstr2string (bstr) 
  Shared WMIResult.s 
  WMIResult.s = "" 
  pos=bstr 
  While PeekW (pos) 
    WMIResult=WMIResult+Chr(PeekW(pos)) 
    pos=pos+2 
  Wend 
  ProcedureReturn @WMIResult 
EndProcedure 

ProcedureDLL.s WMI(WMICommand.s) 
  CoInitializeEx_(0,#COINIT_MULTITHREAD) 
  hres=CoInitializeSecurity_(0, -1,0,0,#RPC_C_AUTHN_LEVEL_CONNECT,#RPC_C_IMP_LEVEL_IDENTIFY,0,#EOAC_NONE,0) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoInitializeSecurity", #MB_OK): Goto cleanup: EndIf 
  hres=CoCreateInstance_(?CLSID_WbemLocator,0,#CLSCTX_INPROC_SERVER,?IID_IWbemLocator,@loc.IWbemLocator) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoCreateInstance", #MB_OK): Goto cleanup: EndIf 
  hres=loc\ConnectServer(ansi2bstr("root\cimv2"),0,0,0,0,0,0,@svc.IWbemServices) 
  If hres <> 0: MessageRequester("ERROR", "unable to call IWbemLocator::ConnectServer", #MB_OK): Goto cleanup: EndIf 
  hres=svc\QueryInterface(?IID_IUnknown,@pUnk.IUnknown) 
  hres=CoSetProxyBlanket_(svc,#RPC_C_AUTHN_WINNT,#RPC_C_AUTHZ_NONE,0,#RPC_C_AUTHN_LEVEL_CALL,#RPC_C_IMP_LEVEL_IMPERSONATE,0,#EOAC_NONE) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoSetProxyBlanket", #MB_OK): Goto cleanup: EndIf 
  hres=CoSetProxyBlanket_(pUnk,#RPC_C_AUTHN_WINNT,#RPC_C_AUTHZ_NONE,0,#RPC_C_AUTHN_LEVEL_CALL,#RPC_C_IMP_LEVEL_IMPERSONATE,0,#EOAC_NONE) 
  If hres <> 0: MessageRequester("ERROR", "unable to call CoSetProxyBlanket", #MB_OK): Goto cleanup: EndIf 
  pUnk\Release() 
  
  
  k=CountString(WMICommand,#WMISeparator) 
  Dim wmitxt$(k) 
  For i=0 To k 
    wmitxt$(i) = StringField(WMICommand,i+1,#WMISeparator) 
  Next 
  
  hres=svc\ExecQuery(ansi2bstr("WQL"),ansi2bstr(wmitxt$(0)), #IFlags,0,@pEnumerator.IEnumWbemClassObject) 
  If hres <> 0: MessageRequester("ERROR", "unable to call IWbemServices::ExecQuery", #MB_OK): Goto cleanup: EndIf 
  hres=pEnumerator\reset() 
  Repeat 
  hres=pEnumerator\Next(#WBEM_INFINITE, 1, @pclsObj.IWbemClassObject, @uReturn) 
  For i=1 To k 
    mem=AllocateMemory(1000) 
    hres=pclsObj\get(ansi2bstr(wmitxt$(i)), 0, mem, 0, 0) 
    Type=PeekW(mem) 
    Select Type 
      Case 8 
        val.s=PeekS(bstr2string(PeekL(mem+8))) 
      Case 3 
        val.s=Str(PeekL(mem+8)) 
      Default 
        val.s="" 
    EndSelect 
    If uReturn <> 0: wmi$=wmi$+wmitxt$(i)+" = "+val+Chr(10)+Chr(13): EndIf 
    FreeMemory(mem) 
  Next 
Until uReturn = 0 

cleanup: 
svc\Release() 
loc\Release() 
pEnumerator\Release() 
pclsObj\Release() 
CoUninitialize_() 

ProcedureReturn wmi$ 
EndProcedure 

DataSection 
CLSID_IEnumWbemClassObject:
Data.l $1B1CAD8C 
Data.w $2DAB, $11D2 
Data.b $B6, $04, $00, $10, $4B, $70, $3E, $FD 
IID_IEnumWbemClassObject:
Data.l $7C857801 
Data.w $7381, $11CF 
Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24 
CLSID_WbemLocator:
Data.l $4590F811 
Data.w $1D3A, $11D0 
Data.b $89, $1F, $00, $AA, $00, $4B, $2E, $24 
IID_IWbemLocator:
Data.l $DC12A687 
Data.w $737F, $11CF 
Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24 
IID_IUnknown:
Data.l $00000000 
Data.w $0000, $0000 
Data.b $C0, $00, $00, $00, $00, $00, $00, $46 

EndDataSection 



MessageRequester("WMI",WMI("SELECT * FROM Win32_VideoController,DeviceID,Caption,AdapterDACType,DriverVersion,InstalledDisplayDrivers,CurrentBitsPerPixel,CurrentRefreshRate,CurrentHorizontalResolution,CurrentVerticalResolution" )) 

Egypt my love
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: GPU Name

Post by luis »

IdeasVacuum wrote:How to find (programmatically) the Graphics Card/GPU Manufacturer/Name/Model and, if OpenGL is supported, the OpenGL version?
OpenGL would require some work. In the end you can use glGetString_(#GL_VERSION), but to call that you must have a valid opengl compatible device context. Look for nehe opengl lesson #1 on internet or the port available in this forum, cut and paste and add the glGetString_ above !

http://www.opengl.org/wiki/GlGetString# ... VERSION.29
"Have you tried turning it off and on again ?"
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: GPU Name

Post by IdeasVacuum »

Hi Rashad

That's a meaty piece of code, thank you :D

It's totally foreign to me so I'm struggling with the errors. Line 42 pops-up an error message "unable to call IWbemLocator::ConnectServer", and then redirects to cleanup, which crashes with an invalid memory access. That apparently is because the svc struct is not defined?
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: GPU Name

Post by IdeasVacuum »

Hi Luis

Thank you - I think I should be able to figure that one out. I'm not actually creating a program that uses OpenGL but I need to check the OpenGL version available as my app is an add-on to another app that does depend on it, but is not necessarily compatible with all OpenGL versions.

Have got a strange thing going on with PB already though, with incomplete code. I have set OpenGL as the only Library Subsystem.

Code: Select all

#GL_VERSION = $1F02

sGlVersion.s = glGetString_(#GL_VERSION)

Debug sGlVersion
With the above code, the PB compiler fails with this error message:

Line 3: Can't write a numerical value into a string variable.

If I change the var to a long, PB is happy with it but of course the function is going to return a string.......tricky.

EDIT: Tried the following instead, same failure:

Code: Select all

#GL_VERSION = $1F02

Import "Opengl32.lib"
   glGetString(a.l)
EndImport

sGlVersion.s = glGetString(#GL_VERSION)

Debug sGlVersion
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
citystate
Enthusiast
Enthusiast
Posts: 638
Joined: Sun Feb 12, 2006 10:06 pm

Re: GPU Name

Post by citystate »

my guess would be that glGetString_() is returning a pointer
try

Code: Select all

sGlVersion.s = PeekS(glGetString_(#GL_VERSION))
or (as a last resort)

Code: Select all

sGlVersion.s = Str(glGetString_(#GL_VERSION))
there is no sig, only zuul (and the following disclaimer)

WARNING: may be talking out of his hat
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8452
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: GPU Name

Post by netmaestro »

The opengl functions require a valid rendering surface. You must choose "opengl" as subsystem in your compiler options, choose ansi executable (not unicode), then you may try this code and you should get something:

Code: Select all

#GL_VERSION = $1F02

Import "Opengl32.lib"
  glGetString(a)
EndImport

InitSprite()
OpenScreen(800,600,32,"")

; Now we have a valid context, let's try a function..
sGlVersion$ = PeekS(glGetString(#GL_VERSION))

CloseScreen()

Debug sGlVersion$
I get "1.4.0 - Build 8.15.10.1912" here. Your mileage may vary. Proceed to cash 'n carry.
BERESHEIT
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: GPU Name

Post by IdeasVacuum »

Ah, should have realised it would not simply be a string.

That works well netmaestro, my result is "2.1.2".

I think my customers will find the 'whole screen goes black' alarming (they are infrequent users of PCs). So, I changed the OpenScreen() size to 100*100, which draws a mini screen of that size but fails the glGetString function '[ERROR] Specified address is null'. That seems strange to me, but a tiny WindowedScreen works OK. If anyone else needs it, here is the final code snippet:

Code: Select all

#GL_VERSION = $1F02

Import "opengl32.lib"
  glGetString(a)
EndImport

InitSprite()
WinId = OpenWindow(0, 0, 0, 100, 100, "OpenGL")
OpenWindowedScreen(WinId,0,0,100,100,0,0,0)

; Now we have a valid context, let's try a function..
sGlVersion$ = PeekS(glGetString(#GL_VERSION))

CloseScreen()

Debug sGlVersion$
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: GPU Name

Post by luis »

Sorry I was sleeping :)

Yes, if you can use the opengl subsystem shortcut then the code from netmaestro is the fastest way!

BTW, you can avoid to import the ogl function for this simple snippets if you like.

Keep in mind the OGL version is X.Y the rest is vendor dependent.

This should always work:

Code: Select all

#GL_VERSION = $1F02

InitSprite()
WinId = OpenWindow(0, 0, 0, 100, 100, "OpenGL")
OpenWindowedScreen(WinId,0,0,100,100,0,0,0)

; Now we have a valid context, let's try a function..
sGlVersion$ = PeekS(glGetString_(#GL_VERSION))
sGlVersion$ = StringField(sGlVersion$, 1, " ")

CloseScreen()

Debug StringField(sGlVersion$, 1, ".") ; major
Debug StringField(sGlVersion$, 2, ".") ; minor
"Have you tried turning it off and on again ?"
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: GPU Name

Post by luis »

netmaestro wrote: I get "1.4.0 - Build 8.15.10.1912" here. Your mileage may vary. Proceed to cash 'n carry.
What card is that ? Maybe an Intel integrated ? Thanks.
"Have you tried turning it off and on again ?"
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: GPU Name

Post by IdeasVacuum »

citystate 100% correct, definitely not talking out of his hat :mrgreen:
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: GPU Name

Post by IdeasVacuum »

glGetString_(#GL_VERSION)

good tip Luis, thank you.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: GPU Name

Post by IdeasVacuum »

My wife's laptop result: OpenGL version: 2.1.0 - Build 8.15.10.2302

That's built-in Intel HD Graphics (i3)
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: GPU Name

Post by luis »

IdeasVacuum wrote: That's built-in Intel HD Graphics (i3)
I see, thanks. Same format so I guess netmaestro's is an Intel too.

Bye!
"Have you tried turning it off and on again ?"
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: GPU Name

Post by IdeasVacuum »

Extensive info about the GPU is delivered by the DirectX Diagnostic Tool, dxdiag.exe

So, that's great thinks me, as it will output a text file in command line mode which can be parsed. Unfortunately, it takes a month of Sundays to write the file :cry:
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Post Reply