//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//===========================================================================//

#define DISABLE_PROTECTED_THINGS
#include "togl/rendermechanism.h"
#include "locald3dtypes.h"
#include "colorformatdx8.h"
#include "shaderapidx8_global.h"
#include "bitmap/imageformat.h"
#include "shaderapi/ishaderutil.h"
#include "tier0/dbg.h"
#include "tier1/strtools.h"
#include "shaderdevicedx8.h"


// Must be last
#include "tier0/memdbgon.h"


//-----------------------------------------------------------------------------
// Figures out what texture formats we support
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// globals
//-----------------------------------------------------------------------------

// Texture formats supported by DX driver[vertextexture][render target][non filterable]
static D3DFORMAT	g_D3DColorFormat[NUM_IMAGE_FORMATS][2][2][2];
static UINT			g_DisplayAdapter;
static D3DDEVTYPE	g_DeviceType;
static ImageFormat	g_DeviceFormat;
static bool			g_bSupportsD24S8;
static bool			g_bSupportsD24X8;
static bool			g_bSupportsD16;
static bool			g_bSupportsD24X4S4;
static bool			g_bSupportsD15S1;

//-----------------------------------------------------------------------------
// Determines what formats we actually *do* support
//-----------------------------------------------------------------------------
static bool TestTextureFormat( D3DFORMAT format, bool bIsRenderTarget, 
							   bool bIsVertexTexture, bool bIsFilterableRequired ) 
{
	int nUsage = bIsRenderTarget ? D3DUSAGE_RENDERTARGET : 0;
	if ( bIsVertexTexture )
	{
		// vertex textures never need filtering
		nUsage |= D3DUSAGE_QUERY_VERTEXTEXTURE;
	}
	if ( bIsFilterableRequired )
	{
		nUsage |= D3DUSAGE_QUERY_FILTER;
	}

	HRESULT hr;

	// IHV depth texture formats require a slightly different check...
	if ( !IsX360() && bIsRenderTarget && ( ( format == NVFMT_RAWZ ) || ( format == NVFMT_INTZ   ) ||
										   ( format == D3DFMT_D16 ) || ( format == D3DFMT_D24S8 ) ||
										   ( format == ATIFMT_D16 ) || ( format == ATIFMT_D24S8 ) ) )
	{
		hr = D3D()->CheckDeviceFormat(
			g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
			D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, format );
	}
	else if ( !IsX360() || !bIsRenderTarget )
	{
		// See if we can do it!
		hr = D3D()->CheckDeviceFormat( 
			g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
			nUsage, D3DRTYPE_TEXTURE, format );
	}
	else // 360
	{
		// 360 can only validate render targets as surface display format
		hr = D3D()->CheckDeviceFormat( g_DisplayAdapter, g_DeviceType, format, 0, D3DRTYPE_SURFACE, format );
	}

    return SUCCEEDED( hr );
}

D3DFORMAT GetNearestD3DColorFormat( ImageFormat fmt,
									bool isRenderTarget, bool bIsVertexTexture,
									bool bIsFilterableRequired)
{
	switch(fmt)
	{
	case IMAGE_FORMAT_RGBA8888:
	case IMAGE_FORMAT_ABGR8888:
	case IMAGE_FORMAT_ARGB8888:
	case IMAGE_FORMAT_BGRA8888:
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		if (TestTextureFormat(D3DFMT_A4R4G4B4, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A4R4G4B4;
		break;

#if defined( _X360 )
	case IMAGE_FORMAT_LINEAR_RGBA8888:
	case IMAGE_FORMAT_LINEAR_ABGR8888:
	case IMAGE_FORMAT_LINEAR_ARGB8888:
	case IMAGE_FORMAT_LINEAR_BGRA8888:
		// same as above - all xxxx8888 RGBA ordering funnels to d3d a8r8g8b8
		if ( TestTextureFormat( D3DFMT_LIN_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_LIN_A8R8G8B8;
		break;
#endif

#if defined( _X360 )
	case IMAGE_FORMAT_LINEAR_BGRX8888:
		if ( TestTextureFormat( D3DFMT_LIN_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_LIN_X8R8G8B8;
		break;
#endif

	case IMAGE_FORMAT_BGRX8888:
		// We want this format to return exactly it's equivalent so that
		// when we create render targets to blit to from the framebuffer,
		// the CopyRect won't fail due to format mismatches.
		if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_X8R8G8B8;

		// fall through. . . .
	case IMAGE_FORMAT_RGB888:
	case IMAGE_FORMAT_BGR888:
#if !defined( _X360 )
		if (TestTextureFormat(D3DFMT_R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_R8G8B8;
#endif
		if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_X8R8G8B8;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		if (TestTextureFormat(D3DFMT_R5G6B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_R5G6B5;
		if (TestTextureFormat(D3DFMT_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_X1R5G5B5;
		if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A1R5G5B5;
		break;

	case IMAGE_FORMAT_BGR565:
	case IMAGE_FORMAT_RGB565:
		if (TestTextureFormat(D3DFMT_R5G6B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_R5G6B5;
		if (TestTextureFormat(D3DFMT_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_X1R5G5B5;
		if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A1R5G5B5;
#if !defined( _X360 )
		if (TestTextureFormat(D3DFMT_R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_R8G8B8;
#endif
		if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_X8R8G8B8;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		break;

	case IMAGE_FORMAT_BGRX5551:
		if (TestTextureFormat(D3DFMT_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_X1R5G5B5;
		if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A1R5G5B5;
		if (TestTextureFormat(D3DFMT_R5G6B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_R5G6B5;
#if !defined( _X360 )
		if (TestTextureFormat(D3DFMT_R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_R8G8B8;
#endif
		if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_X8R8G8B8;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		break;

#if defined( _X360 )
	case IMAGE_FORMAT_LINEAR_BGRX5551:
		if ( TestTextureFormat( D3DFMT_LIN_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_LIN_X1R5G5B5;
		break;
#endif

	case IMAGE_FORMAT_BGRA5551:
		if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A1R5G5B5;
		if (TestTextureFormat(D3DFMT_A4R4G4B4, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A4R4G4B4;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		break;

	case IMAGE_FORMAT_BGRA4444:
		if (TestTextureFormat(D3DFMT_A4R4G4B4, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A4R4G4B4;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		break;

	case IMAGE_FORMAT_I8:
		if (TestTextureFormat(D3DFMT_L8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_L8;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		break;

#if defined( _X360 )
	case IMAGE_FORMAT_LINEAR_I8:
		if ( TestTextureFormat( D3DFMT_LIN_L8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_LIN_L8;
		break;
#endif

	case IMAGE_FORMAT_IA88:
		if (TestTextureFormat(D3DFMT_A8L8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8L8;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		break;

	case IMAGE_FORMAT_A8:
		if (TestTextureFormat(D3DFMT_A8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8;
		if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_A8R8G8B8;
		break;

	case IMAGE_FORMAT_DXT1:
	case IMAGE_FORMAT_DXT1_ONEBITALPHA:
	case IMAGE_FORMAT_DXT1_RUNTIME:
		if (TestTextureFormat(D3DFMT_DXT1, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
			return D3DFMT_DXT1;
		break;

	case IMAGE_FORMAT_DXT3:
		if (TestTextureFormat(D3DFMT_DXT3, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
			return D3DFMT_DXT3;
		break;

	case IMAGE_FORMAT_DXT5:
	case IMAGE_FORMAT_DXT5_RUNTIME:
		if (TestTextureFormat(D3DFMT_DXT5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
			return D3DFMT_DXT5;
		break;

	case IMAGE_FORMAT_UV88:
		if (TestTextureFormat(D3DFMT_V8U8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
			return D3DFMT_V8U8;
		break;

	case IMAGE_FORMAT_UVWQ8888:
		if (TestTextureFormat(D3DFMT_Q8W8V8U8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
			return D3DFMT_Q8W8V8U8;
		break;

	case IMAGE_FORMAT_UVLX8888:
		if (TestTextureFormat(D3DFMT_X8L8V8U8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
			return D3DFMT_X8L8V8U8;
		break;

	case IMAGE_FORMAT_RGBA16161616F:
		if ( TestTextureFormat( D3DFMT_A16B16G16R16F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_A16B16G16R16F;
		if ( TestTextureFormat( D3DFMT_A16B16G16R16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_A16B16G16R16;
		break;

	case IMAGE_FORMAT_RGBA16161616:
		if ( TestTextureFormat( D3DFMT_A16B16G16R16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_A16B16G16R16;
		if ( TestTextureFormat( D3DFMT_A16B16G16R16F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_A16B16G16R16F;
		break;

#if defined( _X360 )
	case IMAGE_FORMAT_LINEAR_RGBA16161616:
		if ( TestTextureFormat( D3DFMT_LIN_A16B16G16R16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_LIN_A16B16G16R16;
		break;
#endif

	case IMAGE_FORMAT_R32F:
		if ( TestTextureFormat( D3DFMT_R32F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_R32F;
		break;

	case IMAGE_FORMAT_RGBA32323232F:
		if ( TestTextureFormat( D3DFMT_A32B32G32R32F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_A32B32G32R32F;
		break;

#if defined( _X360 )
	case IMAGE_FORMAT_X360_DST16:
		return D3DFMT_D16;

	case IMAGE_FORMAT_X360_DST24:
		return D3DFMT_D24S8;

	case IMAGE_FORMAT_X360_DST24F:
		return D3DFMT_D24FS8;

	case IMAGE_FORMAT_LE_BGRX8888:
		return D3DFMT_LE_X8R8G8B8;

	case IMAGE_FORMAT_LE_BGRA8888:
		return D3DFMT_LE_A8R8G8B8;
#endif

	// nVidia overloads DST formats as texture formats
	case IMAGE_FORMAT_NV_DST16:
		if ( TestTextureFormat( D3DFMT_D16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_D16;
		break;

	case IMAGE_FORMAT_NV_DST24:
		if ( TestTextureFormat( D3DFMT_D24S8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return D3DFMT_D24S8;
		break;
	case IMAGE_FORMAT_NV_INTZ:
		if ( TestTextureFormat( NVFMT_INTZ, isRenderTarget, bIsVertexTexture, false ) )
			return NVFMT_INTZ;
		break;

	case IMAGE_FORMAT_NV_RAWZ:
		if ( TestTextureFormat( NVFMT_RAWZ, isRenderTarget, bIsVertexTexture, false ) )
			return NVFMT_RAWZ;
		break;

	case IMAGE_FORMAT_NV_NULL:
		if ( TestTextureFormat( NVFMT_NULL, isRenderTarget, bIsVertexTexture, false ) )
			return NVFMT_NULL;
		break;

	case IMAGE_FORMAT_ATI_DST16:
		if ( TestTextureFormat( ATIFMT_D16, isRenderTarget, bIsVertexTexture, false ) )
			return ATIFMT_D16;
		break;

	case IMAGE_FORMAT_ATI_DST24:
		if ( TestTextureFormat( ATIFMT_D24S8, isRenderTarget, bIsVertexTexture, false ) )
			return ATIFMT_D24S8;
		break;

	case IMAGE_FORMAT_ATI2N:
		if ( TestTextureFormat( ATIFMT_ATI2N, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return ATIFMT_ATI2N;
		break;

	case IMAGE_FORMAT_ATI1N:
		if ( TestTextureFormat( ATIFMT_ATI1N, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
			return ATIFMT_ATI1N;
		break;
	}

	return D3DFMT_UNKNOWN;
}

void InitializeColorInformation( UINT displayAdapter, D3DDEVTYPE deviceType, 
								 ImageFormat displayFormat )
{
	g_DisplayAdapter = displayAdapter;
	g_DeviceType = deviceType;
	g_DeviceFormat = displayFormat;

	int fmt = 0;
	while ( fmt < NUM_IMAGE_FORMATS )
	{
		for ( int nVertexTexture = 0; nVertexTexture <= 1; ++nVertexTexture )
		{
			for ( int nRenderTarget = 0; nRenderTarget <= 1; ++nRenderTarget )
			{
				for ( int nFilterable = 0; nFilterable <= 1; ++nFilterable )
				{
					g_D3DColorFormat[fmt][nVertexTexture][nRenderTarget][nFilterable] = 
						GetNearestD3DColorFormat( (ImageFormat)fmt, nRenderTarget != 0, nVertexTexture != 0, nFilterable != 0 );
				}
			}
		}
		++fmt;
	}

	// Check the depth formats
    HRESULT hr = D3D()->CheckDeviceFormat( 
		g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
        D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 );
	g_bSupportsD24S8 = !FAILED(hr);

    hr = D3D()->CheckDeviceFormat( 
		g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
        D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 );
	g_bSupportsD24X8 = !FAILED(hr);

    hr = D3D()->CheckDeviceFormat( 
		g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
        D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 );
	g_bSupportsD16 = !FAILED(hr);

#if !defined( _X360 )
	hr = D3D()->CheckDeviceFormat( 
		g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
		D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 );
	g_bSupportsD24X4S4 = !FAILED(hr);
#else
	g_bSupportsD24X4S4 = false;
#endif

#if !defined( _X360 )
	hr = D3D()->CheckDeviceFormat( 
		g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
		D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 );
	g_bSupportsD15S1 = !FAILED(hr);
#else
	g_bSupportsD15S1 = false;
#endif
}


//-----------------------------------------------------------------------------
// Returns true if compressed textures are supported
//-----------------------------------------------------------------------------
bool D3DSupportsCompressedTextures()
{
	return	(g_D3DColorFormat[IMAGE_FORMAT_DXT1][0][0][0] != D3DFMT_UNKNOWN) &&
			(g_D3DColorFormat[IMAGE_FORMAT_DXT3][0][0][0] != D3DFMT_UNKNOWN) &&
			(g_D3DColorFormat[IMAGE_FORMAT_DXT5][0][0][0] != D3DFMT_UNKNOWN);
}


//-----------------------------------------------------------------------------
// Returns closest supported format
//-----------------------------------------------------------------------------
ImageFormat FindNearestSupportedFormat( ImageFormat format, bool bIsVertexTexture, bool bIsRenderTarget, bool bFilterableRequired )
{
	return ImageLoader::D3DFormatToImageFormat( g_D3DColorFormat[format][bIsVertexTexture][bIsRenderTarget][bFilterableRequired] );
}


//-----------------------------------------------------------------------------
// Returns true if compressed textures are supported
//-----------------------------------------------------------------------------
bool D3DSupportsDepthTexture(D3DFORMAT format)
{
	// See if we can do it!
    HRESULT hr = D3D()->CheckDeviceFormat( 
		g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat(g_DeviceFormat),
        D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, format);

	return !FAILED(hr);
}


//-----------------------------------------------------------------------------
// Returns true if the depth format is compatible with the display
//-----------------------------------------------------------------------------
static inline bool IsDepthFormatCompatible( int nAdapter, ImageFormat displayFormat, ImageFormat renderTargetFormat, D3DFORMAT depthFormat )
{
	D3DFORMAT d3dDisplayFormat = ImageLoader::ImageFormatToD3DFormat( displayFormat );
	D3DFORMAT d3dRenderTargetFormat = ImageLoader::ImageFormatToD3DFormat( renderTargetFormat );

	// Verify that the depth format is compatible.
	HRESULT hr = D3D()->CheckDepthStencilMatch(	nAdapter, DX8_DEVTYPE,
		d3dDisplayFormat, d3dRenderTargetFormat, depthFormat);
	return !FAILED(hr);
}

//-----------------------------------------------------------------------------
// Finds the nearest supported depth buffer format
//-----------------------------------------------------------------------------
D3DFORMAT FindNearestSupportedDepthFormat( int nAdapter, ImageFormat displayFormat, ImageFormat renderTargetFormat, D3DFORMAT depthFormat )
{
	// This is the default case, used for rendering to the main render target
	Assert( displayFormat != IMAGE_FORMAT_UNKNOWN && renderTargetFormat != IMAGE_FORMAT_UNKNOWN );

	switch (depthFormat)
	{
#if defined( _X360 )
	case D3DFMT_D24FS8:
		return D3DFMT_D24FS8;

	case D3DFMT_LIN_D24S8:
		if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_LIN_D24S8 ) )
			return D3DFMT_LIN_D24S8;
#endif
	case D3DFMT_D24S8:
		if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24S8 ) )
			return D3DFMT_D24S8;
#if !defined( _X360 )
		if ( g_bSupportsD24X4S4 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X4S4 ) )
			return D3DFMT_D24X4S4;
		if ( g_bSupportsD15S1 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D15S1 ) )
			return D3DFMT_D15S1;
#endif
		if ( g_bSupportsD24X8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X8 ) )
			return D3DFMT_D24X8;
		if ( g_bSupportsD16 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D16 ) )
			return D3DFMT_D16;
		break;

	case D3DFMT_D24X8:
		if ( g_bSupportsD24X8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X8 ) )
			return D3DFMT_D24X8;
		if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24S8 ) )
			return D3DFMT_D24S8;
#if !defined( _X360 )
		if ( g_bSupportsD24X4S4 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X4S4 ) )
			return D3DFMT_D24X4S4;
#endif
        if ( g_bSupportsD16 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D16 ) )
			return D3DFMT_D16;
#if !defined( _X360 )
		if ( g_bSupportsD15S1 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D15S1 ) )
			return D3DFMT_D15S1;
#endif
		break;

	case D3DFMT_D16:
		if ( g_bSupportsD16 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D16 ) )
			return D3DFMT_D16;
#if !defined( _X360 )
		if ( g_bSupportsD15S1 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D15S1 ) )
			return D3DFMT_D15S1;
#endif
		if ( g_bSupportsD24X8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X8 ) )
			return D3DFMT_D24X8;
		if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24S8 ) )
			return D3DFMT_D24S8;
#if !defined( _X360 )
		if ( g_bSupportsD24X4S4 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X4S4 ) )
			return D3DFMT_D24X4S4;
#endif
		break;
	}

	Assert( 0 );
	return D3DFMT_D16;
}


//-----------------------------------------------------------------------------
// Is a display buffer valid?
//-----------------------------------------------------------------------------
static inline bool IsFrameBufferFormatValid( UINT displayAdapter, D3DDEVTYPE deviceType, 
	D3DFORMAT displayFormat, D3DFORMAT backBufferFormat, bool bIsWindowed )
{
	HRESULT hr = D3D()->CheckDeviceType( displayAdapter, deviceType, displayFormat, 
                                        backBufferFormat, bIsWindowed );
	return !FAILED(hr);
}


//-----------------------------------------------------------------------------
// Finds the nearest supported frame buffer format
//-----------------------------------------------------------------------------
ImageFormat FindNearestSupportedBackBufferFormat( UINT displayAdapter, 
	  D3DDEVTYPE deviceType, ImageFormat displayFormat, ImageFormat backBufferFormat, bool bIsWindowed )
{
	D3DFORMAT d3dDisplayFormat = ImageLoader::ImageFormatToD3DFormat( displayFormat );
	switch (backBufferFormat)
	{
	case IMAGE_FORMAT_RGBA8888:
	case IMAGE_FORMAT_ABGR8888:
	case IMAGE_FORMAT_ARGB8888:
	case IMAGE_FORMAT_BGRA8888:
	case IMAGE_FORMAT_BGRA4444:		// This is not supported ever; bump up to 32 bit
		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRA8888;

		// Bye, bye dest alpha
		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRX8888;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
			return IMAGE_FORMAT_BGR565;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRA5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRX5551;

		return IMAGE_FORMAT_UNKNOWN;

	case IMAGE_FORMAT_RGB888:
	case IMAGE_FORMAT_BGR888:
	case IMAGE_FORMAT_RGB888_BLUESCREEN:
	case IMAGE_FORMAT_BGRX8888:
		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRX8888;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRA8888;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
			return IMAGE_FORMAT_BGR565;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRA5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRX5551;

		return IMAGE_FORMAT_UNKNOWN;

	case IMAGE_FORMAT_RGB565:
	case IMAGE_FORMAT_BGR565:
		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
			return IMAGE_FORMAT_BGR565;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRA5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRX5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRX8888;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRA8888;

		return IMAGE_FORMAT_UNKNOWN;

	case IMAGE_FORMAT_BGRX5551:
		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRX5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRA5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
			return IMAGE_FORMAT_BGR565;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRX8888;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRA8888;

		return IMAGE_FORMAT_UNKNOWN;

	case IMAGE_FORMAT_BGRA5551:
		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRA5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
			return IMAGE_FORMAT_BGRX5551;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
			return IMAGE_FORMAT_BGR565;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRA8888;

		if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
			return IMAGE_FORMAT_BGRX8888;

		return IMAGE_FORMAT_UNKNOWN;
	}

	return IMAGE_FORMAT_UNKNOWN;
}

#if defined( _X360 )
const char *D3DFormatName( D3DFORMAT d3dFormat )
{
	if ( IS_D3DFORMAT_SRGB( d3dFormat ) )
	{
		// sanitize the format from possible sRGB state for comparison purposes
		d3dFormat = MAKE_NON_SRGB_FMT( d3dFormat );
	}

	switch ( d3dFormat )
	{
	case D3DFMT_A8R8G8B8:
		return "D3DFMT_A8R8G8B8";
	case D3DFMT_LIN_A8R8G8B8:
		return "D3DFMT_LIN_A8R8G8B8";
	case D3DFMT_X8R8G8B8:
		return "D3DFMT_X8R8G8B8";
	case D3DFMT_LIN_X8R8G8B8:
		return "D3DFMT_LIN_X8R8G8B8";
	case D3DFMT_R5G6B5:
		return "D3DFMT_R5G6B5";
	case D3DFMT_X1R5G5B5:
		return "D3DFMT_X1R5G5B5";
	case D3DFMT_A1R5G5B5:
		return "D3DFMT_A1R5G5B5";
	case D3DFMT_A4R4G4B4:
		return "D3DFMT_A4R4G4B4";
	case D3DFMT_L8:
		return "D3DFMT_L8";
	case D3DFMT_A8L8:
		return "D3DFMT_A8L8";
	case D3DFMT_A8:
		return "D3DFMT_A8";
	case D3DFMT_DXT1:
		return "D3DFMT_DXT1";
	case D3DFMT_DXT3:
		return "D3DFMT_DXT3";
	case D3DFMT_DXT5:
		return "D3DFMT_DXT5";
	case D3DFMT_V8U8:
		return "D3DFMT_V8U8";
	case D3DFMT_Q8W8V8U8:
		return "D3DFMT_Q8W8V8U8";
	case D3DFMT_D16:
		return "D3DFMT_D16";
	case D3DFMT_D24S8:
		return "D3DFMT_D24S8";
	case D3DFMT_D24FS8:
		return "D3DFMT_D24FS8";
	case D3DFMT_LIN_D24S8:
		return "D3DFMT_LIN_D24S8";
	case D3DFMT_A16B16G16R16:
		return "D3DFMT_A16B16G16R16";
	case D3DFMT_LIN_A16B16G16R16:
		return "D3DFMT_LIN_A16B16G16R16";
	}
	return "???";
}
#endif