Skip to content

Commit

Permalink
Use WMI to get video memory
Browse files Browse the repository at this point in the history
  • Loading branch information
elishacloud committed Sep 13, 2024
1 parent 392eaec commit 39e384c
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 143 deletions.
2 changes: 1 addition & 1 deletion Dllmain/BuildNo.rc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define BUILD_NUMBER 7142
#define BUILD_NUMBER 7143
154 changes: 80 additions & 74 deletions Utils/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1057,99 +1057,105 @@ inline UINT GetValueFromString(wchar_t* str)
return num;
}

DWORD Utils::GetVideoRam(UINT AdapterNo)
HRESULT Utils::GetVideoRam(UINT AdapterNo, DWORD& TotalMemory)
{
UNREFERENCED_PARAMETER(AdapterNo);

DWORD retSize = 0;
struct ADLIST {
DWORD DeviceID = 0;
DWORD AdapterRAM = 0;
};
static std::vector<ADLIST> AdapterList;

#if (_WIN32_WINNT >= 0x0502)
// Initialize COM
HRESULT hr = CoInitialize(nullptr);
if (FAILED(hr))
if (AdapterList.size())
{
// Handle error
Logging::Log() << __FUNCTION__ << " Error: Failed to CoInitialize.";
return retSize;
}

do {
// Create an instance of the IWbemLocator interface
CComPtr<IWbemLocator> spLoc = nullptr;
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, (LPVOID*)&spLoc);
if (FAILED(hr))
for (auto& entry : AdapterList)
{
// Handle error
Logging::Log() << __FUNCTION__ << " Error: Failed to CoCreateInstance.";
break;
}

// Connect to the root\cimv2 namespace with the IWbemServices interface
CComPtr<IWbemServices> spServices = nullptr;
hr = spLoc->ConnectServer(CComBSTR(L"root\\cimv2"), nullptr, nullptr, nullptr, 0, nullptr, nullptr, &spServices);
if (FAILED(hr))
{
// Handle error
Logging::Log() << __FUNCTION__ << " Error: Failed to connect to the root\\cimv2 namespace.";
break;
if (entry.DeviceID == AdapterNo)
{
TotalMemory = entry.AdapterRAM;
return S_OK;
}
}
return E_FAIL;
}

// Set the security levels for the proxy
hr = CoSetProxyBlanket(spServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
if (FAILED(hr))
{
// Handle error
Logging::Log() << __FUNCTION__ << " Error: Failed to set the security levels.";
break;
}
HRESULT hr = E_FAIL;
HRESULT t_hr = E_FAIL;
IWbemLocator* pLoc = NULL;
IWbemServices* pSvc = NULL;
IEnumWbemClassObject* pEnumerator = NULL;
IWbemClassObject* pclsObj = NULL;
ULONG uReturn = 0;

// Create an enumerator for Win32_VideoController instances
CComPtr<IEnumWbemClassObject> spEnumInst = nullptr;
hr = spServices->CreateInstanceEnum(CComBSTR(L"Win32_VideoController"), WBEM_FLAG_SHALLOW, nullptr, &spEnumInst);
if (FAILED(hr))
HRESULT c_hr = CoInitializeEx(0, COINIT_MULTITHREADED);
bool AlreadyInitialized = (c_hr == S_FALSE || c_hr == RPC_E_CHANGED_MODE);
if ((SUCCEEDED(c_hr) || AlreadyInitialized) &&
SUCCEEDED(t_hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL)) &&
SUCCEEDED(t_hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc)))
{
if (SUCCEEDED(t_hr = pLoc->ConnectServer(_bstr_t(L"root\\cimv2"), NULL, NULL, 0, NULL, 0, 0, &pSvc)))
{
// Handle error
Logging::Log() << __FUNCTION__ << " Error: Failed to create an enumerator for Win32_VideoController instances.";
break;
}

// Loop through the instances and retrieve the video RAM
ULONG uNumOfInstances = 0;
do {
CComPtr<IWbemClassObject> spInstance = nullptr;
hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance, &uNumOfInstances);
if (SUCCEEDED(hr) && uNumOfInstances)
if (SUCCEEDED(t_hr = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE)) &&
SUCCEEDED(t_hr = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_VideoController"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator)))
{
// Get the DeviceID property from the instance
CComVariant varId;
hr = spInstance->Get(CComBSTR(L"DeviceID"), 0, &varId, nullptr, nullptr);
if (SUCCEEDED(hr))
while (pEnumerator)
{
UINT VideoAdapter = GetValueFromString(varId.bstrVal);
t_hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (FAILED(t_hr) || 0 == uReturn)
{
break;
}

// Check adapter number
if (AdapterNo == VideoAdapter)
VARIANT varId = {};

t_hr = pclsObj->Get(L"DeviceID", 0, &varId, 0, 0);
if (SUCCEEDED(t_hr))
{
// Get the AdapterRAM property from the instance
CComVariant varSize;
if (SUCCEEDED(spInstance->Get(CComBSTR(L"AdapterRAM"), 0, &varSize, nullptr, nullptr)))
UINT DeviceID = GetValueFromString(varId.bstrVal);
VariantClear(&varId);

VARIANT vtTotalMemory = {};

t_hr = pclsObj->Get(L"AdapterRAM", 0, &vtTotalMemory, 0, 0);
if (SUCCEEDED(t_hr))
{
Logging::LogDebug() << __FUNCTION__ << " Found AdapterRAM on adapter: " << VideoAdapter << " Size: " << varSize.intVal;
retSize = varSize.intVal;
break;
Logging::Log() << __FUNCTION__ << " Found AdapterRAM on adapter: " << vtTotalMemory.ulVal / (1024 * 1024) << "MBs on DeviceID: " << DeviceID;

ADLIST tmpItem = { DeviceID, vtTotalMemory.ulVal };
AdapterList.push_back(tmpItem);

// Check adapter number
if (AdapterNo == DeviceID)
{
TotalMemory = vtTotalMemory.ulVal;
hr = S_OK;
}
VariantClear(&vtTotalMemory);
}
}
pclsObj->Release();
}
pEnumerator->Release();
}
} while (SUCCEEDED(hr) && uNumOfInstances);

} while (false);

CoUninitialize();
#endif // _WIN32_WINNT >= 0x0502
pSvc->Release();
}
pLoc->Release();
}
if (c_hr == S_OK)
{
CoUninitialize();
}
else if (AlreadyInitialized)
{
Logging::Log() << __FUNCTION__ << " Warning: CoInitializeEx() was already initialized: " << Logging::hex(hr);
}
else
{
Logging::Log() << __FUNCTION__ << " Error: CoInitializeEx() returned an error: " << Logging::hex(hr);
}

return retSize;
return hr;
}

bool Utils::SetWndProcFilter(HWND hWnd)
{
// Check window handle
Expand Down
2 changes: 1 addition & 1 deletion Utils/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace Utils
void GetScreenSize(HWND hwnd, LONG &screenWidth, LONG &screenHeight);
void GetScreenSize(HWND hwnd, int &screenWidth, int &screenHeight);
void GetDesktopRect(HWND hWnd, RECT& screenRect);
DWORD GetVideoRam(UINT AdapterNo); // Adapters start numbering from '1', based on "Win32_VideoController" WMI class and "DeviceID" property.
HRESULT GetVideoRam(UINT AdapterNo, DWORD& TotalMemory); // Adapters start numbering from '1', based on "Win32_VideoController" WMI class and "DeviceID" property.
}

namespace WriteMemory
Expand Down
73 changes: 9 additions & 64 deletions ddraw/IDirectDrawX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2047,23 +2047,17 @@ HRESULT m_IDirectDrawX::GetAvailableVidMem2(LPDDSCAPS2 lpDDSCaps2, LPDWORD lpdwT
DWORD TotalMemory = 0;
DWORD AvailableMemory = 0;

// Get texture/surface memory
if (lpDDSCaps2 && (lpDDSCaps2->dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ZBUFFER)))
// Get memory
if (lpDDSCaps2 && ((lpDDSCaps2->dwCaps & (DDSCAPS_TEXTURE | DDSCAPS_OFFSCREENPLAIN | DDSCAPS_ZBUFFER)) || // Surface and Texture memory
(lpDDSCaps2->dwCaps & (DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_3DDEVICE)))) // Video memory
{
GetTextureMemory(AvailableMemory);
}
// Get video memory
else if (lpDDSCaps2 && (lpDDSCaps2->dwCaps & (DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_3DDEVICE)))
{
// Open the first adapter in the system
if (OpenD3DDDI(GetDC()) && D3DDDIGetVideoMemory(TotalMemory, AvailableMemory))
if (!OpenD3DDDI(GetDC()) || !D3DDDIGetVideoMemory(TotalMemory, AvailableMemory))
{
// Memory acquired using D3DDDI
}
// Failover to texture memory if DDI does not work
else
{
GetTextureMemory(AvailableMemory);
if (d3d9Device)
{
AvailableMemory = d3d9Device->GetAvailableTextureMem();
}
Utils::GetVideoRam(1, TotalMemory); // Just get memory for the first adapter for now
}
}
// Get non-local video memory
Expand Down Expand Up @@ -2119,55 +2113,6 @@ HRESULT m_IDirectDrawX::GetAvailableVidMem2(LPDDSCAPS2 lpDDSCaps2, LPDWORD lpdwT
return hr;
}

void m_IDirectDrawX::GetTextureMemory(DWORD& AvailableMemory)
{
if (d3d9Device)
{
AvailableMemory = d3d9Device->GetAvailableTextureMem();
return;
}

// Check for device interface
if (FAILED(CheckInterface(__FUNCTION__, false)))
{
AvailableMemory = 0;
return;
}

LOG_LIMIT(100, __FUNCTION__ << " Creating temporary Direct3D9 device");

// Create a temporary window
HWND hWnd = CreateWindow(TEXT("TempD3DWindow"), TEXT("DxWrapper Temporary Window"), WS_POPUPWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, NULL, NULL);
if (!hWnd)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create temporary window!");
return;
}

// Set up the Direct3D device parameters
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

// Create the Direct3D device
LPDIRECT3DDEVICE9 tmpD9Device = nullptr;
HRESULT hr = d3d9Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_NOWINDOWCHANGES, &d3dpp, &tmpD9Device);
if (FAILED(hr))
{
AvailableMemory = 0;
LOG_LIMIT(100, __FUNCTION__ << " Error: failed to create temporary Direct3D9 device: " << (D3DERR)hr);
}
else
{
AvailableMemory = tmpD9Device->GetAvailableTextureMem();
tmpD9Device->Release();
}

// Clean up the temporary window if we created one
DestroyWindow(hWnd);
}

/*********************************/
/*** Added in the V4 Interface ***/
/*********************************/
Expand Down
3 changes: 0 additions & 3 deletions ddraw/IDirectDrawX.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,6 @@ class m_IDirectDrawX : public IUnknown, public AddressLookupTableDdrawObject
void InitDdraw(DWORD DirectXVersion);
void ReleaseDdraw();

// Get texture memory
void GetTextureMemory(DWORD &AvailableMemory);

// Direct3D9 interface functions
HRESULT CheckInterface(char *FunctionName, bool CheckD3DDevice);
HRESULT CreateD3D9Object();
Expand Down

0 comments on commit 39e384c

Please sign in to comment.