ID3D10Counter usage
I'm trying to test Counters, with some problems. Here is a code snippet:
const int nCounters = 5;
const D3D10_COUNTER type[nCounters ] = {
D3D10_COUNTER_GPU_IDLE, D3D10_COUNTER_VERTEX_PROCESSING,
D3D10_COUNTER_GEOMETRY_PROCESSING, D3D10_COUNTER_PIXEL_PROCESSING,
D3D10_COUNTER_OTHER_GPU_PROCESSING
};
int Value[ nCounters ];
ID3D10Counter *Counter[nCounters];
for(int i=0;i<nCounters;i++) {
D3D10_COUNTER_DESC d = { type[ i ], 0 };
HRESULT h = pDevice->CreateCounter( &d, &(Counter[ i ]) );
if (FAILED(h)) throw i;
}
The counter creation failed when the third counter is created (I tried permutations) with the following error:
First-chance exception at 0x767edde0 in ezDXUT2console.exe: Microsoft C++ exception: _com_error at memory location 0x0012f23c..
The values are read with:
while( Counter[ i ]->GetData(NULL,0,0) == S_FALSE )continue;
HRESULT h = Counter[ i ]->GetData(&(Value[ i ]),sizeof(float),0);
on all counters created without error.
Is it a reference driver limitation?
By the way, OTHER_GPU_PROCESSING is not supported and theses counters always said the GPU is idle. Is it normal? (Ok, the reference driver is not a gpu, but should it not work like one?) Or, what am I doing or undestanding wrong?
I'm not on my Vista box right now so I don't have my code to hand, but I'm pretty sure I know what you're hitting.
Call ID3D10Device::CheckCounterInfo() and check the returned D3D10_COUNTER_INFO::NumSimultaneousCounters field. I'm pretty sure the RefRast has "4" for this field, but check anyway.
Thing is, each counter is not necessarily 1 counter (if that makes sense). Use ID3D10Device::CheckCounter() with mostly NULL values but inspect the returned pActiveCounters value. You'll find that some, if not all, occupy 2 counter slots.
Put this together and it basically means you have a finite number of counters and have to choose only a couple - which would fit with your code failing when you try and create the 3rd.
I can understand this for hardware devices (I'd not be surprised if we still need instrumented drivers for D3D10 GPU's thus making this feature largely unusable for the wider developer audience) but I'm a little surprised that the RefRast can't support more simultaneous counters. If I remember correctly you can't get all four (or is it five?) load-balancing counters (VS,GS,PS, Idle) at the same time which makes it pretty difficult to get useful results back. Oh well..
hth
Jack
Okay, as promised - here's my enumeration code:
void OutputCounters( ID3D10Device* pDevice )
{
D3D10_COUNTER_INFO CounterInfo;
pDevice->CheckCounterInfo( &CounterInfo );
// Print the basic information
WCHAR wcBasicInfo[512];
StringCchPrintf( wcBasicInfo, 512, L"\tBasic device information:\n"
L"\t\tMaximum number of simultaneous counters: %d\n"
L"\t\tDetectable parallel units: %d\n"
L"\t\tNumber of device-specific counters: %d\n",
CounterInfo.NumSimultaneousCounters,
CounterInfo.NumDetectableParallelUnits,
CounterInfo.LastDeviceDependentCounter - D3D10_COUNTER_DEVICE_DEPENDENT_0
);
OutputDebugString( wcBasicInfo );
// Iterate through all the device independent counters (18 total)
OutputDebugString( L"\tDevice independent counters:\n" );
for( UINT i = 0; i < 18; ++i )
OutputCounterDetails( pDevice, static_cast< D3D10_COUNTER >( i ) );
if( 0 != (CounterInfo.LastDeviceDependentCounter - D3D10_COUNTER_DEVICE_DEPENDENT_0) )
OutputDebugString( L"\tDevice dependent counters:\n" );
for( int i = D3D10_COUNTER_DEVICE_DEPENDENT_0; i < CounterInfo.LastDeviceDependentCounter; ++i )
OutputCounterDetails( pDevice, static_cast< D3D10_COUNTER >( i ) );
}
void OutputCounterDetails( ID3D10Device* pDevice, const D3D10_COUNTER& id )
{
// Extract information about this particular counter
D3D10_COUNTER_DESC d = { id, 0 };
D3D10_COUNTER_TYPE type = static_cast< D3D10_COUNTER_TYPE >( 0 );
UINT uiSlotsRequired = 0;
LPSTR sName = NULL;
UINT uiNameLength = 0;
LPSTR sUnits = NULL;
UINT uiUnitsLength = 0;
LPSTR sDesc = NULL;
UINT uiDescLength = 0;
if( SUCCEEDED( pDevice->CheckCounter( &d, &type, &uiSlotsRequired, NULL, &uiNameLength, NULL, &uiUnitsLength, NULL, &uiDescLength ) ) )
{
// We now know how much space to allocate for each string:
sName = new char[ uiNameLength ];
sUnits = new char[ uiUnitsLength ];
sDesc = new char[ uiDescLength ];
// Repeat the call in order to grab the text fields as well:
if( FAILED( pDevice->CheckCounter( &d, &type, &uiSlotsRequired, sName, &uiNameLength, sUnits, &uiUnitsLength, sDesc, &uiDescLength ) ) )
{
ERR_OUT( L"Failed to retrieve counter's string fields!" );
SAFE_DELETE_ARRAY( sName );
SAFE_DELETE_ARRAY( sUnits );
SAFE_DELETE_ARRAY( sDesc );
return;
}
WCHAR wcTypeName[64];
switch( type )
{
case D3D10_COUNTER_TYPE_FLOAT32:
wcscpy_s( wcTypeName, 64, L"32bit float" );
break;
case D3D10_COUNTER_TYPE_UINT16:
wcscpy_s( wcTypeName, 64, L"unsigned 16bit integer" );
break;
case D3D10_COUNTER_TYPE_UINT32:
wcscpy_s( wcTypeName, 64, L"unsigned 32bit integer" );
break;
case D3D10_COUNTER_TYPE_UINT64:
wcscpy_s( wcTypeName, 64, L"unsigned 64bit integer" );
break;
}
// Convert ASCII strings to Unicode for output...
int size = 0;
size = MultiByteToWideChar( CP_ACP, 0, sName, -1, NULL, 0 );
WCHAR *wcName = new WCHAR[ size ];
MultiByteToWideChar( CP_ACP, 0, sName, -1, wcName, size ); size = MultiByteToWideChar( CP_ACP, 0, sUnits, -1, NULL, 0 );
WCHAR *wcUnits = new WCHAR[ size ];
MultiByteToWideChar( CP_ACP, 0, sUnits, -1, wcUnits, size );
size = MultiByteToWideChar( CP_ACP, 0, sDesc, -1, NULL, 0 );
WCHAR *wcDesc = new WCHAR[ size ];
MultiByteToWideChar( CP_ACP, 0, sDesc, -1, wcDesc, size );
// Check if this counter type is actually supported
HRESULT hr = pDevice->CreateCounter( &d, NULL );
if( SUCCEEDED( hr ) )
{
// We can use this counter just fine!
WCHAR wcOut[512];
StringCchPrintf( wcOut, 512, L"\t\t'%s' can be used with this device.\n"
L"\t\t\t%s\n"
L"\t\t\tRequires %d counter(s)\n"
L"\t\t\t%s %s\n",
wcName,
wcDesc,
uiSlotsRequired,
wcTypeName, wcUnits
);
OutputDebugString( wcOut );
}
// Make sure we release the temporary data
SAFE_DELETE_ARRAY( sName );
SAFE_DELETE_ARRAY( sUnits );
SAFE_DELETE_ARRAY( sDesc );
SAFE_DELETE_ARRAY( wcName );
SAFE_DELETE_ARRAY( wcUnits );
SAFE_DELETE_ARRAY( wcDesc );
}
}
That should just output a list of all supported counters and information about them to the debug output window in VS.
hth
Jack