// NVHwAccel.cpp : Defines the initialization routines for the DLL.
//
// created by Unwinder
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

#include <float.h>
#include <afxdllx.h>

#include "NVHwAccel.h"
#include "RivaTunerExports.h"
#include "MonitoringSourceDesc.h"
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
static AFX_EXTENSION_MODULE NVHwAccelDLL = { NULL, NULL };
/////////////////////////////////////////////////////////////////////////////
GET_DEVICE_ID_PROC			g_pGetDeviceID				= NULL;
NVRM_GET_CFG_EX_PROC		g_pNvRmGetCfgEx				= NULL;
/////////////////////////////////////////////////////////////////////////////
#define NV_CFGEX_PERF_MODE	0x1F0
/////////////////////////////////////////////////////////////////////////////
typedef struct NV_CFGEX_PERF_MODE_DATA
{
	DWORD dwReserved;
	DWORD dwCount;
	DWORD dwFlags;
} NV_CFGEX_PERF_MODE_DATA, *LPNV_CFGEX_PERF_MODE_DATA;
/////////////////////////////////////////////////////////////////////////////
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	UNREFERENCED_PARAMETER(lpReserved);

	if (dwReason == DLL_PROCESS_ATTACH)
	{
		if (!AfxInitExtensionModule(NVHwAccelDLL, hInstance))
			return 0;

		new CDynLinkLibrary(NVHwAccelDLL);
	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		AfxTermExtensionModule(NVHwAccelDLL);
	}
	return 1;
}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get a number of
// data sources in this plugin
//////////////////////////////////////////////////////////////////////
NVHWACCEL_API DWORD GetSourcesNum()
{
	return 1;
}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get descriptor
// for the specified data source
//////////////////////////////////////////////////////////////////////
NVHWACCEL_API BOOL GetSourceDesc(DWORD dwIndex, LPMONITORING_SOURCE_DESC pDesc)
{
	//get host application module handle

	HMODULE hHost = GetModuleHandle(NULL);
	if (!hHost)
		return FALSE;

	//get ptr to host application ID routine and return error if the host doesn't 
	//export it

	//we'll use this condition to verify if we're under RivaTuner v2.0 RC 15.7
	//(older versions are not supported) or any other compatible host

	GET_HOST_APP_ID_PROC pGetHostAppID = (GET_HOST_APP_ID_PROC)GetProcAddress(hHost, "GetHostAppID");
	if (!pGetHostAppID)
		return FALSE;

	//get ptrs to required plugin API functions

	g_pGetDeviceID			= (GET_DEVICE_ID_PROC)GetProcAddress(hHost, "GetDeviceID");
	if (!g_pGetDeviceID)
		return FALSE;

	g_pNvRmGetCfgEx			= (NVRM_GET_CFG_EX_PROC)GetProcAddress(hHost, "NvRmGetCfgEx");
	if (!g_pNvRmGetCfgEx)
		return FALSE;

	//once we've got all function ptrs, we can proceed with hardware checking

	//first, we've to check if it is NVIDIA display adapter

	CString strDeviceID = g_pGetDeviceID();	strDeviceID.MakeUpper();

	DWORD	vendorID, deviceID;
	DWORD	subsysID;
	DWORD	revision;

	sscanf(strDeviceID,"PCI\\VEN_%04x&DEV_%04x&SUBSYS_%08x&REV_%02x", &vendorID, &deviceID, &subsysID, &revision);

	if (vendorID != 0x10DE)
		//return error if display adapter is not manufactured by NVIDIA
		return FALSE;

	//second, we've to check if currently installed NVIDIA display driver supports reporting data we need

	NV_CFGEX_PERF_MODE_DATA data; ZeroMemory(&data, sizeof(data));

	if (!g_pNvRmGetCfgEx(NV_CFGEX_PERF_MODE, (LPBYTE)&data, sizeof(data)))
		return FALSE;
	
	switch (dwIndex)
		//now NVIDIA driver supporting hardware acceleration usage reporting is detected
		//so we can return requested information to RivaTuner
	{
	case 0:
		//fill hardware acceleration source descriptor

		strcpy(pDesc->szName	, "Hardware acceleration");
		if (pDesc->dwVersion >= 0x00010002)
			strcpy(pDesc->szGroup, "GPU");

		pDesc->fltMaxLimit	= 1.0f;
		pDesc->fltMinLimit	= 0.0f;
		pDesc->fltGridDim	= 2.0f;

		strcpy(pDesc->szDesc, " Hardware acceleration reported by NVIDIA display driver ");

		return TRUE;
	}

	return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to poll data sources
/////////////////////////////////////////////////////////////////////////////
NVHWACCEL_API FLOAT GetSourceData(DWORD dwIndex)
{
	FLOAT	result	= FLT_MAX;	

	switch (dwIndex)
	{
	case 0:	//hardware acceleraton

		NV_CFGEX_PERF_MODE_DATA data; ZeroMemory(&data, sizeof(data));
	
		if (g_pNvRmGetCfgEx(NV_CFGEX_PERF_MODE, (LPBYTE)&data, sizeof(data)))
			result = (data.dwFlags & 4) ? 1.0f : 0.0f;

		break;
	}

	return result;
}
/////////////////////////////////////////////////////////////////////////////
