Changed: Implement CSystemUtils::getTotalVideoMemory() for Windows

This commit is contained in:
kervala 2015-12-23 14:48:33 +01:00
parent 8f1a09d9b0
commit 5500af2274
2 changed files with 239 additions and 0 deletions

View file

@ -81,6 +81,7 @@ public:
/// Detect whether the current process is a windowed application. Return true if definitely yes, false if unknown
static bool detectWindowedApplication();
static sint getTotalVideoMemory();
};
} // NLMISC

View file

@ -18,6 +18,14 @@
#include "nel/misc/system_utils.h"
#ifdef NL_OS_WINDOWS
#define INITGUID
#include <ddraw.h>
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <dxgi.h>
#include <initguid.h>
#include <CGuid.h>
# include <ObjBase.h>
# ifdef _WIN32_WINNT_WIN7
// only supported by Windows 7 Platform SDK
@ -365,4 +373,234 @@ bool CSystemUtils::detectWindowedApplication()
return false;
}
#ifdef NL_OS_WINDOWS
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = NULL; } }
#endif
typedef HRESULT (WINAPI* LPDIRECTDRAWCREATE)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
typedef HRESULT (WINAPI* LPCREATEDXGIFACTORY)(REFIID, void**);
static std::string FormatError(HRESULT hr)
{
std::string res;
LPTSTR errorText = NULL;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errorText, 0, NULL);
if (errorText)
{
res = NLMISC::toString("%s (0x%x)", errorText, hr);
LocalFree(errorText);
errorText = NULL;
}
return res;
}
struct SAdapter
{
uint id;
std::string name;
sint memory;
GUID guid;
HMONITOR hMonitor;
bool found;
SAdapter()
{
id = 0;
memory = -1;
guid = GUID_NULL;
hMonitor = NULL;
found = false;
}
};
static std::list<SAdapter> s_dxgiAdapters;
static void EnumerateUsingDXGI(IDXGIFactory *pDXGIFactory)
{
nlassert(pDXGIFactory != NULL);
for(uint index = 0; ; ++index)
{
IDXGIAdapter *pAdapter = NULL;
HRESULT hr = pDXGIFactory->EnumAdapters(index, &pAdapter);
// DXGIERR_NOT_FOUND is expected when the end of the list is hit
if (FAILED(hr)) break;
DXGI_ADAPTER_DESC desc;
memset(&desc, 0, sizeof(DXGI_ADAPTER_DESC));
if (SUCCEEDED(pAdapter->GetDesc(&desc)))
{
SAdapter adapter;
adapter.id = index;
adapter.name = ucstring((ucchar*)desc.Description).toUtf8();
adapter.memory = desc.DedicatedVideoMemory / 1024;
adapter.found = true;
nldebug("DXGI Adapter: %u - %s - DedicatedVideoMemory: %d KiB", index, adapter.name.c_str(), adapter.memory);
s_dxgiAdapters.push_back(adapter);
}
SAFE_RELEASE(pAdapter);
}
}
BOOL WINAPI DDEnumCallbackEx(GUID FAR* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm)
{
SAdapter * pAdapter = (SAdapter*)lpContext;
if (pAdapter->hMonitor == hm)
{
pAdapter->name = lpDriverDescription;
pAdapter->guid = *lpGUID;
pAdapter->found = true;
}
return TRUE;
}
#endif
sint CSystemUtils::getTotalVideoMemory()
{
sint res = -1;
#ifdef NL_OS_WINDOWS
// using DXGI
HINSTANCE hDXGI = LoadLibraryA("dxgi.dll");
if (hDXGI)
{
// We prefer the use of DXGI 1.1
LPCREATEDXGIFACTORY pCreateDXGIFactory = (LPCREATEDXGIFACTORY)GetProcAddress(hDXGI, "CreateDXGIFactory1");
if (!pCreateDXGIFactory)
{
pCreateDXGIFactory = (LPCREATEDXGIFACTORY)GetProcAddress(hDXGI, "CreateDXGIFactory");
}
if (pCreateDXGIFactory)
{
IDXGIFactory *pDXGIFactory = NULL;
HRESULT hr = pCreateDXGIFactory(__uuidof(IDXGIFactory), (LPVOID*)&pDXGIFactory);
if (SUCCEEDED(hr))
{
EnumerateUsingDXGI(pDXGIFactory);
SAFE_RELEASE(pDXGIFactory);
if (!s_dxgiAdapters.empty())
{
// TODO: determine what adapter is used by NeL
res = s_dxgiAdapters.front().memory;
}
else
{
nlwarning("Unable to find an DXGI adapter");
}
}
else
{
nlwarning("Unable to create DXGI factory");
}
}
else
{
nlwarning("dxgi.dll missing entry-point");
}
FreeLibrary(hDXGI);
}
if (res == -1)
{
// using DirectDraw
HMODULE hInstDDraw = LoadLibraryA("ddraw.dll");
if (hInstDDraw)
{
SAdapter adapter;
adapter.hMonitor = MonitorFromWindow(s_window, MONITOR_DEFAULTTONULL);
LPDIRECTDRAWENUMERATEEXA pDirectDrawEnumerateEx = (LPDIRECTDRAWENUMERATEEXA)GetProcAddress(hInstDDraw, "DirectDrawEnumerateExA");
LPDIRECTDRAWCREATE pDDCreate = (LPDIRECTDRAWCREATE)GetProcAddress(hInstDDraw, "DirectDrawCreate");
if (pDirectDrawEnumerateEx && pDDCreate)
{
HRESULT hr = pDirectDrawEnumerateEx(DDEnumCallbackEx, (VOID*)&adapter, DDENUM_ATTACHEDSECONDARYDEVICES);
if (SUCCEEDED(hr) && adapter.found)
{
LPDIRECTDRAW pDDraw = NULL;
hr = pDDCreate(&adapter.guid, &pDDraw, NULL);
if (SUCCEEDED(hr))
{
LPDIRECTDRAW7 pDDraw7 = NULL;
hr = pDDraw->QueryInterface(IID_IDirectDraw7, (VOID**)&pDDraw7);
if (SUCCEEDED(hr))
{
DDSCAPS2 ddscaps;
memset(&ddscaps, 0, sizeof(DDSCAPS2));
ddscaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
DWORD pdwAvailableVidMem;
hr = pDDraw7->GetAvailableVidMem(&ddscaps, &pdwAvailableVidMem, NULL);
if (SUCCEEDED(hr))
{
res = (sint)pdwAvailableVidMem / 1024;
nlinfo("DirectDraw Adapter: %s - DedicatedVideoMemory: %d KiB", adapter.name.c_str(), adapter.memory);
}
else
{
nlwarning("Unable to get DirectDraw available video memory: %s", FormatError(hr).c_str());
}
SAFE_RELEASE(pDDraw7);
}
else
{
nlwarning("Unable to query IDirectDraw7 interface: %s", FormatError(hr).c_str());
}
}
else
{
nlwarning("Unable to call DirectDrawCreate: %s", FormatError(hr).c_str());
}
}
else
{
nlwarning("Unable to enumerate DirectDraw adapters (%s): %s", (adapter.found ? "found":"not found"), FormatError(hr).c_str());
}
}
else
{
nlwarning("Unable to get pointer on DirectDraw functions (DirectDrawEnumerateExA %p, DirectDrawCreate %p)", pDirectDrawEnumerateEx, pDDCreate);
}
FreeLibrary(hInstDDraw);
}
else
{
nlwarning("Unable to load ddraw.dll");
}
}
#else
// TODO: implement for other systems
#endif
return res;
}
} // NLMISC