Good day,
¿Hay alguna manera de averiguar la memoria de video total de la tarjeta gráfica? Me refiero a la memoria física de la tarjeta. He pensado que podría existir algúna cadena de descripción del fabricante, ya que muchas aplicaciones cuando te dicen qué tarjeta tienes tambien muestran la cantidad Ram, pero no encuentro como obtenerla.
Hasta ahora uso en DDraw:
DDCAPS.dwVidMemTotal -> Video + AGP total
DDCAPS.dwVidMemFree -> Video + AGP libre (Este valor es parecido al obtenido con D3D d3dDevice->GetAvailableTextureMem() )
Con los valores anteriores hago un calculo chapucero para intentar "intuir" la memoria de video de la tarjeta, pero es imposible averiguarlo de una manera fiable. Por ejemplo una tarjeta de 64MB con una memoria AGP de 128MB daría los mismos valores que una tarjeta de 128MB con AGP de 64MB, y no se puede saber si realmente la tarjeta tiene 64MB o 128MB.
Solo quiero usar memoria de video "real", ya que la AGP es MUY lenta en algunos equipos. Quizás me estoy liando y existe alguna función por ahí GetVideoCardMemory() que no encuentro, ¿alguna idea?
gracias!
A ver si encuentras algo que te sirva aqui http://www.stratos-ad.com/forums3/viewtopic.php?t=7293
Sí, había leido ese post hace tiempo, aunque no todos los comentarios. Parece ser que todas las soluciones obtienen Video+AGP y no hay manera de separarlas :(
Seguiré buscando...
Gracias!
Hace dos dias instalé 1 giga más de RAM en mi ordenador (ahora mismo tengo 1.5 GB) y cuando llamo a estas funciones me dice que tengo 660 MB de video. Mi tarjeta tiene 128MB, y claro, en cuanto paso de ese límite la renderización empieza a ir a saltos. La memoria AGP es un buen invento para transacciones rápidas de memoria de Sistema<->Video, pero no sirve para utilizarla como almacen de texturas que intervienen en la escena, es demasiado lenta (comparada con la de video) por eso se producen tirones y pausas al mover la cámara por zonas cargadas en video y otras en AGP... :(
Es raro lo de que vaya a saltos, comprueba que tienes habilitada la aceleración de textura AGP, puedes ejecutar el programa de diagnóstico de DirectX desde Inicio/Ejecutar poniendo dxdiag, y dentro de la aplicación la pestaña Pantalla.
Sí, la aceleración de texturas está habilitada. Utilizo Managed Textures en DX9 (D3DPOOL_MANAGED). Al cargar 200MB de texturas en una tarjeta con 128MB se me ocurren dos razones para los "parones", o que las texturas en la AGP bajen el rendimiento, o que DX se vuelva loca moviendo las texturas de un sitio a otro al mover la cámara sobre zonas que están en AGP (aunque acabo de probar creando las texturas con D3DPOOL_DEFAULT y el resultado es el mismo).
Los parones se producen siempre en las mismas posiciones de cámara :?
un saludo
Pues sí que puede ser que sea excesivo el visualizar simultaneamente tanta textura sin estar toda alojada en la VRAM. Si por ejemplo tu aplicacion va a 50 f/s, para mover 100Mb en cada frame necesita una velocidad de 5 GB/s, la velocidad del AGP 8X es de 2GB/s por lo que es imposible que le de tiempo.
Tendrás que buscar algún truco para acelerarlo, supongo que usarás mipmaps. Aunque lo mejor sería que evitases que aparezcan dentro de la cámara más texturas de las que caben en la memoria de vídeo.
De este modo aunque la escena tenga muchas más texturas, mientras no se visualicen simultaneamente no habrá problema, porque si el manager las va moviendo poco a poco a través del AGP a la VRAM a medida que se van necesitando no se produce el bloqueo.
Prueba el truco del mipmap, si cambias el MIPMAPLODBIAS, usará texturas más pequeñas y puede que eso ayude a acelerar su visualización. Reduciras la calidad pero al menos se evitará el bloqueo.
pDevice->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, bias );
Si funciona puedes modificarlo dinamicamente sólo cuando sea necesario y a ser posible con las texturas lejanas o que por su perspectiva no se note mucho el decremento de detalle.
Gracias marmocle,
El problema es que mi programa necesita todas las texturas al mismo tiempo. Puedes verlo en acción en la web de mi firma, se trata de un plugin visualizador de fotografías panorámicas. Por ejemplo, cada imagen de esta página http://www.skialpinizm.pl/360/ ocupa unos 200 MB en RAM. Lo que hace el plugin es utilizar el motor por software si la cantidad de VRAM no es suficiente, y cambiar a DX9 si hay suficiente VRAM. Con una tarjeta de 128MB, 78MB de imagen se quedarían en AGP, por eso se atasca en ciertas partes de la foto (gracias por los datos de velocidad, no los conocía).
El problema es encontrar un método fiable para calcular la VRAM y saber cuando cambiar a DX9 sin usar AGP.
saludos
Pero es imposible que aunque tu programa necesite 200 mb de texturas, hayan de ser vistas al mismo tiempo (más que nada porque no caben en la pantalla). y en caso de que así fuera por una reducción de su tamaño en una vista global entonces puedes usar los mipmaps que te solucionarían el problema sin perdida de calidad, estos son mantenidos automáticamente por lo que cuando hagas zoom se usarán las versiones de texturas más grandes pero al mismo tiempo serán necesarias menos cantidad de ellas al quedar el resto fuera de la visualización.
Quizás tendrías que hacer manualmente el control de las texturas que dibujas o no, pero tampoco te debe suponer mucho problema. Yo creo que si lo haces bien bastaría con conocer el máximo de memoria de texturas disponible y debería ir con fluidez al desplazarte por ellas.
Creo que he encontrado un método: Windows Scripting :D
Ahora sólo falta que alguien lo haga en C++ y ponga el código , claro :D
On Error Resume Next
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
arrComputers = Array("PCCENTRAL12")
For Each strComputer In arrComputers
WScript.Echo
WScript.Echo "=========================================="
WScript.Echo "Computer: " & strComputer
WScript.Echo "=========================================="
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_VideoController", "WQL", _
wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem In colItems
strAcceleratorCapabilities = Join(objItem.AcceleratorCapabilities, ",")
WScript.Echo "AcceleratorCapabilities: " & strAcceleratorCapabilities
WScript.Echo "AdapterCompatibility: " & objItem.AdapterCompatibility
WScript.Echo "AdapterDACType: " & objItem.AdapterDACType
WScript.Echo "AdapterRAM: " & objItem.AdapterRAM
WScript.Echo "Availability: " & objItem.Availability
strCapabilityDescriptions = Join(objItem.CapabilityDescriptions, ",")
WScript.Echo "CapabilityDescriptions: " & strCapabilityDescriptions
WScript.Echo "Caption: " & objItem.Caption
WScript.Echo "ColorTableEntries: " & objItem.ColorTableEntries
WScript.Echo "ConfigManagerErrorCode: " & objItem.ConfigManagerErrorCode
WScript.Echo "ConfigManagerUserConfig: " & objItem.ConfigManagerUserConfig
WScript.Echo "CreationClassName: " & objItem.CreationClassName
WScript.Echo "CurrentBitsPerPixel: " & objItem.CurrentBitsPerPixel
WScript.Echo "CurrentHorizontalResolution: " & objItem.CurrentHorizontalResolution
WScript.Echo "CurrentNumberOfColors: " & objItem.CurrentNumberOfColors
WScript.Echo "CurrentNumberOfColumns: " & objItem.CurrentNumberOfColumns
WScript.Echo "CurrentNumberOfRows: " & objItem.CurrentNumberOfRows
WScript.Echo "CurrentRefreshRate: " & objItem.CurrentRefreshRate
WScript.Echo "CurrentScanMode: " & objItem.CurrentScanMode
WScript.Echo "CurrentVerticalResolution: " & objItem.CurrentVerticalResolution
WScript.Echo "Description: " & objItem.Description
WScript.Echo "DeviceID: " & objItem.DeviceID
WScript.Echo "DeviceSpecificPens: " & objItem.DeviceSpecificPens
WScript.Echo "DitherType: " & objItem.DitherType
WScript.Echo "DriverDate: " & WMIDateStringToDate(objItem.DriverDate)
WScript.Echo "DriverVersion: " & objItem.DriverVersion
WScript.Echo "ErrorCleared: " & objItem.ErrorCleared
WScript.Echo "ErrorDescription: " & objItem.ErrorDescription
WScript.Echo "ICMIntent: " & objItem.ICMIntent
WScript.Echo "ICMMethod: " & objItem.ICMMethod
WScript.Echo "InfFilename: " & objItem.InfFilename
WScript.Echo "InfSection: " & objItem.InfSection
WScript.Echo "InstallDate: " & WMIDateStringToDate(objItem.InstallDate)
WScript.Echo "InstalledDisplayDrivers: " & objItem.InstalledDisplayDrivers
WScript.Echo "LastErrorCode: " & objItem.LastErrorCode
WScript.Echo "MaxMemorySupported: " & objItem.MaxMemorySupported
WScript.Echo "MaxNumberControlled: " & objItem.MaxNumberControlled
WScript.Echo "MaxRefreshRate: " & objItem.MaxRefreshRate
WScript.Echo "MinRefreshRate: " & objItem.MinRefreshRate
WScript.Echo "Monochrome: " & objItem.Monochrome
WScript.Echo "Name: " & objItem.Name
WScript.Echo "NumberOfColorPlanes: " & objItem.NumberOfColorPlanes
WScript.Echo "NumberOfVideoPages: " & objItem.NumberOfVideoPages
WScript.Echo "PNPDeviceID: " & objItem.PNPDeviceID
strPowerManagementCapabilities = Join(objItem.PowerManagementCapabilities, ",")
WScript.Echo "PowerManagementCapabilities: " & strPowerManagementCapabilities
WScript.Echo "PowerManagementSupported: " & objItem.PowerManagementSupported
WScript.Echo "ProtocolSupported: " & objItem.ProtocolSupported
WScript.Echo "ReservedSystemPaletteEntries: " & objItem.ReservedSystemPaletteEntries
WScript.Echo "SpecificationVersion: " & objItem.SpecificationVersion
WScript.Echo "Status: " & objItem.Status
WScript.Echo "StatusInfo: " & objItem.StatusInfo
WScript.Echo "SystemCreationClassName: " & objItem.SystemCreationClassName
WScript.Echo "SystemName: " & objItem.SystemName
WScript.Echo "SystemPaletteEntries: " & objItem.SystemPaletteEntries
WScript.Echo "TimeOfLastReset: " & WMIDateStringToDate(objItem.TimeOfLastReset)
WScript.Echo "VideoArchitecture: " & objItem.VideoArchitecture
WScript.Echo "VideoMemoryType: " & objItem.VideoMemoryType
WScript.Echo "VideoMode: " & objItem.VideoMode
WScript.Echo "VideoModeDescription: " & objItem.VideoModeDescription
WScript.Echo "VideoProcessor: " & objItem.VideoProcessor
WScript.Echo
Next
Next
Function WMIDateStringToDate(dtmDate)
WScript.Echo dtm:
WMIDateStringToDate = CDate(Mid(dtmDate, 5, 2) & "/" & _
Mid(dtmDate, 7, 2) & "/" & Left(dtmDate, 4) _
& " " & Mid (dtmDate, 9, 2) & ":" & Mid(dtmDate, 11, 2) & ":" & Mid(dtmDate,13, 2))
End Function
Evidentemente el API C++ de Windows tiene su equivalente. En las MSDN hay ejemplos sobre el uso de WMI (http://msdn2.microsoft.com/en-us/library/aa394558.aspx).
Saludos.
Hola,
Os cuento el desenlace de esta historia. Probé lo del WMI, pero no me entero de nada. Al final le hice caso a marcode y sólo subo a VRAM lo que se vé en cada momento. Parece que dividiendo las Mega-texturas en trocitos no mayores de 512x512 las transferencias no ralentizan la fluidez de la cámara. Parece ser que la AGP es suficientemente rápida para hacer las transferencias sin bloqueos (uso UpdateTexture para subir las texturas que entran en el frustum).
Me parece algo increíble que no se pueda obtener por separado algo tan sencillo como la cantidad de VRAM y AGP, ya que la AGP va de culo si la utilizas para renderizar. Simplemente me parece ridículo preguntar a la tarjeta por la cantidad disponible de VRAM, para por ejemplo decidir el nivel de calidad de las texturas de un juego, y que te responda con la cantidad de VRAM+AGP, cuando está demostrado que la AGP sólo sirve para transferencias rápidas (no para render). 200MB de SDK y no puedes ni averiguar algo tan básico.
Al final he utilizado un código que encontré en uno de los ejemplos de DX9SDK (dxdiag), con esto averiguo la VRAM de la tarjeta:
#define INITGUID
#include <initguid.h>
#include <dxdiag.h>
//-----------------------------------------------------------------------------
// Name: GetStringValue()
// Desc: Get a string value from a IDxDiagContainer object
//-----------------------------------------------------------------------------
HRESULT GetStringValue( IDxDiagContainer* pObject, WCHAR* wstrName, TCHAR* strValue, int nStrLen )
{
HRESULT hr;
VARIANT var;
VariantInit( &var );
if( FAILED( hr = pObject->GetProp( wstrName, &var ) ) )
return hr;
if( var.vt != VT_BSTR )
return E_INVALIDARG;
#ifdef _UNICODE
wcsncpy( strValue, var.bstrVal, nStrLen-1 );
#else
wcstombs( strValue, var.bstrVal, nStrLen );
#endif
strValue[nStrLen-1] = TEXT('\0');
VariantClear( &var );
return S_OK;
}
DWORD GetDisplayMemory()
{
int bCleanupCOM;
HRESULT hRes;
WCHAR wszContainer[256];
TCHAR buffer[1024],*buf;
IDxDiagProvider* pDxDiagProvider=NULL;
IDxDiagContainer* pDxDiagRoot=NULL;
IDxDiagContainer* pContainer=NULL;
IDxDiagContainer* pObject=NULL;
DWORD nInstanceCount=0;
DWORD nItem=0;
DWORD nCurCount=0;
DWORD memoria=0;
bCleanupCOM=SUCCEEDED(CoInitialize(NULL));
hRes = CoCreateInstance( CLSID_DxDiagProvider,NULL,CLSCTX_INPROC_SERVER,IID_IDxDiagProvider,(LPVOID*) &pDxDiagProvider);
if(SUCCEEDED(hRes) && pDxDiagProvider!=NULL)
{
DXDIAG_INIT_PARAMS dxDiagInitParam;
ZeroMemory( &dxDiagInitParam, sizeof(DXDIAG_INIT_PARAMS) );
dxDiagInitParam.dwSize=sizeof(DXDIAG_INIT_PARAMS);
dxDiagInitParam.dwDxDiagHeaderVersion=DXDIAG_DX9_SDK_VERSION;
dxDiagInitParam.bAllowWHQLChecks=0;
dxDiagInitParam.pReserved=NULL;
hRes = pDxDiagProvider->Initialize( &dxDiagInitParam );
if(SUCCEEDED(hRes))
{
hRes = pDxDiagProvider->GetRootContainer(&pDxDiagRoot);
if(SUCCEEDED(hRes))
{
// Get the IDxDiagContainer object called "DxDiag_DisplayDevices".
// This call may take some time while dxdiag gathers the info.
if( SUCCEEDED( hRes = pDxDiagRoot->GetChildContainer( L"DxDiag_DisplayDevices", &pContainer ) ) )
{
hRes=pContainer->GetNumberOfChildContainers(&nInstanceCount);
for( nItem = 0; nItem < nInstanceCount; nItem++ )
{
hRes = pContainer->EnumChildContainerNames( nItem, wszContainer, 256 );
if(SUCCEEDED(hRes))
{
hRes = pContainer->GetChildContainer( wszContainer, &pObject );
if(SUCCEEDED(hRes) && pObject!=NULL)
{
hRes=GetStringValue(pObject, L"szDisplayMemoryEnglish", buffer,1024);
buf=Strstr(buffer,_T("."));
if(buf) buf[0]=0;
memoria=Atoi(buffer)*1024*1024;
}
}
}
}
}
}
}
SAFE_RELEASE( pObject );
SAFE_RELEASE( pContainer );
SAFE_RELEASE( pDxDiagRoot );
SAFE_RELEASE( pDxDiagProvider );
if(bCleanupCOM)
CoUninitialize();
return memoria;
}
saludos
Existe una forma mas sencilla, te pego un fragmento de la clase SysCheck de mi engine:
// ========================================================================
// Returns the Available Video RAM on system
// ========================================================================
unsigned int SysCheck::GetAvailableVMemory() {
IDirect3DDevice9 *lp_D3DDev;
UINT free=0;
// Returns free VRAM in MB
free = lp_D3DDev->GetAvailableTextureMem();
if(free < FREE_VRAM_NEEDED) {
LODENGINE_LOG_START(LoDEngine::Log::S_ERROR) <<
"System Video Memory (Your Video Card dont have enough memory to install this game.\n\r"
"Please, revise the system requeriments to execute this game.\n\r" << ")" <<
LODENGINE_LOG_END;
this->m_vramCheck = false;
return false;
}
else {
this->m_vramCheck = true;
return true;
}
}
bool SysCheck::EnoughVMemory() {
if(this->GetAvailableVMemory())
return true;
else
return false;
}
Saludos.