// ============================================================================
//
//  alphaprecision.cpp
//  Written by billkris.
//
// ============================================================================

#include "alphafloatrt.h"

#include "CBuffers.h"
#include "CTextures.h"
#include "CSwapChain.h"
#include "cd3dx.h"		//for D3DXAssembleShader9
#include "assert.h"
#include "strsafe.h"

#define TEXSIZE (16)

char CAlphaPrecisionFloatRT::m_MsgString[] = "";



// Plan A
//
// output = c0
// BUGBUG - This might not work since the spec seems to imply
// that shader constants are only required to be at least 16-bit.
// This means that 24/32-bit values cannot be passed in directly
// via constants.
const char *psWriteValueInC0[] =
{
	"ps.2.0 "
	"mov oC0, c0 "
	,
	"ps.3.0 "
	"mov oC0, c0 "
	,
};

// Plan B
//
// ouput = texcoord.uuuv
// BUGBUG - This might not work as I have heard that
// texture coordinate precision might not actually 
// need to be full 24/32-bit.  If this is true then
// 
const char *psWriteValueInT0[] =
{
	"ps.2.0 "
	"dcl t0 "
	"mov r0, t0.x "
	"mov r0.a, t0.y "
	"mov oC0, r0 "
	,
	"ps.3.0 "
	"dcl_texcoord v0 "
	"mov r0, v0.x "
	"mov r0.a, v0.y "
	"mov oC0, r0 "
	,
};

// Plan C
//
// output = rgb = c0.x * c0.y * c0.z * c0.w * c1.x * c1.y * c1.z * c1.w * c2.x * ( c2.y + c2.z + ( c2.w * 2^-14 ) )
//			  a = c3.x * c3.y * c3.z * c3.w * c4.x * c4.y * c4.z * c4.w * c5.x * ( c5.y + c5.z + ( c5.w * 2^-14 ) )
// 
// This method is the most confusing but is also the least subject to failure
// since all hardware should have at least 16-bit constants.  In theory it will construct any full 32-bit
// range/precision value from 12 16-bit floating point values.
// These values are generated by the function MakeFloat16Constants().
const char *psWriteValueFromConstArray[] =
{
	//
	// ps_2_0
	//
	
	"ps.2.0 "
	// RGB
	"def c6, 0.000061, 0.000061, 0.000061, 0.000061 " // 2^-14
	"mov r0, c0 "
	"mov r1, c1 "
	"mul r0, r0, r1 " // c0.x * c1.x, c0.y * c1.y, c0.z * c1.z, c0.w * c1.w
	"mul r0.x, r0.x, r0.y "
	"mul r0.x, r0.x, r0.z "
	"mul r0.x, r0.x, r0.w " // c0.x * c0.y * c0.z * c0.w * c1.x * c1.y * c1.z * c1.w
	"mov r1, c2 "
	"mul r1.w, r1.w, c6 "	// r1.w = c2.w * 2^-14
	"mul r0.x, r0.x, r1.x " // c0.x * c0.y * c0.z * c0.w * c1.x * c1.y * c1.z * c1.w * c2.x
	"mul r2, r0.x, r1.y "
	"mad r2, r0.x, r1.z, r2 "
	"mad r2, r0.x, r1.w, r2 " // c0.x * c0.y * c0.z * c0.w * c1.x * c1.y * c1.z * c1.w * c2.x * ( c2.y + c2.z + ( c2.w * 2^-14 ) )
	// Alpha
	"mov r0, c3 "
	"mov r1, c4 "
	"mul r0, r0, r1 " // c3.x * c4.x, c3.y * c4.y, c3.z * c4.z, c3.w * c4.w
	"mul r0.x, r0.x, r0.y "
	"mul r0.x, r0.x, r0.z "
	"mul r0.x, r0.x, r0.w " // c3.x * c3.y * c3.z * c3.w * c4.x * c4.y * c4.z * c4.w
	"mov r1, c5 "
	"mul r1.w, r1.w, c6 "	// r1.w = c5.w * 2^-14
	"mul r0.x, r0.x, r1.x " // c3.x * c3.y * c3.z * c3.w * c4.x * c4.y * c4.z * c4.w * c5.x
	"mul r3, r0.x, r1.y "
	"mad r3, r0.x, r1.z, r3 "
	"mad r2.a, r0.x, r1.w, r3 " // c3.x * c3.y * c3.z * c3.w * c4.x * c4.y * c4.z * c4.w * c5.x * ( c5.y + c5.z + ( c5.w * 2^-14 ) )
	"mov oC0, r2 "
	,
	
	
	//
	// ps_3_0
	//
	
	"ps.3.0 "
	// RGB
	"def c6, 0.000061, 0.000061, 0.000061, 0.000061 " // 2^-14
	"mov r0, c0 "
	"mov r1, c1 "
	"mul r0, r0, r1 " // c0.x * c1.x, c0.y * c1.y, c0.z * c1.z, c0.w * c1.w
	"mul r0.x, r0.x, r0.y "
	"mul r0.x, r0.x, r0.z "
	"mul r0.x, r0.x, r0.w " // c0.x * c0.y * c0.z * c0.w * c1.x * c1.y * c1.z * c1.w
	"mov r1, c2 "
	"mul r1.w, r1.w, c6 "	// r1.w = c2.w * 2^-14
	"mul r0.x, r0.x, r1.x " // c0.x * c0.y * c0.z * c0.w * c1.x * c1.y * c1.z * c1.w * c2.x
	"mul r2, r0.x, r1.y "
	"mad r2, r0.x, r1.z, r2 "
	"mad r2, r0.x, r1.w, r2 " // c0.x * c0.y * c0.z * c0.w * c1.x * c1.y * c1.z * c1.w * c2.x * ( c2.y + c2.z + ( c2.w * 2^-14 ) )
	// Alpha
	"mov r0, c3 "
	"mov r1, c4 "
	"mul r0, r0, r1 " // c3.x * c4.x, c3.y * c4.y, c3.z * c4.z, c3.w * c4.w
	"mul r0.x, r0.x, r0.y "
	"mul r0.x, r0.x, r0.z "
	"mul r0.x, r0.x, r0.w " // c3.x * c3.y * c3.z * c3.w * c4.x * c4.y * c4.z * c4.w
	"mov r1, c5 "
	"mul r1.w, r1.w, c6 "	// r1.w = c5.w * 2^-14
	"mul r0.x, r0.x, r1.x " // c3.x * c3.y * c3.z * c3.w * c4.x * c4.y * c4.z * c4.w * c5.x
	"mul r3, r0.x, r1.y "
	"mad r3, r0.x, r1.z, r3 "
	"mad r2.a, r0.x, r1.w, r3 " // c3.x * c3.y * c3.z * c3.w * c4.x * c4.y * c4.z * c4.w * c5.x * ( c5.y + c5.z + ( c5.w * 2^-14 ) )
	"mov oC0, r2 "
	,
};
	
//
// output = c0^8 (effectively increasing the floating point exponent by a factor of 8)

////////////////////////////////////////////////////////////
// 16-bit render target precision parameter table
////////////////////

inline float fpow2( int n )
{
	DWORD dwRVal = ( ( n + 127 ) & 0x00ff ) << 23;
	return *( (float *) &dwRVal );
}

const AlphaPrecParams fFloat16Params[] =
{
	// Verify 2^14 * 2 = 2^15
	AlphaPrecParams( fpow2( 14 ), 2.f, 0, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 15 ) ),
	AlphaPrecParams( 2.f, fpow2( 14 ), 0, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 15 ) ),
	AlphaPrecParams( 0, 2.f, fpow2( 14 ), D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 15 ) ),
	AlphaPrecParams( 0, fpow2( 14 ), 2.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 15 ) ),
	AlphaPrecParams( fpow2( 14 ), 0, 2.f, D3DBLEND_ZERO, D3DBLEND_SRCCOLOR, D3DBLENDOP_ADD, fpow2( 15 ) ),
	AlphaPrecParams( 2.f, 0, fpow2( 14 ), D3DBLEND_DESTCOLOR, D3DBLEND_ZERO, D3DBLENDOP_ADD, fpow2( 15 ) ),
	
	// Verify 2^14 * 2^-14 = 1
	AlphaPrecParams( fpow2( -14 ), fpow2( 14 ), 0.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, 1.f ),
	
	// Verify 1 + 2^-10
	AlphaPrecParams( fpow2( -10 ), 1.f, 1.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, 1.f + fpow2( -10 ) ),
	AlphaPrecParams( fpow2( -10 ), 1.f, 1.f, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLENDOP_ADD, 1.f + fpow2( -10 ) ),
	AlphaPrecParams( fpow2( -10 ), 1.f, 1.f, D3DBLEND_ONE, D3DBLEND_ONE, D3DBLENDOP_ADD, 1.f + fpow2( -10 ) ),
	
	//Verify 2^15 + 2^5
	AlphaPrecParams( fpow2( 15 ), 1.f, fpow2( 5 ), D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 15 ) + fpow2( 5 ) ),
	AlphaPrecParams( fpow2( 15 ), 1.f, fpow2( 5 ), D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLENDOP_ADD, fpow2( 15 ) + fpow2( 5 ) ),
	AlphaPrecParams( fpow2( 15 ), 1.f, fpow2( 5 ), D3DBLEND_ONE, D3DBLEND_ONE, D3DBLENDOP_ADD, fpow2( 15 ) + fpow2( 5 ) ),
	
	// Verify INVSRCALPHA
	AlphaPrecParams( 0.f, fpow2( -10 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLENDOP_ADD, 1.f - fpow2( -10 ) ),
	AlphaPrecParams( 0.f, fpow2( 10 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLENDOP_ADD, 1.f - fpow2( 10 ) ),	
};

////////////////////////////////////////////////////////////
// 32-bit render target with 24-bit pixel shader precision
//
// Since  ps_2_0 only requires 24-bit precision 
// expect ps output to be 24-bit
////////////////////
const AlphaPrecParams fFloat32Params24[] =
{
	// Verify 2^63 * 2^63 = 2^126
	AlphaPrecParams( fpow2( 63 ), fpow2( 63 ), 0.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 126 ) ),
	AlphaPrecParams( 0.f, fpow2( 63 ), fpow2( 63 ), D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 126 ) ),
	
	// Verify 2^-63 * 2^-63 = 2^-126
	AlphaPrecParams( fpow2( -63 ), fpow2( -63 ), 0.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( -126 ) ),
	AlphaPrecParams( 0.f, fpow2( -63 ), fpow2( -63 ), D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( -126 ) ),
	
	// Verify 1 + 2^-23
	AlphaPrecParams( fpow2( -12 ), fpow2( -11 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLENDOP_ADD, 1.f + fpow2( -23 ) ),
	AlphaPrecParams( ( 1.f + fpow2( -23 ) ), fpow2( -126 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLENDOP_ADD, fpow2( -126 ) * ( 1.f + fpow2( -23 ) ) ),
	
	// Verify 2^126 + 2^103
	AlphaPrecParams( fpow2( 63 ), fpow2( 63 ), fpow2( 40 ), D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 126 ) + fpow2( 103 ) ),
		
	// Verify INVSRCALPHA
	AlphaPrecParams( 0.f, fpow2( -23 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLENDOP_ADD, 1.f - fpow2( -23 ) ),
	AlphaPrecParams( 0.f, fpow2( 63 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLENDOP_ADD, 1.f - fpow2( 63 ) ),	
};

////////////////////////////////////////////////////////////
// 32-bit render target with 32-bit pixel shader precision
////////////////////
const AlphaPrecParams fFloat32Params[] =
{
	// Verify 2^126 * 2 = 2^127
	AlphaPrecParams( fpow2( 126 ), 2.f, 0, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 127 ) ),
	AlphaPrecParams( 2.f, fpow2( 126 ), 0, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 127 ) ),
	AlphaPrecParams( 0, 2.f, fpow2( 126 ), D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 127 ) ),
	AlphaPrecParams( 0, fpow2( 126 ), 2.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 127 ) ),
	AlphaPrecParams( fpow2( 126 ), 0, 2.f, D3DBLEND_ZERO, D3DBLEND_SRCCOLOR, D3DBLENDOP_ADD, fpow2( 127 ) ),
	AlphaPrecParams( 2.f, 0, fpow2( 126 ), D3DBLEND_DESTCOLOR, D3DBLEND_ZERO, D3DBLENDOP_ADD, fpow2( 127 ) ),
	
	// Verify 2^126 * 2^-126 = 1
	AlphaPrecParams( fpow2( -126 ), fpow2( 126 ), 0.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, 1.f ),
	
	// Verify 1 + 2^-23
	AlphaPrecParams( fpow2( -23 ), 1.f, 1.f, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, 1.f + fpow2( -23 ) ),
	AlphaPrecParams( fpow2( -23 ), 1.f, 1.f, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLENDOP_ADD, 1.f + fpow2( -23 ) ),
	AlphaPrecParams( fpow2( -23 ), 1.f, 1.f, D3DBLEND_ONE, D3DBLEND_ONE, D3DBLENDOP_ADD, 1.f + fpow2( -23 ) ),
	
	//Verify 2^127 + 2^104
	AlphaPrecParams( fpow2( 127 ), 1.f, fpow2( 104 ), D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA, D3DBLENDOP_ADD, fpow2( 127 ) + fpow2( 104 ) ),
	AlphaPrecParams( fpow2( 127 ), 1.f, fpow2( 104 ), D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLENDOP_ADD, fpow2( 127 ) + fpow2( 104 ) ),
	AlphaPrecParams( fpow2( 127 ), 1.f, fpow2( 104 ), D3DBLEND_ONE, D3DBLEND_ONE, D3DBLENDOP_ADD, fpow2( 127 ) + fpow2( 104 ) ),
	
	// Verify INVSRCALPHA
	AlphaPrecParams( 0.f, fpow2( -23 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLENDOP_ADD, 1.f - fpow2( -23 ) ),
	AlphaPrecParams( 0.f, fpow2( 127 ), 1.f, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLENDOP_ADD, 1.f - fpow2( 127 ) ),	
};

//////////////////////////////////////////////////
// A 32-bit float can be broken down to a combination of 
// 12 16-bit floats.  
//
// Nine of the 16-bit floats 
// with a zero mantissa are multiplied together to 
// create a 32-bit float with the correct exponent.
//
// Three of the 16-bit floats are added together to
// get the correct mantissa.  This value is then multiplied
// with the previous result to get the full 32-bit
// value.
//
// The first Nine elements of fConstants are the exponent floats
// and the last three are the fractional floats.
////////////////////
void MakeFloat16Constants( float f32, float fConstants[12] )
{
	int iExp;
	int iFrac;
	
	float *f16ExpArray = fConstants;
	float *f16FracArray = fConstants + 9;
	
	DWORD dw32 = *( (DWORD *) &f32 );
	
	// Initialize constants
	fConstants[0] = 1.f;
	fConstants[1] = 1.f;
	fConstants[2] = 1.f;
	fConstants[3] = 1.f;
	fConstants[4] = 1.f;
	fConstants[5] = 1.f;
	fConstants[6] = 1.f;
	fConstants[7] = 1.f;
	fConstants[8] = 1.f;
	fConstants[9] = 0.f;
	fConstants[10] = 0.f;
	fConstants[11] = 0.f;
	
	// Zero is a special case
	if( dw32 == 0 )
		return;
		
	//
	// First calculate the Exponent array values
	//
	int exp = ( ( dw32 & 0x7f800000 ) >> 23 ) - 127;
	
	for( iExp = 0; iExp < 9 && exp > 0; iExp++)
	{
		int exp16 = exp;
		
		if( exp16 > 15 )
		{
			exp16 = 15;
		}
		
		exp -= exp16;
		
		DWORD dwExp = ( ( ( exp16 + 127 ) & 0x00ff ) << 23 );
		f16ExpArray[iExp] = *( (float *) &dwExp );
	}
	
	assert( iExp <= 9 );
	
	for( iExp = 0; iExp < 9 && exp < 0; iExp++)
	{
		int exp16 = exp;
		
		if( exp16 < -14 )
		{
			exp16 = -14;
		}
		
		exp -= exp16;
		
		DWORD dwExp = ( ( ( exp16 + 127 ) & 0x00ff ) << 23 );
		f16ExpArray[iExp] = *( (float *) &dwExp );
	}
	
	assert( iExp <= 9 );
	
	// Negate first value in exponent array if f32 is negative
	if( dw32 & 0x80000000 )
	{
		f16ExpArray[0] = -f16ExpArray[0];
	}
	
	//
	// Next calculate the fractional values
	//
	int nExp = 0;
	for( iFrac = 0; iFrac < 3; iFrac++ )
	{
		// Get the current fraction truncated to 10 bits
		DWORD dwFrac = ( ( nExp + 127 ) << 23 ) | ( dw32 & 0x007fe000 );
		f16FracArray[iFrac] = *( (float *) &dwFrac );
		
		// Mask all but the remaining fractional bits
		dw32 &= 0x00001fff;

		if( dw32 == 0 )
			break;
					
		// Shift the bits to the left until a 1 appears in bit-23
		while( ( dw32 & 0x00800000 ) == 0 )
		{
			nExp--;
			dw32 <<= 1;
		}
		
		// Strip off bit 23
		dw32 &= 0x007fffff;
	}
	
	// Since the last fractional value may be as small as 2^-23 and
	// the minimum exponent is -14, scale this value by 2^14.
	f16FracArray[2] *= 16384;
	
	// Now check that the original 32-bit float can be recomposed
	float fTest = f16FracArray[0] + f16FracArray[1] + ( f16FracArray[2] * .000061f );
	
	for( iExp = 0; iExp < 9; ++iExp )
	{
		fTest *= f16ExpArray[iExp];
	}
	
	assert( fTest == f32 );
}
	
float CalcFloatEpsilon( float fExpectedValue, int nFracBits )
{
	DWORD dwBase = *( (DWORD *) &fExpectedValue );
	dwBase &= 0x7f800000;

	int nExp = ( dwBase >> 23 ) - 127;
	int nEpsExp = nExp - nFracBits;
	
	DWORD dwRVal = ( ( nEpsExp + 127 ) & 0x00ff ) << 23;
	return *( ( float *) &dwRVal );
}
	
static const char *GetBlendOpString( D3DBLENDOP d3dBlendOp )
{
	switch( d3dBlendOp )
	{
		case D3DBLENDOP_ADD:
			return "D3DBLENDOP_ADD";
			break;
		case D3DBLENDOP_SUBTRACT:
			return "D3DBLENDOP_SUBTRACT";
			break;
		case D3DBLENDOP_REVSUBTRACT:
			return "D3DBLENDOP_REVSUBTRACT";
			break;
		case D3DBLENDOP_MIN:
			return "D3DBLENDOP_MIN";
			break;
		case D3DBLENDOP_MAX:
			return "D3DBLENDOP_MAX";
			break;
		default:
			break;
	}
	
	return NULL;
}

static const char *GetBlendString( D3DBLEND d3dBlend )
{
	switch( d3dBlend )
	{
		case D3DBLEND_ZERO:
			return "D3DBLEND_ZERO";
			break;
		case D3DBLEND_ONE:		
			return "D3DBLEND_ONE";
			break;
		case D3DBLEND_SRCCOLOR:
			return "D3DBLEND_SRCCOLOR";
			break;
		case D3DBLEND_INVSRCCOLOR:
			return "D3DBLEND_INVSRCCOLOR";
			break;
		case D3DBLEND_SRCALPHA:
			return "D3DBLEND_SRCALPHA";
			break;
		case D3DBLEND_INVSRCALPHA:
			return "D3DBLEND_INVSRCALPHA";
			break;
		case D3DBLEND_DESTALPHA:
			return "D3DBLEND_DESTALPHA";
			break;
		case D3DBLEND_INVDESTALPHA:
			return "D3DBLEND_INVDESTALPHA";
			break;
		case D3DBLEND_DESTCOLOR:
			return "D3DBLEND_DESTCOLOR";
			break;
		case D3DBLEND_INVDESTCOLOR:
			return "D3DBLEND_INVDESTCOLOR";
			break;
		case D3DBLEND_SRCALPHASAT:
			return "D3DBLEND_SRCALPHASAT";
			break;
		case D3DBLEND_BOTHSRCALPHA:
			return "D3DBLEND_BOTHSRCALPHA";
			break;
		case D3DBLEND_BOTHINVSRCALPHA:
			return "D3DBLEND_BOTHINVSRCALPHA";
			break;
		default:
			break;
	}

	return NULL;
}


////////////////////////////////////////////////////////////
// CAlphaPrecisionFloatRT
////////////////////
CAlphaPrecisionFloatRT::CAlphaPrecisionFloatRT() : 
	m_pTargetTexture( NULL ),
	m_pSysMemTexture( NULL ),
	m_pCmpTexture( NULL ),
	m_pPixelShader( NULL ),
	m_pParams( NULL ),
	m_nNumParams( 0 )
{
	SetTestType( TESTTYPE_CONF );
	
	m_Options.ModeOptions.dwTexInclude = PF_FLOATTEX;
	
	m_Options.ModeOptions.TextureFmt = FMT_ALL;

	m_Options.D3DOptions.DisplayMode.Format.d3dfFormat = (D3DFORMAT)FMT_ANY;
	
	// Force test to use Dx9
	m_Options.D3DOptions.fMinDXVersion = 9.0f;
	
	m_Options.D3DOptions.nBackBufferWidth = TEXSIZE;
	m_Options.D3DOptions.nBackBufferHeight = TEXSIZE;
	
	m_Options.D3DOptions.bReference = false;

	//m_Options.TestOptions.bCompareSrcRef = false;


    // Init variables
    m_bInvalid = false;
    m_bOffscreen = false;
	m_bNull = false;
    m_bValidate = true;

    if (KeySet("NoValidate"))
        m_bValidate = false;
}

CAlphaPrecisionFloatRT::~CAlphaPrecisionFloatRT()
{
}

bool CAlphaPrecisionFloatRT::CapsCheck()
{
	FORMAT *pFormatRT;
	
    // Tell framework what formats to use
    pFormatRT = &m_pCommonTextureFormats[m_pCurrentMode->nTextureFormat];
	
	if( FAILED( m_pD3D->CheckDeviceFormat(	m_pSrcDevice->GetAdapterID(), 
											m_pSrcDevice->GetDevType(), 
											m_pCurrentMode->pDisplay->Format,
											USAGE_RENDERTARGET, 
											RTYPE_TEXTURE, 
											*pFormatRT ) ) )
	{
		return FALSE;
	}
	
	if( FAILED( m_pD3D->CheckDeviceFormat(	m_pSrcDevice->GetAdapterID(), 
											m_pSrcDevice->GetDevType(), 
											m_pCurrentMode->pDisplay->Format,
											USAGE_QUERY_POSTPIXELSHADER_BLENDING, 
											RTYPE_TEXTURE, 
											*pFormatRT ) ) )
	{
		return FALSE;
	}

	return CD3DTest::CapsCheck();
}

UINT CAlphaPrecisionFloatRT::TestInitialize()
{
	// Create foreground/background
	if( !CreateQuad() )
		return D3DTESTINIT_ABORT;
	
	// Create the quad that will display the result in the visible
	// window.
	float xmax = 0.5f + m_pCurrentMode->nBackBufferWidth;
	float ymax = 0.5f + m_pCurrentMode->nBackBufferHeight;

	char formatstring[256];

	FORMAT *pFormatRT = &m_pCommonTextureFormats[m_pCurrentMode->nTextureFormat];
	FmtToString( FORMAT_TEXTURE, pFormatRT, formatstring );
	if( FAILED( StringCchPrintf( m_MsgString, sizeof( m_MsgString ), "RT Format: %s\n", formatstring ) ) )
		assert( !"String too long" );
	
	WriteToLog( "%s\n", m_MsgString );

	return D3DTESTINIT_RUN;
}

bool CAlphaPrecisionFloatRT::TestTerminate()
{
	return CD3DTest::TestTerminate();
}

bool CAlphaPrecisionFloatRT::Setup()
{
	bool bResult;
	
	// Create pixel shaders
	if( !BuildPixelShader() )
		return false;
		
    FORMAT * pFormatRT = &m_pCommonTextureFormats[m_pCurrentMode->nTextureFormat];

    int nWidthRT = m_pCurrentMode->nBackBufferWidth;
    int nHeightRT = m_pCurrentMode->nBackBufferHeight;

	// Create texture and set as render target
	bResult = CreateTexture( nWidthRT, nHeightRT, 1, USAGE_RENDERTARGET, *pFormatRT, FMWK_DEFAULT, &m_pTargetTexture );
	if( bResult == false )
	{
		WriteToLog("CreateTexture() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		return false;
	}
	
	// Create offcreen buffer to copy render results to which will later be used for comparison
	bResult = CreateTexture( nWidthRT, nHeightRT, 1, 0, *pFormatRT, POOL_SYSTEMMEM, &m_pSysMemTexture );
	if( bResult == false )
	{
		WriteToLog("CreateTexture() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		return false;
	}
	
	// Create a compatible texture for displaying comparison results
	bResult = CreateTexture( nWidthRT, nHeightRT, 1, 0, *pFormatRT, POOL_SYSTEMMEM, &m_pCmpTexture );
	if( bResult == false )
	{
		WriteToLog( "CreateTexture() failed with HResult = %s.\n", m_pD3D->HResultToString( GetLastError() ) );
		return false;
	}

	return CD3DTest::Setup();
}

void CAlphaPrecisionFloatRT::Cleanup()
{
	// Release pixel shaders
	RELEASE( m_pPixelShader );

	// Release render targets	
	RELEASE( m_pTargetTexture );
	RELEASE( m_pSysMemTexture );
	RELEASE( m_pCmpTexture );

	CD3DTest::Cleanup();
}

bool CAlphaPrecisionFloatRT::CompareResults( float r, float g, float b )
{
	bool bRVal = true;
	float fEpsilon;
	FORMAT *pFormatRT;
	
    pFormatRT = &m_pCommonTextureFormats[m_pCurrentMode->nTextureFormat];

    switch( pFormatRT->d3dfFormat )
    {
		case D3DFMT_R16F:
		case D3DFMT_G16R16F:
		case D3DFMT_A16B16G16R16F:
			fEpsilon = CalcFloatEpsilon( m_pCurrentParams->fExpectedResult, 10 );
			fEpsilon *= 2; // Soften epsilon by 1 bit of precision
			break;
			
		case D3DFMT_R32F:
		case D3DFMT_G32R32F:
		case D3DFMT_A32B32G32R32F:
			fEpsilon = CalcFloatEpsilon( m_pCurrentParams->fExpectedResult, 23 );
			break;
    }
    
    switch( pFormatRT->d3dfFormat )
    {
		case D3DFMT_A16B16G16R16F:
		case D3DFMT_A32B32G32R32F:
			if( fabsf( b - m_pCurrentParams->fExpectedResult ) > fEpsilon )
			{
				WriteToLog( "Blue channel blend precision failure.\n" );
				WriteToLog( " Result: %.10g", b );
				WriteToLog( " Expected: %.10g", m_pCurrentParams->fExpectedResult );
				bRVal = false;
			}

			// Fall through...
			
		case D3DFMT_G16R16F:
		case D3DFMT_G32R32F:
			if( fabsf( g - m_pCurrentParams->fExpectedResult ) > fEpsilon )
			{
				WriteToLog( "Green channel blend precision failure.\n" );
				WriteToLog( " Result: %.10g", g );
				WriteToLog( " Expected: %.10g", m_pCurrentParams->fExpectedResult );
				bRVal = false;
			}

			// Fall through...
			
		case D3DFMT_R16F:
		case D3DFMT_R32F:
			if( fabsf( r - m_pCurrentParams->fExpectedResult ) > fEpsilon )
			{
				WriteToLog( "Red channel blend precision failure.\n" );
				WriteToLog( " Result: %.10g", r );
				WriteToLog( " Expected: %.10g", m_pCurrentParams->fExpectedResult );
				bRVal = false;
			}
			break;
    }

	if( !bRVal )
	{
		WriteToLog( " SrcBlend: %s", GetBlendString( m_pCurrentParams->srcBlend ) );
		WriteToLog( " DestBlend: %s", GetBlendString( m_pCurrentParams->destBlend ) );
		WriteToLog( " BlendOp: %s", GetBlendOpString( m_pCurrentParams->blendOp ) );
		WriteToLog( " SRC R = G = B = %.10g", m_pCurrentParams->fSrcRGBConst );
		WriteToLog( " SRC Alpha = %.10g", m_pCurrentParams->fSrcAlpha );	
		WriteToLog( " DEST R = G = B = %.10g", m_pCurrentParams->fDestRGBConst );
	}
	
	return bRVal;
}



static bool CanBlend( D3DBLEND blend, DWORD dwBlendCaps )
{
	DWORD dwFlag;
	
	switch( blend )
	{
		case D3DBLEND_ZERO:
			dwFlag = D3DPBLENDCAPS_ZERO;
			break;
		case D3DBLEND_ONE:		
			dwFlag = D3DPBLENDCAPS_ONE;
			break;
		case D3DBLEND_SRCCOLOR:
			dwFlag = D3DPBLENDCAPS_SRCCOLOR;
			break;
		case D3DBLEND_INVSRCCOLOR:
			dwFlag = D3DPBLENDCAPS_INVSRCCOLOR;
			break;
		case D3DBLEND_SRCALPHA:
			dwFlag = D3DPBLENDCAPS_SRCALPHA;
			break;
		case D3DBLEND_INVSRCALPHA:
			dwFlag = D3DPBLENDCAPS_INVSRCALPHA;
			break;
		case D3DBLEND_DESTALPHA:
			dwFlag = D3DPBLENDCAPS_DESTALPHA;
			break;
		case D3DBLEND_INVDESTALPHA:
			dwFlag = D3DPBLENDCAPS_INVDESTALPHA;
			break;
		case D3DBLEND_DESTCOLOR:
			dwFlag = D3DPBLENDCAPS_DESTCOLOR;
			break;
		case D3DBLEND_INVDESTCOLOR:
			dwFlag = D3DPBLENDCAPS_INVDESTCOLOR;
			break;
		case D3DBLEND_SRCALPHASAT:
			dwFlag = D3DPBLENDCAPS_SRCALPHASAT;
			break;
		case D3DBLEND_BOTHSRCALPHA:
			dwFlag = D3DPBLENDCAPS_BOTHSRCALPHA;
			break;
		case D3DBLEND_BOTHINVSRCALPHA:
			dwFlag = D3DPBLENDCAPS_BOTHINVSRCALPHA;
			break;
	}
	
	return !!( dwBlendCaps & dwFlag );
}

bool CAlphaPrecisionFloatRT::ExecuteTest( UINT uTestNumber )
{
	bool bResult = true;

	// Change the render target to the texture
	CnSurface *pOldRenderTarget = NULL;
	CnSurface *pOldDepthStencil = NULL;
	CnSurface *pNewRenderTarget = NULL;
	GetRenderTarget( &pOldRenderTarget );
	GetDepthStencilSurface( &pOldDepthStencil );
	
	int nIndex = uTestNumber - 1;
	m_pCurrentParams = &m_pParams[nIndex];
	
	// Check whether the blending methods are supported
	DWORD dwSrcCapsFlag = 0;
	
	DWORD dwSrcBlendCaps = m_pSrcDevice->GetCaps()->dwSrcBlendCaps;
	DWORD dwDestBlendCaps = m_pSrcDevice->GetCaps()->dwDestBlendCaps;
	
	if( !CanBlend( m_pCurrentParams->srcBlend, dwSrcBlendCaps ) )
	{
		Skip();
		goto Exit;
	}
	
	if( !CanBlend( m_pCurrentParams->destBlend, dwDestBlendCaps ) )
	{
		Skip();
		goto Exit;
	}
	
	if( m_pCurrentParams->blendOp != D3DBLENDOP_ADD && !( m_pSrcDevice->GetCaps()->dwPrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP ) )
	{
		Skip();
		goto Exit;
	}
	
	bResult = m_pTargetTexture->GetSurfaceLevel( 0, &pNewRenderTarget );
	if( bResult == false )
	{
		WriteToLog("GetSurfaceLevel() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		goto Exit;
	}

	bResult = SetRenderTarget( pNewRenderTarget, NULL );
	if( bResult == false )
	{
		WriteToLog("SetRenderTarget() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		goto Exit;
	}

    FORMAT *pFormatRT = &m_pCommonTextureFormats[m_pCurrentMode->nTextureFormat];
	char formatstring[256];
	FmtToString( FORMAT_TEXTURE, pFormatRT, formatstring );
	if( FAILED( StringCchPrintf( m_MsgString, sizeof( m_MsgString ), "%s - RT: %s", GetTitle(), formatstring ) ) )
		assert( !"String too long" );
	
	
	// Tell the log that we are starting
	BeginTestCase( m_MsgString, uTestNumber );

	// Render to the texture RT
	if( BeginScene() )
	{
		// Disable Z-buffer
		SetRenderState( D3DRS_ZENABLE, false );
		SetRenderState( D3DRS_ZWRITEENABLE, false );
		
		//
		// First Pass
		//

		// Disable alpha blending		
		SetRenderState( D3DRS_ALPHABLENDENABLE, false );
		SetSamplerState( 0, SAMP_ADDRESSU, D3DTADDRESS_WRAP );
		SetSamplerState( 0, SAMP_ADDRESSV, D3DTADDRESS_WRAP );
		
		float c[12];
		float a[12];
		
		MakeFloat16Constants( m_pCurrentParams->fDestRGBConst, c );
		SetPixelShaderConstant( 0, (LPVOID) c, 3 );
		
		MakeFloat16Constants( 1.f, a );
		SetPixelShaderConstant( 3, (LPVOID) a, 3 );
/*
		c[0] = c[1] = c[2] = m_pCurrentParams->fSrcRGBConst;
		c[2] = m_pCurrentParams->fSrcAlpha;
		SetPixelShaderConstant( 0, (LPVOID) c, 1 );
*/
		
/*		
		// Set the texture coordinates to the desired output data (R = G = B = u, Alpha = v)
		m_tlVerts[0].tu = m_pCurrentParams->fDestRGBConst;
		m_tlVerts[0].tv = 1;
		m_tlVerts[1].tu = m_pCurrentParams->fDestRGBConst;
		m_tlVerts[1].tv = 1;
		m_tlVerts[2].tu = m_pCurrentParams->fDestRGBConst;
		m_tlVerts[2].tv = 1;
		m_tlVerts[3].tu = m_pCurrentParams->fDestRGBConst;
		m_tlVerts[3].tv = 1;
*/
		// Set pixel shader
		SetPixelShader( m_pPixelShader );
		
		// Render the first pass
		SetFVF( D3DFVF_TLVERTEX );
		DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, m_tlVerts, sizeof( D3DTLVERTEX ) );
		
		
		//
		// Second Pass
		//
		MakeFloat16Constants( m_pCurrentParams->fSrcRGBConst, c );
		SetPixelShaderConstant( 0, (LPVOID) c, 3 );
		
		MakeFloat16Constants( m_pCurrentParams->fSrcAlpha, a );
		SetPixelShaderConstant( 3, (LPVOID) a, 3 );
/*		
		c[0] = c[1] = c[2] = m_pCurrentParams->fSrcRGBConst;
		c[2] = m_pCurrentParams->fSrcAlpha;
		SetPixelShaderConstant( 0, (LPVOID) c, 1 );
*/
/*		
		// Set the texture coordinates to the desired output data (R = G = B = u, Alpha = v)
		m_tlVerts[0].tu = m_pCurrentParams->fSrcRGBConst;
		m_tlVerts[0].tv = m_pCurrentParams->fSrcAlpha;
		m_tlVerts[1].tu = m_pCurrentParams->fSrcRGBConst;
		m_tlVerts[1].tv = m_pCurrentParams->fSrcAlpha;
		m_tlVerts[2].tu = m_pCurrentParams->fSrcRGBConst;
		m_tlVerts[2].tv = m_pCurrentParams->fSrcAlpha;
		m_tlVerts[3].tu = m_pCurrentParams->fSrcRGBConst;
		m_tlVerts[3].tv = m_pCurrentParams->fSrcAlpha;
*/		
		// Initialize blend parameters
		SetRenderState( D3DRS_ALPHABLENDENABLE, true );
		SetRenderState( D3DRS_BLENDOP, m_pCurrentParams->blendOp );
		SetRenderState( D3DRS_SRCBLEND, m_pCurrentParams->srcBlend );
		SetRenderState( D3DRS_DESTBLEND, m_pCurrentParams->destBlend );

		DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, m_tlVerts, sizeof( D3DTLVERTEX ) );

		EndScene();
	}
	
	// Restore the render target
	SetRenderTarget( pOldRenderTarget, pOldDepthStencil );

Exit:	

	RELEASE( pNewRenderTarget );
	RELEASE( pOldRenderTarget );
	RELEASE( pOldDepthStencil );
	
	return bResult;
}

void CAlphaPrecisionFloatRT::UpdateStatus()
{
	CD3DTest::UpdateStatus();
	
	WriteStatus( "$wSrcBlend", "$a%s", GetBlendString( m_pCurrentParams->srcBlend ) );
	WriteStatus( "$wDestBlend", "$a%s", GetBlendString( m_pCurrentParams->destBlend ) );
	WriteStatus( "$wBlendOp", "$a%s", GetBlendOpString( m_pCurrentParams->blendOp ) );
	WriteStatus( "$wSRC R=G=B=", "$a%.10g", m_pCurrentParams->fSrcRGBConst );
	WriteStatus( "$wSRC Alpha=", "$a%.10g", m_pCurrentParams->fSrcAlpha );	
	WriteStatus( "$wDEST R=G=B=", "$a%.10g", m_pCurrentParams->fDestRGBConst );
	WriteStatus( "$wExpected Result", "$a%.10g", m_pCurrentParams->fExpectedResult );
}


////////////////////////////////////////////////////////////
// Override ProcessFrame to compare the result of the render
// to expected values based on input parameters.
//////////////////////////////
bool CAlphaPrecisionFloatRT::ProcessFrame(void)
{
	bool bRes = true;
    CSurface *pSrcSurf = NULL, *pRefSurf = NULL;
	CnSurface *pRTSurface = NULL;
	CnSurface *pSysMemSurface = NULL;
	SURFACEDESC  Desc;
	FSurface *pFSurf = NULL;

	// Copy the results of the render into the system memory texture
	if( !m_pTargetTexture->GetSurfaceLevel( 0, &pRTSurface ) )
	{
		WriteToLog("GetSurfaceLevel() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		bRes = false;
		goto Exit;
	}
	
	if( !m_pSysMemTexture->GetSurfaceLevel( 0, &pSysMemSurface ) )
	{
		WriteToLog("GetSurfaceLevel() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		bRes = false;
		goto Exit;
	}
	
	if( !GetRenderTargetData( pRTSurface, pSysMemSurface ) )
	{
		WriteToLog("GetRenderTargetData() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		bRes = false;
		goto Exit;
	}
	
	if( !pSysMemSurface->GetSurface( &pSrcSurf, 0 ) )
	{
		WriteToLog("GetSurface() failed with HResult = %s.\n",m_pD3D->HResultToString(GetLastError()));
		bRes = false;
		goto Exit;
	}
	
	if( FAILED( pSrcSurf->GetDesc(&Desc) ) )
	{
		DPF( 1, _T( "CImageCompare::FloatCompare() - GetDescription failed surface 1. hr = %s.\n"),
			m_pD3D->HResultToString( GetLastError() ) );
		goto Exit;
	}

	pFSurf = new FSurface();
	
	if( NULL == pFSurf)
	{
		DPF(1, _T("CImageCompare::FloatCompare() - Out of memory.\n"));
		bRes = false;
		goto Exit;
	}
	
	if( FAILED( pFSurf->ConvertFrom( pSrcSurf ) ) )
	{
		DPF( 1, _T( "FSurface::ConvertFrom() - failed to convert SRC surface.\n" ) );
		bRes = false;
		Fail();
		m_fPassPercentage = 0;
		goto Exit;
	}
	
	// Get the "center" pixel color
	FColor *color = pFSurf->GetData() + ( Desc.Width * Desc.Height ) / 2;
	
	if( !CompareResults( color->R, color->G, color->B ) )
	{
		m_fPassPercentage = 0;
		Fail();
		goto Exit;
	}
	else
	{
		m_fPassPercentage = 100;
		Pass();
	}

Exit:
	SAFEDELETE( pFSurf );
 	RELEASE( pRTSurface );
	RELEASE( pSysMemSurface );
	RELEASE( pSrcSurf );
	RELEASE( pRefSurf );

	return bRes;
}



//
// Protected methods
//
bool CAlphaPrecisionFloatRT::CreateQuad()
{
	// Create a triangle strip with horizontal bands of colors
	DWORD dwWidth = (DWORD) m_pCurrentMode->nBackBufferWidth;
	DWORD dwHeight = (DWORD) m_pCurrentMode->nBackBufferHeight;
	float fHeight = (float) dwHeight;
	
	m_tlVerts[0] = D3DTLVERTEX( D3DXVECTOR3( 0.f, (float) dwHeight, 0.f ), 1.f, 0xffffffff, 0, 0, 0 );
	m_tlVerts[1] = D3DTLVERTEX( D3DXVECTOR3( 0.f, 0.f, 0.f ), 1.f, 0xffffffff, 0, 0, 0 );
	m_tlVerts[2] = D3DTLVERTEX( D3DXVECTOR3( (float) dwWidth, (float) dwHeight, 0.f ), 1.f, 0xffffffff, 0, 0, 0 );
	m_tlVerts[3] = D3DTLVERTEX( D3DXVECTOR3( (float) dwWidth, 0.f, 0.f ), 1.f, 0xffffffff, 0, 0, 0 );
	
	return true;
}




bool CAlphaPrecisionFloatRT::BuildPixelShader()
{
	HRESULT hr;
    CnPixelShader *pPixelShader = NULL;
	LPD3DXBUFFER pXCode = NULL;
	LPD3DXBUFFER pXError = NULL;
	
//	const char *lpszSource = psWriteValueInT0[GetPixelShaderVersionMajor() - 2];
//	const char *lpszSource = psWriteValueInC0[GetPixelShaderVersionMajor() - 2];
	const char *lpszSource = psWriteValueFromConstArray[GetPixelShaderVersionMajor() - 2];
	
	if( lpszSource )
	{	
		hr = D3DXAssembleShader9( lpszSource, (int) strlen( lpszSource ), NULL, NULL, 0, &pXCode, &pXError );
		
		if( FAILED( hr ) )
		{
			WriteToLog(_T("Pixel Shader failed to assemble. (%08X)\n"), hr);
			RELEASE(pXCode);
			RELEASE(pXError);
			return false;
		}
		
		if( !CreatePixelShader( (DWORD*) pXCode->GetBufferPointer(), &pPixelShader ) )
		{
			WriteToLog( _T( "CreatePixelShader() failed with HResult = %s.\n" ), m_pD3D->HResultToString( GetLastError() ) );
			RELEASE( pXCode );
			RELEASE( pXError );
			return false;
		}
		
		m_pPixelShader = pPixelShader;
		
		RELEASE( pXCode );
		RELEASE( pXError );
	}
		
	return true;
}




//
// CAlphaPrecisionFloatRTPS20
//
CAlphaPrecisionFloatRTPS20::CAlphaPrecisionFloatRTPS20()
{
	m_szTestName = "FloatRT Precision - Pixel Shader V2.0";
	m_szCommandKey = "FloatRTPS20";
}

UINT CAlphaPrecisionFloatRTPS20::TestInitialize()
{
	UINT nRet = CAlphaPrecisionFloatRT::TestInitialize();
	
	if( nRet != D3DTESTINIT_RUN )
		return nRet;
	
	FORMAT *pFormatRT = &m_pCommonTextureFormats[m_pCurrentMode->nTextureFormat];

	switch( pFormatRT->d3dfFormat )
	{
		case D3DFMT_R16F:
		case D3DFMT_G16R16F:
		case D3DFMT_A16B16G16R16F:
			m_pParams = fFloat16Params;
			m_nNumParams = sizeof( fFloat16Params ) / sizeof( fFloat16Params[0] );
			break;
			
		case D3DFMT_R32F:
		case D3DFMT_G32R32F:
		case D3DFMT_A32B32G32R32F:
			m_pParams = fFloat32Params24;
			m_nNumParams = sizeof( fFloat32Params24 ) / sizeof( fFloat32Params24[0] );
			break;
	}
	
	SetTestRange( 1, m_nNumParams );
	
	return D3DTESTINIT_RUN;
}


bool CAlphaPrecisionFloatRTPS20::CapsCheck()
{
 	DWORD dwVer = D3DSHADER_VERSION_MAJOR( m_pSrcDevice->GetCaps()->dwPixelShaderVersion );
 	
 	if( dwVer < 2 )
 		return false;
 	
 	return CAlphaPrecisionFloatRT::CapsCheck();

}


//
// CAlphaPrecisionFloatRTPS30
//
CAlphaPrecisionFloatRTPS30::CAlphaPrecisionFloatRTPS30()
{
	m_szTestName = "FloatRT Precision - Pixel Shader V3.0";
	m_szCommandKey = "FloatRTPS30";
}


bool CAlphaPrecisionFloatRTPS30::CapsCheck()
{
 	DWORD dwVer = D3DSHADER_VERSION_MAJOR( m_pSrcDevice->GetCaps()->dwPixelShaderVersion );
 	
 	if( dwVer < 3 )
 		return false;
 	
 	return CAlphaPrecisionFloatRT::CapsCheck();

}

UINT CAlphaPrecisionFloatRTPS30::TestInitialize()
{
	UINT nRet = CAlphaPrecisionFloatRT::TestInitialize();
	
	if( nRet != D3DTESTINIT_RUN )
		return nRet;
	
	FORMAT *pFormatRT = &m_pCommonTextureFormats[m_pCurrentMode->nTextureFormat];

	switch( pFormatRT->d3dfFormat )
	{
		case D3DFMT_R16F:
		case D3DFMT_G16R16F:
		case D3DFMT_A16B16G16R16F:
			m_pParams = fFloat16Params;
			m_nNumParams = sizeof( fFloat16Params ) / sizeof( fFloat16Params[0] );
			break;
			
		case D3DFMT_R32F:
		case D3DFMT_G32R32F:
		case D3DFMT_A32B32G32R32F:
			m_pParams = fFloat32Params;
			m_nNumParams = sizeof( fFloat32Params ) / sizeof( fFloat32Params[0] );
			break;
	}
	
	SetTestRange( 1, m_nNumParams );
	
	return D3DTESTINIT_RUN;
}

