Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Averiguar memoria de video de la tarjeta

Iniciado por fiero, 27 de Noviembre de 2006, 11:15:20 AM

« anterior - próximo »

fiero

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!
www.videopanoramas.com Videopanoramas 3D player

Marci


fiero

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!
www.videopanoramas.com Videopanoramas 3D player

fiero

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...  :(
www.videopanoramas.com Videopanoramas 3D player

marcode

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.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

fiero

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
www.videopanoramas.com Videopanoramas 3D player

marcode

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.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

marcode

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.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

fiero

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
www.videopanoramas.com Videopanoramas 3D player

marcode

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.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

XÑA

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


BeRSeRKeR

Evidentemente el API C++ de Windows tiene su equivalente. En las MSDN hay ejemplos sobre el uso de WMI.

Saludos.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

fiero

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
www.videopanoramas.com Videopanoramas 3D player

DamnWidget

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.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.