View Issue Details

IDProjectCategoryView StatusLast Update
0003966The Dark ModCodingpublic07.10.2017 18:50
Reporterbibendovsky Assigned Toduzenko  
PrioritynormalSeveritynormalReproducibilityalways
Status closedResolutionfixed 
OSWindows 
Product VersionSVN 
Fixed in VersionTDM 2.06 
Summary0003966: MFC stuff in Sys_GetVideoRam prevents compiling
DescriptionMFC stuff in function Sys_GetVideoRam (win_shared.cpp) prevents compiling of engine project with Visual Studio Express Edition. An attached patch resolves the problem.
TagsNo tags attached.
Attached Files
win_shared.cpp.patch (11,167 bytes)   
Index: sys/win32/win_shared.cpp
===================================================================
--- sys/win32/win_shared.cpp	(revision 6374)
+++ sys/win32/win_shared.cpp	(working copy)
@@ -40,6 +40,9 @@
 #pragma comment (lib, "wbemuuid.lib")
 #endif
 
+#include <dxgi.h>
+
+
 /*
 ================
 Sys_Milliseconds
@@ -106,52 +109,338 @@
 #ifdef	ID_DEDICATED
 	return 0;
 #else
-	unsigned int retSize = 64;
+    // Based on information from
+    // https://code.msdn.microsoft.com/windowsdesktop/DirectX-Video-Memory-ee7d8319
 
-	CComPtr<IWbemLocator> spLoc = NULL;
-	HRESULT hr = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, ( LPVOID * ) &spLoc );
-	if ( hr != S_OK || spLoc == NULL ) {
-		return retSize;
-	}
+    ULONGLONG vram_size = 0;
+    BOOL api_result = FALSE;
 
-	CComBSTR bstrNamespace( _T( "\\\\.\\root\\CIMV2" ) );
-	CComPtr<IWbemServices> spServices;
+    OSVERSIONINFOEXW version_info;
+    version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
+    version_info.dwMajorVersion = 6;
 
-	// Connect to CIM
-	hr = spLoc->ConnectServer( bstrNamespace, NULL, NULL, 0, NULL, 0, 0, &spServices );
-	if ( hr != WBEM_S_NO_ERROR ) {
-		return retSize;
-	}
+    ULONGLONG ver_condition_mask = 0;
 
-	// Switch the security level to IMPERSONATE so that provider will grant access to system-level objects.  
-	hr = CoSetProxyBlanket( spServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
-	if ( hr != S_OK ) {
-		return retSize;
-	}
+    ver_condition_mask = ::VerSetConditionMask(
+        ver_condition_mask,
+        VER_MAJORVERSION,
+        VER_GREATER_EQUAL);
 
-	// Get the vid controller
-	CComPtr<IEnumWbemClassObject> spEnumInst = NULL;
-	hr = spServices->CreateInstanceEnum( CComBSTR( "Win32_VideoController" ), WBEM_FLAG_SHALLOW, NULL, &spEnumInst ); 
-	if ( hr != WBEM_S_NO_ERROR || spEnumInst == NULL ) {
-		return retSize;
-	}
+    api_result = ::VerifyVersionInfoW(
+        &version_info,
+        VER_MAJORVERSION,
+        ver_condition_mask);
 
-	ULONG uNumOfInstances = 0;
-	CComPtr<IWbemClassObject> spInstance = NULL;
-	hr = spEnumInst->Next( 10000, 1, &spInstance, &uNumOfInstances );
+    auto is_vista_or_higher = (api_result != FALSE);
 
-	if ( hr == S_OK && spInstance ) {
-		// Get properties from the object
-		CComVariant varSize;
-		hr = spInstance->Get( CComBSTR( _T( "AdapterRAM" ) ), 0, &varSize, 0, 0 );
-		if ( hr == S_OK ) {
-			retSize = varSize.intVal / ( 1024 * 1024 );
-			if ( retSize == 0 ) {
-				retSize = 64;
-			}
-		}
-	}
-	return retSize;
+
+    //
+    // Retrieve via DXGI 1.0/1.1 (Vista or higher)
+    //
+
+    ULONGLONG dxgi_vram_size = 0;
+
+    if (is_vista_or_higher) {
+        using LPCREATEDXGIFACTORY = HRESULT(WINAPI*)(
+            REFIID riid,
+            void** pp_factory);
+
+        HRESULT h_result = S_OK;
+        auto is_dxgi_1_1 = false;
+        LPCREATEDXGIFACTORY dxgi_create_factory = nullptr;
+        HMODULE dxgi_module = nullptr;
+
+        dxgi_module = ::LoadLibraryW(L"dxgi.dll");
+
+        if (dxgi_module) {
+            dxgi_create_factory = reinterpret_cast<LPCREATEDXGIFACTORY>(
+                ::GetProcAddress(dxgi_module, "CreateDXGIFactory1"));
+
+            if (dxgi_create_factory) {
+                is_dxgi_1_1 = true;
+            } else {
+                dxgi_create_factory = reinterpret_cast<LPCREATEDXGIFACTORY>(
+                    ::GetProcAddress(dxgi_module, "CreateDXGIFactory"));
+            }
+        }
+
+        if (dxgi_create_factory) {
+            IDXGIFactory* dxgi_factory = nullptr;
+
+            if (SUCCEEDED(h_result)) {
+                h_result = dxgi_create_factory(
+                    is_dxgi_1_1 ? ::IID_IDXGIFactory1 : ::IID_IDXGIFactory,
+                    reinterpret_cast<void**>(&dxgi_factory));
+            }
+
+
+            IDXGIAdapter* dxgi_adapter = nullptr;
+
+            if (SUCCEEDED(h_result)) {
+                h_result = dxgi_factory->EnumAdapters(0, &dxgi_adapter);
+            }
+
+            if (SUCCEEDED(h_result)) {
+                DXGI_ADAPTER_DESC desc;
+
+                h_result = dxgi_adapter->GetDesc(&desc);
+
+                if (SUCCEEDED(h_result)) {
+                    dxgi_vram_size = desc.DedicatedVideoMemory;
+                }
+            }
+
+            if (dxgi_adapter) {
+                static_cast<void>(dxgi_adapter->Release());
+            }
+
+            if (dxgi_factory) {
+                static_cast<void>(dxgi_factory->Release());
+            }
+        }
+
+        static_cast<void>(::FreeLibrary(dxgi_module));
+    }
+
+
+    //
+    // Retrieve via WMI
+    //
+
+    ULONGLONG vmi_vram_size = 0;
+
+    if (dxgi_vram_size == 0) {
+        HRESULT h_result = S_OK;
+
+        HMONITOR primary_monitor = nullptr;
+
+        if (SUCCEEDED(h_result)) {
+            primary_monitor = ::MonitorFromWindow(
+                ::GetDesktopWindow(),
+                MONITOR_DEFAULTTOPRIMARY);
+
+            if (!primary_monitor) {
+                h_result = E_FAIL;
+            }
+        }
+
+
+        std::wstring device_id;
+
+        if (SUCCEEDED(h_result)) {
+            //
+            // Get video adapter for primary desktop
+            //
+
+            auto is_device_found = false;
+            const DWORD max_adapters = 0xFFFFFFFF;
+
+            for (DWORD i = 0; i < max_adapters; ++i) {
+                DISPLAY_DEVICEW device_info;
+                device_info.cb = sizeof(DISPLAY_DEVICEW);
+
+                auto api_result = ::EnumDisplayDevicesW(
+                    nullptr,
+                    i,
+                    &device_info,
+                    0);
+
+                if (api_result == FALSE)
+                    break;
+
+                if ((device_info.StateFlags &
+                    DISPLAY_DEVICE_PRIMARY_DEVICE) == 0)
+                {
+                    continue;
+                }
+
+                is_device_found = true;
+                device_id = device_info.DeviceID;
+                break;
+            }
+
+            if (!is_device_found && SUCCEEDED(h_result)) {
+                h_result = E_FAIL;
+            }
+        }
+
+
+        auto is_com_initialized = false;
+
+        if (SUCCEEDED(h_result)) {
+            h_result = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
+
+            if (SUCCEEDED(h_result))
+                is_com_initialized = true;
+        }
+
+
+        IWbemLocator* wbem_locator = nullptr;
+
+        if (SUCCEEDED(h_result)) {
+            h_result = ::CoCreateInstance(
+                CLSID_WbemLocator,
+                nullptr,
+                CLSCTX_INPROC_SERVER,
+                IID_IWbemLocator,
+                reinterpret_cast<LPVOID*>(&wbem_locator));
+        }
+
+
+        IWbemServices* wbem_services = nullptr;
+
+        if (SUCCEEDED(h_result)) {
+            h_result = wbem_locator->ConnectServer(
+                BSTR(L"\\\\.\\root\\cimv2"),
+                nullptr,
+                nullptr,
+                nullptr,
+                0,
+                nullptr,
+                nullptr,
+                &wbem_services);
+        }
+
+
+        IClientSecurity* client_security = nullptr;
+
+        if (SUCCEEDED(h_result)) {
+            h_result = wbem_services->QueryInterface(
+                IID_PPV_ARGS(&client_security));
+        }
+
+        if (SUCCEEDED(h_result)) {
+            h_result = client_security->SetBlanket(
+                wbem_services,
+                RPC_C_AUTHN_WINNT,
+                RPC_C_AUTHZ_NONE,
+                nullptr,
+                RPC_C_AUTHN_LEVEL_CALL,
+                RPC_C_IMP_LEVEL_IMPERSONATE,
+                0,
+                EOAC_NONE);
+
+            static_cast<void>(client_security->Release());
+        }
+
+
+        IEnumWbemClassObject* controllers_enumerator = nullptr;
+
+        if (SUCCEEDED(h_result)) {
+            h_result = wbem_services->CreateInstanceEnum(
+                L"Win32_VideoController",
+                0,
+                nullptr,
+                &controllers_enumerator);
+        }
+
+        if (SUCCEEDED(h_result)) {
+            h_result = controllers_enumerator->Reset();
+        }
+
+        if (SUCCEEDED(h_result)) {
+            HRESULT var_result = S_OK;
+            ULONG controller_count = 0;
+            IWbemClassObject* controller_object = nullptr;
+            auto is_controller_found = false;
+            const LONG timeout_ms = 5 * 1000;
+
+            VARIANT pnp_device_id_var;
+            VARIANT adapter_ram_var;
+
+            ::VariantInit(&pnp_device_id_var);
+            ::VariantInit(&adapter_ram_var);
+
+            ULONG adapter_ram_size = 0;
+
+            while (true) {
+                h_result = controllers_enumerator->Next(
+                    timeout_ms,
+                    1,
+                    &controller_object,
+                    &controller_count);
+
+                if (FAILED(h_result) || controller_count == 0) {
+                    break;
+                }
+
+                h_result = controller_object->Get(
+                    L"PNPDeviceID",
+                    0,
+                    &pnp_device_id_var,
+                    nullptr,
+                    nullptr);
+
+                if (SUCCEEDED(h_result)) {
+                    h_result = controller_object->Get(
+                        L"AdapterRAM",
+                        0,
+                        &adapter_ram_var,
+                        nullptr,
+                        nullptr);
+                }
+
+                static_cast<void>(controller_object->Release());
+
+
+                std::wstring wmi_device_id;
+
+                if (SUCCEEDED(h_result)) {
+                    wmi_device_id = pnp_device_id_var.bstrVal;
+                    adapter_ram_size = adapter_ram_var.ulVal;
+                }
+
+                var_result = ::VariantClear(&pnp_device_id_var);
+                assert(SUCCEEDED(var_result));
+
+                var_result = ::VariantClear(&adapter_ram_var);
+                assert(SUCCEEDED(var_result));
+
+                if (FAILED(h_result)) {
+                    continue;
+                }
+
+                if (wmi_device_id.find(device_id) != 0) {
+                    continue;
+                }
+
+                vmi_vram_size = adapter_ram_size;
+
+                break;
+            }
+        }
+
+        if (controllers_enumerator) {
+            static_cast<void>(controllers_enumerator->Release());
+        }
+
+        if (wbem_services) {
+            static_cast<void>(wbem_services->Release());
+        }
+
+        if (wbem_locator) {
+            static_cast<void>(wbem_locator->Release());
+        }
+
+        if (is_com_initialized) {
+            ::CoUninitialize();
+        }
+    }
+
+
+    if (dxgi_vram_size > 0) {
+        vram_size = dxgi_vram_size;
+    } else if (vmi_vram_size > 0) {
+        vram_size = vmi_vram_size;
+    }
+
+    vram_size /= 1024 * 1024;
+
+    if (vram_size < 64) {
+        vram_size = 64;
+    }
+
+    return static_cast<int>(vram_size);
 #endif
 }
 
win_shared.cpp.patch (11,167 bytes)   

Activities

duzenko

duzenko

07.10.2017 18:50

developer   ~0009420

Sys_GetVideoRam removed as obsolete

Issue History

Date Modified Username Field Change
09.12.2014 18:18 bibendovsky New Issue
09.12.2014 18:18 bibendovsky File Added: win_shared.cpp.patch
07.10.2017 18:49 duzenko Assigned To => duzenko
07.10.2017 18:49 duzenko Status new => assigned
07.10.2017 18:50 duzenko Note Added: 0009420
07.10.2017 18:50 duzenko Status assigned => closed
07.10.2017 18:50 duzenko Resolution open => fixed
07.10.2017 18:50 duzenko Fixed in Version => TDM 2.06