D3D9Resource.cpp

http://code.google.com/p/gamebravo/source/browse/trunk/UnrealX/D3D9Drv/D3D9Resource.cpp?spec=svn308&r=308

/*=============================================================================
        D3DResource.cpp: Unreal Direct3D resource implementation.
        Copyright 2001 Epic Games, Inc. All Rights Reserved.

        Revision history:
                * Created by Andrew Scheidecker
=============================================================================*/

#include "D3D9Drv.h"

#define RESOURCE_POOL D3DPOOL_MANAGED

//
//      FD3D9Resource::FD3D9Resource
//
FD3D9Resource::FD3D9Resource(UD3D9RenderDevice* InRenDev,QWORD InCacheId)
{
        guard(FD3D9Resource::FD3D9Resource);

        RenDev = InRenDev;
        CacheId = InCacheId;
        CachedRevision = 0;

        // Add this resource to the device resource list.
        NextResource = RenDev->ResourceList;
        RenDev->ResourceList = this;

        // Calculate a hash index.
        HashIndex = GetResourceHashIndex(CacheId);

        // Add this resource to the device resource hash.
        HashNext = RenDev->ResourceHash[HashIndex];
        RenDev->ResourceHash[HashIndex] = this;

        LastFrameUsed = 0;

        unguard;
}

//
//      FD3D9Resource::~FD3D9Resource
//
FD3D9Resource::~FD3D9Resource()
{
        guard(FD3D9Resource::~FD3D9Resource);

        FD3D9Resource*  ResourcePtr;

        // Remove this resource from the device resource list.
        if(RenDev->ResourceList != this)
        {
                ResourcePtr = RenDev->ResourceList;

                while(ResourcePtr && ResourcePtr->NextResource != this)
                        ResourcePtr = ResourcePtr->NextResource;

                if(ResourcePtr)
                        ResourcePtr->NextResource = NextResource;

                NextResource = NULL;
        }
        else
        {
                RenDev->ResourceList = NextResource;
                NextResource = NULL;
        }

        // Remove this resource from the device resource hash.
        if(RenDev->ResourceHash[HashIndex] != this)
        {
                ResourcePtr = RenDev->ResourceHash[HashIndex];

                while(ResourcePtr && ResourcePtr->HashNext != this)
                        ResourcePtr = ResourcePtr->HashNext;

                if(ResourcePtr)
                        ResourcePtr->HashNext = HashNext;

                HashNext = NULL;
        }
        else
        {
                RenDev->ResourceHash[HashIndex] = HashNext;
                HashNext = NULL;
        }

        unguard;
}

//
//      FD3D9Texture::FD3D9Texture
//
FD3D9Texture::FD3D9Texture(UD3D9RenderDevice* InRenDev,QWORD InCacheId) : FD3D9Resource(InRenDev,InCacheId)
{
        RenderTargetSurface             = NULL;
        DepthStencilSurface             = NULL;
        Direct3DTexture9                = NULL;
        Direct3DCubeTexture9    = NULL;
}

//
//      FD3D9Texture::~FD3D9Texture
//
FD3D9Texture::~FD3D9Texture()
{
        if( RenderTargetSurface )
                RenderTargetSurface->Release();
        if( DepthStencilSurface )
                DepthStencilSurface->Release();
        if( Direct3DTexture9 )
                Direct3DTexture9->Release();
        if( Direct3DCubeTexture9 )
                Direct3DCubeTexture9->Release();
}

//
//  FD3D9Texture::CalculateFootprint
//
INT FD3D9Texture::CalculateFootprint()
{
        INT     Bytes = 0;

        for(INT MipIndex = CachedFirstMip;MipIndex < CachedNumMips;MipIndex++)
                Bytes += (GetFormatBPP(CachedFormat) * (CachedWidth >> MipIndex) / 8) * (CachedHeight >> MipIndex);

        return Bytes;
}

//
//      FD3D9Texture::Cache
//
UBOOL FD3D9Texture::Cache(FBaseTexture* SourceTexture)
{
        guard(FD3D9Texture::Cache);

        UBOOL   Failed = 0;
        INT             FirstMip = SourceTexture->GetFirstMip(),
                        Width    = SourceTexture->GetWidth(),
                        Height   = SourceTexture->GetHeight(),
                        NumMips  = SourceTexture->GetNumMips();
        HRESULT Result;

        // Determine the source texture format.
        ETextureFormat  SourceFormat =          SourceTexture->GetFormat();

        // Determine the actual texture format.
        ETextureFormat  ActualFormat =          SourceFormat == TEXF_P8         ? TEXF_RGBA8 :
                                                                                SourceFormat == TEXF_G16        ? TEXF_RGBA8 :
                                                                                SourceFormat == TEXF_RGBA7      ? TEXF_RGBA8 :
                                                                                SourceFormat;

        FCompositeTexture*      CompositeTexture = SourceTexture->GetCompositeTextureInterface();
        FCubemap*                       Cubemap = SourceTexture->GetCubemapInterface();
        FTexture*                       Texture = SourceTexture->GetTextureInterface();
        FRenderTarget*          RenderTarget = SourceTexture->GetRenderTargetInterface();

        // Workaround for HW bug on older NVIDIA cards.
        if( RenDev->HasNVCubemapBug
        &&      Texture
        &&      Texture->GetUTexture()
        &&  (appStrcmp(Texture->GetUTexture()->GetPathName(), TEXT("NvidiaLogo_T.PlaySeal_T")) == 0)
        )
                NumMips = Min( 4, NumMips );

        // Verify NumMips.
        INT MinDimension = Min( Width, Height );
        INT LogDimension = 0;
        while( MinDimension > 0 )
        {
                MinDimension >>= 1;
                LogDimension++;
        }
       
        // Spit our warning if too many miplevels.
        //if( NumMips > LogDimension && Texture )
        //      debugf( TEXT("Texture [%s] is %ix%i and has %i Mips instead of %i"), Texture->GetUTexture()->GetPathName(), Width, Height, NumMips, LogDimension );

        // Clamp number of miplevels to avoid crashes.
        NumMips = Min( NumMips, LogDimension );

        // Report dynamic uploads if wanted.
        UBOOL Precaching = RenDev->LockedViewport ? RenDev->LockedViewport->Precaching : 0;
        if( !GIsEditor && !Precaching && UTexture::__Client && UTexture::__Client->ReportDynamicUploads )
        {
                INT Size = 0;
                for( INT i=FirstMip; i<NumMips; i++ )
                        Size += GetBytesPerPixel(ActualFormat,(Width >> i) * (Height >> i));
                if( CompositeTexture )
                {
                        debugf(TEXT("Uploading Lightmap!!!"));
                }
                else if( Cubemap )
                {
                        debugf(TEXT("Uploading Cubemap: Texture=[%s], Size=[%i]"),Cubemap->GetFace(0)->GetUTexture()->GetPathName(),Size*6);
                }
                else if( Texture )
                {
                        debugf(TEXT("Uploading Texture: Texture=[%s], Size=[%i]"),Texture->GetUTexture()->GetPathName(),Size);
                }
        }

        // Use first face if cubemaps aren't supported.
        if( Cubemap && !RenDev->SupportsCubemaps )
        {
                Texture = Cubemap->GetFace(0);
                Cubemap = NULL;
        }

        // Determine the corresponding Direct3D format.
        D3DFORMAT               Direct3DFormat =        ActualFormat == TEXF_RGBA8      ? (RenDev->SupportsTextureFormat(TEXF_RGBA8) ? D3DFMT_A8R8G8B8 : D3DFMT_A4R4G4B4 ) :
                                                                                ActualFormat == TEXF_DXT1       ? D3DFMT_DXT1 :
                                                                                ActualFormat == TEXF_DXT3       ? D3DFMT_DXT3 :
                                                                                ActualFormat == TEXF_DXT5       ? D3DFMT_DXT5 :
                                                                                D3DFMT_UNKNOWN;

        // Calculate the first mipmap to use.
        UBOOL DownSample = 0;
        while((Width >> FirstMip) > (INT) RenDev->DeviceCaps9.MaxTextureWidth || (Height >> FirstMip) > (INT) RenDev->DeviceCaps9.MaxTextureHeight)
                if(++FirstMip >= NumMips)
                        DownSample = 1;

        if( DownSample )
                FirstMip = 0;

        INT     USize = Width  >> FirstMip,
                VSize = Height >> FirstMip;

        INT ScaleX = 1,
                ScaleY = 1;
        if( DownSample )
        {
                USize   = Min<INT>(USize, RenDev->DeviceCaps9.MaxTextureWidth);
                VSize   = Min<INT>(VSize, RenDev->DeviceCaps9.MaxTextureHeight);
                ScaleX  = Width  / USize;
                ScaleY  = Height / VSize;
                //if( SourceTexture->GetTextureInterface() )
                //      debugf(TEXT("Downsampling: %s"), SourceTexture->GetTextureInterface()->GetUTexture()->GetFullName());
        }

        if( !VSize || !USize )
        {
                if(SourceTexture->GetTextureInterface() && SourceTexture->GetTextureInterface()->GetUTexture())
                        debugf(TEXT("ERROR! ZERO USIZE OR VSIZE ON TEXTURE: %s"), SourceTexture->GetTextureInterface()->GetUTexture()->GetFullName());

                Direct3DCubeTexture9    = NULL;
                Direct3DTexture9                = NULL;
        }
        else if( CompositeTexture )
        {
                //!!vogel
                // In UT2003 lightmaps are the only composite textures. They are opaque RGBA8888 512x512 and
                // we therefore can easily convert them to 256x256 RGB565. If this assumption ever changes please
                // change the code below.
                INT     NumChildren = CompositeTexture->GetNumChildren();

                if(!Direct3DTexture9 || CachedWidth != USize || CachedHeight != VSize || CachedFirstMip != 0 || CachedNumMips != 1 || CachedFormat != Direct3DFormat)
                {
                        // Release the existing texture.
                        if(Direct3DTexture9)
                                Direct3DTexture9->Release();

                        // Voodoo 3 specific hack.
                        if( ActualFormat == TEXF_RGBA8 && !RenDev->SupportsTextureFormat(TEXF_RGBA8) )
                                Direct3DFormat = D3DFMT_R5G6B5;

                        // Create a new Direct3D texture.
                        Result = RenDev->Direct3DDevice9->CreateTexture(
                                USize,
                                VSize,
                                1,
                                0,
                                Direct3DFormat,
                                D3DPOOL_MANAGED,
                                &Direct3DTexture9,
                                NULL
                                );
       
                        if( FAILED(Result) )
                                appErrorf(TEXT("CreateTexture failed(%s)."),*D3DError(Result));

                        CachedChildRevision.Empty(NumChildren);
                }

                if(CachedChildRevision.Num() != NumChildren)
                {
                        CachedChildRevision.Empty(NumChildren);
                        CachedChildRevision.AddZeroed(NumChildren);

                        // Lock the Direct3D texture.
                        D3DLOCKED_RECT  LockedRect;

                        Result = Direct3DTexture9->LockRect(0,&LockedRect,NULL,0);

                        if( FAILED(Result) )
                                appErrorf(TEXT("LockRect failed(%s)."),*D3DError(Result));

                        // Copy all children into the texture.
                        BYTE*   Data    = (BYTE*) LockedRect.pBits;
                        INT             Pitch   = LockedRect.Pitch;
#ifdef _XBOX
                        //!!vogel: TODO: don't use dynamic memory allocation.
                        if ( ActualFormat == TEXF_RGBA8 )
                                Data = new BYTE[VSize * LockedRect.Pitch];
#else
                        if( Direct3DFormat == D3DFMT_R5G6B5 )
                        {
                                Pitch   = Width * 4;
                                Data    = new BYTE[Height * Pitch];
                        }
#endif
                        for(INT ChildIndex = 0;ChildIndex < NumChildren;ChildIndex++)
                        {
                                INT                     ChildX = 0,
                                                        ChildY = 0;
                                FTexture*       Child = CompositeTexture->GetChild(ChildIndex,&ChildX,&ChildY);
                                INT                     ChildRevision = Child->GetRevision();
                                BYTE*           TileData = CalculateTexelPointer(Data,ActualFormat,Pitch,ChildX,ChildY);

                                // Read the child texture into the locked region.
                                Child->GetTextureData(0,TileData,Pitch,ActualFormat,0);

                                CachedChildRevision(ChildIndex) = ChildRevision;
                        }

#ifdef _XBOX
                        // Non compressed textures need swizzling.
                        if( ActualFormat == TEXF_RGBA8 )
                        {
                                XGSwizzleRect(Data,LockedRect.Pitch,NULL,LockedRect.pBits,USize,VSize,NULL,4);
                                delete [] Data;
                        }
#else
                        if( Direct3DFormat == D3DFMT_R5G6B5 )
                        {
                                // Convert 512x512 RGBA8888 lightmap to 256x256 RGB565
                                DWORD* Src = (DWORD*) Data;
                                _WORD* Dst = (_WORD*) LockedRect.pBits;
                               
                                check( (USize == 256) && (VSize == 256) && DownSample );
                                for( INT y=0; y<VSize; y++ )
                                {
                                        for( INT x=0; x<USize; x++ )
                                        {
                                                *(Dst++) = FColor(*Src).HiColor565();
                                                Src += 2;
                                        }
                                        Src += USize * 2;
                                }
                                delete [] Data;
                        }
#endif
                        // Unlock the Direct3D texture.
                        Direct3DTexture9->UnlockRect(0);
                }
                else
                {
                        // XBox relies on this code never be called.
                        check(GIsEditor);

                        // Update modified subrects of the texture.
                        for(INT ChildIndex = 0;ChildIndex < NumChildren;ChildIndex++)
                        {
                                INT                     ChildX = 0,
                                                        ChildY = 0;
                                FTexture*       Child = CompositeTexture->GetChild(ChildIndex,&ChildX,&ChildY);
                                INT                     ChildRevision = Child->GetRevision();

                                if(CachedChildRevision(ChildIndex) != ChildRevision)
                                {
                                        // Lock the Direct3D texture.
                                        D3DLOCKED_RECT  LockedRect;
                                        RECT                    ChildRect;
                       
                                        ChildRect.left = ChildX;
                                        ChildRect.top = ChildY;
                                        ChildRect.right = ChildX + Child->GetWidth();
                                        ChildRect.bottom = ChildY + Child->GetHeight();

                                        Result = Direct3DTexture9->LockRect(0,&LockedRect,&ChildRect,0);

                                        if( FAILED(Result) )
                                                appErrorf(TEXT("LockRect failed(%s)."),*D3DError(Result));

                                        // Read the child texture into the locked region.
                                        Child->GetTextureData(0,(void*) LockedRect.pBits,LockedRect.Pitch,ActualFormat,0);

                                        // Unlock the Direct3D texture.
                                        Direct3DTexture9->UnlockRect(0);

                                        CachedChildRevision(ChildIndex) = ChildRevision;
                                }
                        }
                }
        }
        else if ( Cubemap && RenDev->SupportsCubemaps && RenDev->SupportsTextureFormat(ActualFormat) )
        {
                //!! TODO: conversion code.
                if(!Direct3DCubeTexture9 || CachedWidth != USize || CachedHeight != VSize || CachedFirstMip != FirstMip || CachedNumMips != NumMips || CachedFormat != Direct3DFormat)
                {
                        // Release the existing texture.
                        if(Direct3DCubeTexture9)
                                Direct3DCubeTexture9->Release();

                        if( Width != Height )
                                appErrorf(TEXT("Cubemaps must be square"));

                        // Create a new Direct3D texture.
                        Result = RenDev->Direct3DDevice9->CreateCubeTexture(
                                USize,
                                RenDev->UseMippedCubemaps ? NumMips - FirstMip : 1,
                                0,
                                Direct3DFormat,
                                D3DPOOL_MANAGED,
                                &Direct3DCubeTexture9,
                                NULL
                                );
       
                        if( FAILED(Result) )
                                appErrorf(TEXT("CreateCubeTexture failed(%s)."),*D3DError(Result));
                }

                // Copy the cubemap into the Direct3D cube texture.
                INT Count = RenDev->UseMippedCubemaps ? NumMips : FirstMip+1;
                for(INT MipIndex=FirstMip; MipIndex<Count; MipIndex++)
                {
                        // Lock the Direct3D texture.
                        D3DLOCKED_RECT  LockedRect;
       
                        for(INT Face=0; Face<6; Face++)
                        {
                                FTexture*       Texture = Cubemap->GetFace(Face);

                                if(Texture)
                                {
                                        Result = Direct3DCubeTexture9->LockRect((D3DCUBEMAP_FACES)Face,MipIndex-FirstMip,&LockedRect,NULL,0);

                                        if(Result != D3D_OK)
                                                appErrorf(TEXT("LockRect failed(%s)."),*D3DError(Result));
#ifdef _XBOX
                                        // Non compressed textures need swizzling.
                                        if ( ActualFormat == TEXF_RGBA8 )
                                        {
                                                INT MipWidth  = USize >> (MipIndex - FirstMip);
                                                INT MipHeight = VSize >> (MipIndex - FirstMip);
                                                check( MipHeight && MipWidth );
                                                //!!vogel: TODO: don't use dynamic memory allocation.
                                                BYTE* Data  = new BYTE[MipHeight * LockedRect.Pitch];
                                                Texture->GetTextureData(MipIndex,(void*) Data,LockedRect.Pitch,ActualFormat);
                                                XGSwizzleRect(Data,LockedRect.Pitch,NULL,LockedRect.pBits,MipWidth,MipHeight,NULL,4);
                                                delete [] Data;
                                        }
                                        else
#endif
                                        Texture->GetTextureData(MipIndex,(void*) LockedRect.pBits,LockedRect.Pitch,ActualFormat);

                                        // Unlock the Direct3D texture.
                                        Direct3DCubeTexture9->UnlockRect((D3DCUBEMAP_FACES)Face,MipIndex-FirstMip);
                                }
                        }
                }
        }
        else if(RenderTarget)
        {
                // Pick render target format.
                Direct3DFormat = D3DFMT_A8R8G8B8;

                if( !RenDev->SupportsRenderToTextureRGBA8888 )
                {
                        if( RenDev->SupportsRenderToTextureRGB565 )
                                Direct3DFormat = D3DFMT_R5G6B5;
                        else
                                Failed = 1;
                }

                if( !Failed && (!Direct3DTexture9 || CachedWidth != USize || CachedHeight != VSize || CachedFirstMip != FirstMip || CachedNumMips != NumMips || CachedFormat != Direct3DFormat) )
                {
                        // Release the existing texture.

                        if(Direct3DTexture9)
                                Direct3DTexture9->Release();

                        // Try to allocate the render target.
                        // Direct3D won't bump managed textures out of memory for it, so if the first allocation fails,
                        // it will manually ask D3D to free up video memory and try to allocate the render target again.

                        INT     NumTries = 0;

                        Result = 0;

                        while(NumTries < 2)
                        {
                                // Create a new Direct3D texture.

                                Result = RenDev->Direct3DDevice9->CreateTexture(
                                        USize,
                                        VSize,
                                        NumMips - FirstMip,
                                        D3DUSAGE_RENDERTARGET,
                                        Direct3DFormat,
                                        D3DPOOL_DEFAULT,
                                        &Direct3DTexture9,
                                        NULL
                                        );

                                if( !FAILED(Result) )
                                        break;

#ifndef _XBOX
                                if( FAILED(RenDev->Direct3DDevice9->EvictManagedResources(/*GetBytesPerPixel(ActualFormat,USize) * VSize*/)) )
                                        appErrorf(TEXT("EvictManagedResources failed."));
#endif

                                NumTries++;
                        };

                        if( FAILED(Result) )
                                Failed = 1;
                        else
                        {
                                // Retrieve the texture's surface.

                                Result = Direct3DTexture9->GetSurfaceLevel(0,&RenderTargetSurface);

                                if( FAILED(Result) )
                                        appErrorf(TEXT("GetSurfaceLevel failed(%s)."),*D3DError(Result));
                        }
                }

                if(!Failed)
                {
                        if(!DepthStencilSurface || CachedWidth != USize || CachedHeight != VSize || CachedFirstMip != FirstMip || CachedNumMips != NumMips)
                        {
                                // Release the existing texture.
                                if(DepthStencilSurface)
                                        DepthStencilSurface->Release();

                                INT     NumTries = 0;

                                Result = 0;

                                while(NumTries < 4)
                                {
                                        // Create a new Direct3D depth-stencil surface.

                                        Result = RenDev->Direct3DDevice9->CreateDepthStencilSurface(
                                                USize,
                                                VSize,
#ifdef _XBOX
                                                D3DFMT_LIN_D24S8,
#else
                                                RenDev->DepthBufferFormat,
#endif
                                                D3DMULTISAMPLE_NONE,
                                                0,                                //multisample quality
                                                TRUE,
                                                &DepthStencilSurface,
                                                NULL
                                                );

                                        if( !FAILED(Result) )
                                                break;

#ifndef _XBOX
                                        if( FAILED(RenDev->Direct3DDevice9->EvictManagedResources(/*USize * VSize * 4*/)) )
                                                appErrorf(TEXT("EvictManagedResources failed."));
#endif

                                        NumTries++;
                                };
               
                                if( FAILED(Result) )
                                        Failed = 1;
                        }
                }

                if(Failed)
                {
                        if(RenderTargetSurface)
                                RenderTargetSurface->Release();

                        if(Direct3DTexture9)
                                Direct3DTexture9->Release();
               
                        if(DepthStencilSurface)
                                DepthStencilSurface->Release();

                        Direct3DTexture9                = NULL;
                        Direct3DCubeTexture9    = NULL;
                        RenderTargetSurface             = NULL;
                        DepthStencilSurface             = NULL;
                }
        }
        else if ( Texture )
        {
                // Conversion variables.
                BYTE* Data              = NULL;
                UBOOL ForceRGBA = 0;
                UBOOL WasRGBA   = 0;

                // Convert if necessary.
                if( !RenDev->SupportsTextureFormat(ActualFormat) && (IsDXTC(ActualFormat) || RenDev->Use16bitTextures) )
                {
                        if( ActualFormat == TEXF_RGBA8 )
                        {
                                Direct3DFormat = D3DFMT_A4R4G4B4;
                                if( DownSample )
                                {
                                        Data = new BYTE[4*Width*Height];
                                        Texture->GetTextureData(FirstMip,Data,Width * 4,ActualFormat);
                                }
                                else
                                {
                                        Data = new BYTE[4*USize*VSize];
                                        Texture->GetTextureData(FirstMip,Data,USize * 4,ActualFormat);
                                }
                                WasRGBA = 1;
                        }
                        else
                        {
                               
                                ActualFormat = Texture->GetUTexture()->ConvertDXT( FirstMip, !RenDev->SupportsTextureFormat(TEXF_DXT1), 0, &Data );
                                switch( ActualFormat )
                                {
                                case TEXF_RGBA8:
                                        Direct3DFormat  = RenDev->SupportsTextureFormat(TEXF_RGBA8) ? D3DFMT_A8R8G8B8 : D3DFMT_A4R4G4B4;
                                        ForceRGBA               = 1;
                                        break;
                                case TEXF_DXT1:
                                        Direct3DFormat  = D3DFMT_DXT1;
                                        ForceRGBA               = 0;
                                        break;
                                default:
                                        appErrorf(TEXT("ConvertDXT returned unknown texture format"));
                                }
                        }
                }

                if(!Direct3DTexture9 || CachedWidth != USize || CachedHeight != VSize || CachedFirstMip != FirstMip || CachedNumMips != NumMips || CachedFormat != Direct3DFormat)
                {
                        // Release the existing texture.
                        if(Direct3DTexture9)
                                Direct3DTexture9->Release();

                        // Create a new Direct3D texture.
                        Result = RenDev->Direct3DDevice9->CreateTexture(
                                USize,
                                VSize,
                                NumMips - FirstMip,
                                0,
                                Direct3DFormat,
                                D3DPOOL_MANAGED,
                                &Direct3DTexture9,
                                NULL
                                );
       
                        if( FAILED(Result) )
                                appErrorf(TEXT("CreateTexture failed(%s)."),*D3DError(Result));
                }

                // Copy the texture into the Direct3D texture.
                for(INT MipIndex = FirstMip;MipIndex < NumMips;MipIndex++)
                {
                        // Lock the Direct3D texture.
                        D3DLOCKED_RECT  LockedRect;
                        INT                             MipWidth  = USize >> (MipIndex - FirstMip),
                                                        MipHeight = VSize >> (MipIndex - FirstMip);
       
                        Result = Direct3DTexture9->LockRect(MipIndex - FirstMip,&LockedRect,NULL,0);

                        if( FAILED(Result) )
                                appErrorf(TEXT("LockRect failed(%s)."),*D3DError(Result));

#ifdef _XBOX
                        // Non compressed textures need swizzling.
                        if ( ActualFormat == TEXF_RGBA8 )
                        {
                                if ( MipHeight && MipWidth ) //!!TODO: DEBUG
                                {
                                        BYTE* Data  = new BYTE[MipHeight * LockedRect.Pitch];
                                        Texture->GetTextureData(MipIndex,(void*) Data,LockedRect.Pitch,ActualFormat,(MipIndex >= RenDev->FirstColoredMip));
                                        XGSwizzleRect(Data,LockedRect.Pitch,NULL,LockedRect.pBits,MipWidth,MipHeight,NULL,4);
                                        delete [] Data;
                                }
                                else
                                        debugf(TEXT("!!vogel: debug this"));
                        }
                        else
#else
                        if( Data )
                        {
                                INT USize       = MipWidth;
                                INT VSize       = MipHeight;
                                INT Stride;
                                if( IsDXTC(ActualFormat) )
                                {
                                        USize   = Max( USize, 4 );
                                        VSize   = Max( VSize, 4 ) / 4;
                                        Stride  = GetBytesPerPixel(ActualFormat, USize) * 4;
                                }
                                else
                                        Stride  = GetBytesPerPixel(ActualFormat, USize);        

                                if( RenDev->Use16bitTextures )
                                {
                                        Stride /= 2;

                                        // convert to 4444
                                        DWORD* Src = (DWORD*) Data;
                                        _WORD* Dst = (_WORD*) Data;
                                        if( DownSample )
                                        {
                                                for( INT y=0; y<VSize; y++ )
                                                {
                                                        for( INT x=0; x<USize; x++ )
                                                        {
                                                                *(Dst++) = FColor(*Src).HiColor4444();
                                                                Src += ScaleX;
                                                        }
                                                        Src += Width * (ScaleY - 1);
                                                }
                                        }
                                        else
                                        {
                                                for( INT y=0; y<VSize; y++ )
                                                {
                                                        for( INT x=0; x<USize; x++ )            
                                                        {
                                                                *(Dst++) = FColor(*(Src++)).HiColor4444();
                                                        }
                                                }
                                        }
                                }

                                if( LockedRect.Pitch == Stride )
                                        appMemcpy( LockedRect.pBits, Data, Stride * VSize );
                                else
                                {
                                        BYTE* Dest = (BYTE*) LockedRect.pBits;
                                        BYTE* Src  = (BYTE*) Data;
                                        for( INT h=0; h<VSize; h++ )
                                        {
                                                appMemcpy( Dest, Src, Stride );
                                                Dest += LockedRect.Pitch;
                                                Src  += Stride;
                                        }
                                }
                        }
                        else
#endif
                        if( !RenDev->Use16bitTextures )
                                Texture->GetTextureData(MipIndex,(void*) LockedRect.pBits,LockedRect.Pitch,ActualFormat,(MipIndex >= RenDev->FirstColoredMip));
       
                        if( Data )
                        {
                                delete [] Data;
                                Data = NULL;
                                if( MipIndex < (NumMips-1) )
                                {
                                        if( WasRGBA )
                                        {
                                                // Actually too much memory.
                                                Data = new BYTE[4 * MipWidth * MipHeight];
                                                Texture->GetTextureData(MipIndex+1,Data,MipWidth*2,ActualFormat);
                                        }
                                        else
                                                Texture->GetUTexture()->ConvertDXT( MipIndex+1, ForceRGBA, 0, &Data );          
                                }
                        }

                        // Unlock the Direct3D texture.
                        Direct3DTexture9->UnlockRect(MipIndex - FirstMip);
                }
                delete [] Data;
        }
        // Not supported. Instead of bombing out set the NULL texture.
        else
        {
                Direct3DCubeTexture9    = NULL;
                Direct3DTexture9                = NULL;
        }

        // Update the cached info.
        CachedRevision  = SourceTexture->GetRevision();
        CachedWidth             = USize;
        CachedHeight    = VSize;
        CachedFirstMip  = FirstMip;
        CachedNumMips   = NumMips;
        CachedFormat    = Direct3DFormat;

        return Failed;

        unguard;
}

//
//      FD3D9VertexStream::FD3D9VertexStream
//
FD3D9VertexStream::FD3D9VertexStream(UD3D9RenderDevice* InRenDev,QWORD InCacheId) : FD3D9Resource(InRenDev,InCacheId)
{
        Direct3DVertexBuffer9 = NULL;
}

//
//      FD3D9VertexStream::~FD3D9VertexStream
//
FD3D9VertexStream::~FD3D9VertexStream()
{
        if(Direct3DVertexBuffer9)
                Direct3DVertexBuffer9->Release();
}

//
//  FD3D9VertexStream::CalculateFootprint
//
INT FD3D9VertexStream::CalculateFootprint()
{
        return CachedSize;
}

//
//      FD3D9VertexStream::Cache
//
void FD3D9VertexStream::Cache(FVertexStream* SourceStream)
{
        guard(FD3D9VertexStream::Cache);

        check(SourceStream);
        check(RenDev);

        INT             Size = SourceStream->GetSize();
        HRESULT Result;

    // sjs ---
    DWORD UsageFlags = D3DUSAGE_WRITEONLY;
    D3DPOOL PoolFlags = RESOURCE_POOL;
    DWORD LockFlags = 0;
    if( (Size < 0) || SourceStream->HintDynamic() )
    {
        Size = Abs(Size);
        UsageFlags = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
        PoolFlags = D3DPOOL_DEFAULT;
#ifndef _XBOX
        LockFlags = D3DLOCK_DISCARD;
#endif
    }
    // --- sjs

#ifndef _XBOX
        if( SourceStream->UseNPatches() && RenDev->UseNPatches )
                UsageFlags |= D3DUSAGE_NPATCHES;

        if( !RenDev->UseHardwareTL )
                UsageFlags |= D3DUSAGE_SOFTWAREPROCESSING;
#endif

        if(!Direct3DVertexBuffer9 || CachedSize != Size)
        {
                // Release the existing vertex buffer.
                if(Direct3DVertexBuffer9)
                        Direct3DVertexBuffer9->Release();

                D3DPOOL PoolFlags       = D3DPOOL_DEFAULT;
                INT Result       = D3D_OK;
                INT NumTries = 0;

                while( NumTries < 3 )
                {
                        // Use systemmem pool if allocation in default pool fails.
                        if( NumTries == 2 )
                                PoolFlags = D3DPOOL_SYSTEMMEM;

                        // Create a new Direct3D vertex buffer.
                        Result = RenDev->Direct3DDevice9->CreateVertexBuffer(Size,UsageFlags,0,PoolFlags,&Direct3DVertexBuffer9, NULL);
                        if( SUCCEEDED(Result) )
                                break;
#ifndef _XBOX
                        if( FAILED(RenDev->Direct3DDevice9->EvictManagedResources() ) )
                                appErrorf(TEXT("EvictManagedResources failed."));
#endif
                        NumTries++;
                }
       
                if( FAILED(Result) )
                        appErrorf(TEXT("CreateVertexBuffer failed(%s)."),*D3DError(Result));
        }

        // Lock the vertex buffer.
        BYTE*   VertexBufferContents;

        Result = Direct3DVertexBuffer9->Lock(0, Size, reinterpret_cast<void**>(&VertexBufferContents), LockFlags);

        if( FAILED(Result) )
                appErrorf(TEXT("IDirect3DVertexBuffer9::Lock failed(%s)."),*D3DError(Result));

        // Copy the stream contents into the vertex buffer.
        try
        {
                SourceStream->GetStreamData(VertexBufferContents);
        }
        catch( ... )
        {
                debugf(NAME_Error, TEXT("Locked rendering resource invalid - mode switch?"));
        }


        // Unlock the vertex buffer.
        Result = Direct3DVertexBuffer9->Unlock();

        if( FAILED(Result) )
                appErrorf(TEXT("IDirect3DVertexBuffer9::Unlock failed(%s)."),*D3DError(Result));

        // Update the cached info.
        CachedRevision = SourceStream->GetRevision();
        CachedSize = Size;

        unguard;
}

//
//      FD3D9DynamicVertexStream::FD3D9DynamicVertexStream
//
#define INITIAL_DYNAMIC_VERTEXBUFFER_SIZE       65536   // Initial size of dynamic vertex buffers, in bytes.

BYTE DummyBuffer[512 * 1024];

FD3D9DynamicVertexStream::FD3D9DynamicVertexStream(UD3D9RenderDevice* InRenDev) : FD3D9VertexStream(InRenDev,NULL)
{
        guard(FD3D9DynamicVertexStream::FD3D9DynamicVertexStream);

        Reallocate(INITIAL_DYNAMIC_VERTEXBUFFER_SIZE);

        unguard;
}

//
//      FD3D9DynamicVertexStream::Reallocate
//
void FD3D9DynamicVertexStream::Reallocate(INT NewSize)
{
        guard(FD3D9DynamicVertexStream::Reallocate);

        debugf(TEXT("Allocating %u byte dynamic vertex buffer."),NewSize);

        // Release the old vertex buffer.
        if(Direct3DVertexBuffer9)
        {
                // Make sure it's not currently bound via SetStreamSource.
                RenDev->DeferredState.UnSetVertexBuffer( Direct3DVertexBuffer9 );
                Direct3DVertexBuffer9->Release();
                Direct3DVertexBuffer9 = NULL;
        }

        // Create a dynamic vertex buffer to hold the vertices.
        CachedSize = NewSize;
        Tail = 0;

        DWORD UsageFlags = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;

#ifndef _XBOX
        if( !RenDev->UseHardwareTL )
                UsageFlags |= D3DUSAGE_SOFTWAREPROCESSING;
#endif

        D3DPOOL PoolFlags       = D3DPOOL_DEFAULT;
        INT Result       = D3D_OK;
        INT NumTries = 0;

        while( NumTries < 3 )
        {
                // Use systemmem pool if allocation in default pool fails.
                if( NumTries == 2 )
                        PoolFlags = D3DPOOL_SYSTEMMEM;

                // Create a new Direct3D vertex buffer.
                Result = RenDev->Direct3DDevice9->CreateVertexBuffer(CachedSize,UsageFlags,0,PoolFlags,&Direct3DVertexBuffer9, NULL);

                if( SUCCEEDED(Result) )
                                break;
#ifndef _XBOX
                        if( FAILED(RenDev->Direct3DDevice9->EvictManagedResources()))
                                appErrorf(TEXT("EvictManagedResources failed."));
#endif
                NumTries++;
        }

        if( FAILED(Result) )
                appErrorf(TEXT("CreateVertexBuffer failed(%s)."),*D3DError(Result));

        unguard;
}

//
//      FD3D9DynamicVertexStream::AddVertices
//
INT FD3D9DynamicVertexStream::AddVertices(FVertexStream* Stream)
{
        guard(FD3D9DynamicVertexStream::AddVertices);

        check(Stream);
        check(RenDev);
        check(Direct3DVertexBuffer9);

        INT     Size = Abs(Stream->GetSize()),
                Stride = Stream->GetStride();

        // If the dynamic vertex buffer isn't big enough to contain all the vertices, resize it.
        DWORD   LockFlags = D3DLOCK_NOOVERWRITE;

        if(Size > CachedSize)
        {
                Reallocate(Size);
#ifndef _XBOX
                LockFlags = D3DLOCK_DISCARD;
#else
                LockFlags = 0;
#endif
                GStats.DWORDStats(RenDev->D3DStats.STATS_DynamicVertexBufferDiscards)++;
        }

        // If the dynamic vertex buffer will overflow with the additional vertices, flush it.
        if( Stream->GetSize()<0 || Tail + Stride + Size > CachedSize || ((DWORD) (Tail + Stride + Size) / Stride) > RenDev->DeviceCaps9.MaxVertexIndex) // sjs - hacked
        {
                Tail = 0;
#ifndef _XBOX
                LockFlags = D3DLOCK_DISCARD;
#else
                LockFlags = 0;
#endif
                GStats.DWORDStats(RenDev->D3DStats.STATS_DynamicVertexBufferDiscards)++;
        }

        // Determine the offset in the vertex buffer to allocate the vertices at.
        INT     VertexBufferOffset = ((Tail + Stride - 1) / Stride) * Stride;

        // Lock the dynamic vertex buffer.
        BYTE*   VertexBufferContents = NULL;

        clock(GStats.DWORDStats(RenDev->D3DStats.STATS_DynamicVertexBufferLockCycles));
        HRESULT Result = Direct3DVertexBuffer9->Lock(VertexBufferOffset, Size, reinterpret_cast<void**>(&VertexBufferContents), LockFlags);
        unclock(GStats.DWORDStats(RenDev->D3DStats.STATS_DynamicVertexBufferLockCycles));
        GStats.DWORDStats(RenDev->D3DStats.STATS_DynamicVertexBufferLockCalls)++;

        if( FAILED(Result) )
                appErrorf(TEXT("IDirect3DVertexBuffer9::Lock failed(%s)."),*D3DError(Result));

        BYTE*   Buffer          = VertexBufferContents;
        DWORD*  BufferEnd       = NULL;

        // Tag memory if overflow detection is enabled.
        if( RenDev->CheckForOverflow )
        {
                if( Size+4 > RenDev->StaticBuffer.Num() )
                {
                        RenDev->StaticBuffer.Empty();
                        RenDev->StaticBuffer.Add( 2 * Max(Size,65535) );
                }
                BufferEnd       = (DWORD*) &RenDev->StaticBuffer(Size+1);
                *BufferEnd      = 0x03221977;
                Buffer          = &RenDev->StaticBuffer(0);
        }

        // Copy the indices into the index buffer.
        try
        {
                Stream->GetStreamData(Buffer);
        }
        catch( ... )
        {
                debugf(NAME_Error, TEXT("Locked rendering resource invalid - mode switch?"));
        }

        // Verify tag.
        if( RenDev->CheckForOverflow )
        {
                check( *BufferEnd == 0x03221977 );
                appMemcpy( VertexBufferContents, Buffer, Size );
        }

        // Unlock the dynamic vertex buffer.
        Result = Direct3DVertexBuffer9->Unlock();

        if( FAILED(Result) )
                appErrorf(TEXT("IDirect3DVertexBuffer9::Unlock failed(%s)."),*D3DError(Result));

        // Update the tail pointer.
        Tail = VertexBufferOffset + Size;

        return VertexBufferOffset / Stride;

        unguard;
}

//
//      FD3D9VertexShader::FD3D9VertexShader
//
FD3D9VertexShader::FD3D9VertexShader(UD3D9RenderDevice* InRenDev,FShaderDeclaration& InDeclaration)
{
        guard(FD3D9VertexShader::FD3D9VertexShader);

        RenDev          = InRenDev;
        Declaration = InDeclaration;

        // Build the Direct3D shader declaration.
        TArray<D3DVERTEXELEMENT9> D3DDeclaration;
        for(INT StreamIndex = 0;StreamIndex < Declaration.NumStreams;StreamIndex++)
        {
                INT CurrOffset = 0;
                for(INT ComponentIndex = 0;ComponentIndex < Declaration.Streams[StreamIndex].NumComponents;ComponentIndex++)
                {
                        FVertexComponent& Component = Declaration.Streams[StreamIndex].Components[ComponentIndex];

                        D3DVERTEXELEMENT9               Element;
                        Element.Stream                  = StreamIndex;
                        Element.Offset                  = CurrOffset;
                        Element.Method                  = D3DDECLMETHOD_DEFAULT;
                        Element.UsageIndex              = 0;

                        INT NumElements                 = 0;

                        switch( Component.Type )
                        {
                        case CT_Float4:
                                Element.Type            = D3DDECLTYPE_FLOAT4;
                                NumElements                     = 4;
                                break;
                        case CT_Float3:
                                Element.Type            = D3DDECLTYPE_FLOAT3;
                                NumElements                     = 3;
                                break;
                        case CT_Float2:
                                Element.Type            = D3DDECLTYPE_FLOAT2;
                                NumElements                     = 2;
                                break;
                        case CT_Float1:
                                Element.Type            = D3DDECLTYPE_FLOAT1;
                                NumElements                     = 1;
                                break;
                        case CT_Color:
                                Element.Type            = D3DDECLTYPE_D3DCOLOR;
                                NumElements                     = 1;
                                break;
                        default:
                                appErrorf(TEXT("Unknown component type %i."), Component.Type);
                        }
               
                        switch( Component.Function )
                        {
                        case FVF_Position:
                                Element.Usage           = D3DDECLUSAGE_POSITION;
                                break;
                        case FVF_Normal:
                                Element.Usage           = D3DDECLUSAGE_NORMAL;
                                break;
                        case FVF_Diffuse:
                                Element.Usage           = D3DDECLUSAGE_COLOR;
                                break;
                        case FVF_Specular:
                                Element.Usage           = D3DDECLUSAGE_COLOR;
                                Element.UsageIndex      = 1;
                                break;
                        case FVF_TexCoord0:
                        case FVF_TexCoord1:
                        case FVF_TexCoord2:
                        case FVF_TexCoord3:
                        case FVF_TexCoord4:
                        case FVF_TexCoord5:
                        case FVF_TexCoord6:
                        case FVF_TexCoord7:
                                Element.Usage           = D3DDECLUSAGE_TEXCOORD;
                                Element.UsageIndex      = Component.Function - FVF_TexCoord0;
                                break;
                        default:
                                appErrorf(TEXT("Unknown component function %i."), Component.Function);
                        }
                       
                        D3DDeclaration.AddItem(Element);

                        CurrOffset += NumElements * 4;
                }
        }

        D3DVERTEXELEMENT9 EndElement = D3DDECL_END();
        D3DDeclaration.AddItem(EndElement);

        // Create the declaration object.
        HRESULT Result = RenDev->Direct3DDevice9->CreateVertexDeclaration( &D3DDeclaration(0), &Decl );
        if( FAILED(Result) )
                appErrorf(TEXT("CreateVertexDeclaration failed(%s)."),*D3DError(Result));

        // Add the vertex shader to the device vertex shader list.
        NextVertexShader                = RenDev->VertexShaders;
        RenDev->VertexShaders   = this;

        unguard;
}

//
//      FD3D9VertexShader::~FD3D9VertexShader
//
FD3D9VertexShader::~FD3D9VertexShader()
{
        guard(FD3D9VertexShader::~FD3D9VertexShader);

        // Remove the vertex shader from the device vertex shader list.
        FD3D9VertexShader*      ShaderPtr;

        if(RenDev->VertexShaders != this)
        {
                ShaderPtr = RenDev->VertexShaders;

                while(ShaderPtr && ShaderPtr->NextVertexShader != this)
                        ShaderPtr = ShaderPtr->NextVertexShader;

                if(ShaderPtr)
                        ShaderPtr->NextVertexShader = NextVertexShader;

                NextVertexShader = NULL;
        }
        else
        {
                RenDev->VertexShaders = NextVertexShader;
                NextVertexShader = NULL;
        }

        // Delete the vertex shader.
        if (Shader)
        {
                Shader->Release();
                Shader = NULL;
        }
        //RenDev->DeferredState.DeleteVertexShader(Handle);

        unguard;
}

//
//      FD3D9FixedVertexShader::FD3D9FixedVertexShader
//
FD3D9FixedVertexShader::FD3D9FixedVertexShader(UD3D9RenderDevice* InRenDev,FShaderDeclaration& InDeclaration) : FD3D9VertexShader(InRenDev,InDeclaration)
{
        guard(FD3D9FixedVertexShader::FD3D9FixedVertexShader);

        Type = VS_FixedFunction;

        // Create the fixed function vertex shader.
       
        // There's no longer such thing as a fixed function vertex shader in dx9, so we null out the shader ptr
        Shader = NULL;  

        unguard;
}

//
//      FD3D9IndexBuffer::FD3D9IndexBuffer
//
FD3D9IndexBuffer::FD3D9IndexBuffer(UD3D9RenderDevice* InRenDev,QWORD InCacheId) : FD3D9Resource(InRenDev,InCacheId)
{
        Direct3DIndexBuffer9 = NULL;
}

//
//      FD3D9IndexBuffer::~FD3D9IndexBuffer
//
FD3D9IndexBuffer::~FD3D9IndexBuffer()
{
        if(Direct3DIndexBuffer9)
                Direct3DIndexBuffer9->Release();
}

//
//  FD3D9IndexBuffer::CalculateFootprint
//
INT FD3D9IndexBuffer::CalculateFootprint()
{
        return CachedSize;
}

//
//      FD3D9IndexBuffer::Cache
//
void FD3D9IndexBuffer::Cache(FIndexBuffer* SourceIndexBuffer)
{
        guard(FD3D9IndexBuffer::Cache);

        INT             Size = Max(2,SourceIndexBuffer->GetSize());
        HRESULT Result;

        if(!Direct3DIndexBuffer9 || CachedSize != Size)
        {
                // Release the existing index buffer.
                if(Direct3DIndexBuffer9)
                        Direct3DIndexBuffer9->Release();

                D3DFORMAT IndexFormat;
                if( SourceIndexBuffer->GetIndexSize() == sizeof(DWORD) )
#ifdef _XBOX
                {
                        IndexFormat = (D3DFORMAT) 0;
                        check(0);
                }
#else
                        IndexFormat = D3DFMT_INDEX32;
#endif
                else
                        IndexFormat = D3DFMT_INDEX16;

                DWORD UsageFlags = D3DUSAGE_WRITEONLY;

#ifndef _XBOX
                if( !RenDev->UseHardwareTL )
                        UsageFlags |= D3DUSAGE_SOFTWAREPROCESSING;
#endif

                // Create a new index buffer.
                Result = RenDev->Direct3DDevice9->CreateIndexBuffer(Size,UsageFlags,IndexFormat,RESOURCE_POOL,&Direct3DIndexBuffer9, NULL);

                if( FAILED(Result) )
                        appErrorf(TEXT("CreateIndexBuffer failed(%s)."),*D3DError(Result));
        }

        if(CachedRevision != SourceIndexBuffer->GetRevision())
        {
                // Lock the index buffer.
                BYTE*   IndexBufferContents = NULL;

                Result = Direct3DIndexBuffer9->Lock(0, Size, reinterpret_cast<void**>(&IndexBufferContents), 0);

                if( FAILED(Result) )
                        appErrorf(TEXT("IDirect3DIndexBuffer9::Lock failed(%s)."),*D3DError(Result));

                // Fill the index buffer.
                SourceIndexBuffer->GetContents(IndexBufferContents);

                // Unlock the index buffer.
                Result = Direct3DIndexBuffer9->Unlock();

                if( FAILED(Result) )
                        appErrorf(TEXT("IDirect3DIndexBuffer9::Unlock failed(%s)."),*D3DError(Result));
        }

        // Update cached info.
        CachedRevision = SourceIndexBuffer->GetRevision();
        CachedSize = Size;

        unguard;
}

//
//      FD3D9DynamicIndexBuffer::FD3D9DynamicIndexBuffer
//
#define INITIAL_DYNAMIC_INDEXBUFFER_SIZE        16384   // Initial size of dynamic index buffers, in bytes.

FD3D9DynamicIndexBuffer::FD3D9DynamicIndexBuffer(UD3D9RenderDevice* InRenDev, INT InIndexSize) : FD3D9IndexBuffer(InRenDev,NULL), IndexSize(InIndexSize)
{
        guard(FD3D9DynamicIndexBuffer::FD3D9DynamicIndexBuffer);

        Reallocate(INITIAL_DYNAMIC_INDEXBUFFER_SIZE);

        unguard;
}

//
//      FD3D9DynamicIndexBuffer::Reallocate
//
void FD3D9DynamicIndexBuffer::Reallocate(INT NewSize)
{
        guard(FD3D9DynamicIndexBuffer::Reallocate);

        debugf(TEXT("Allocating %u byte dynamic index buffer."),NewSize);

        // Release the old index buffer.
        // NOTE: Unsure of this, but I imagine the old index buffer will actually
        // stick around until all rendering calls using it are retired.
        //!!vogel: see comment in VertexBuffer::Reallocate
        if(Direct3DIndexBuffer9)
        {
                Direct3DIndexBuffer9->Release();
                Direct3DIndexBuffer9 = NULL;
        }

        // Create a dynamic vertex buffer to hold the vertices.
        CachedSize = NewSize;
        Tail = 0;

        D3DFORMAT IndexFormat;
        if( IndexSize == sizeof(DWORD) )
#ifdef _XBOX
        {
                IndexFormat = (D3DFORMAT) 0;
                check(0);
        }
#else
                IndexFormat = D3DFMT_INDEX32;
#endif
        else
                IndexFormat = D3DFMT_INDEX16;

        DWORD UsageFlags = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;

#ifndef _XBOX
        if( !RenDev->UseHardwareTL )
                UsageFlags |= D3DUSAGE_SOFTWAREPROCESSING;
#endif
       
        D3DPOOL PoolFlags       = D3DPOOL_DEFAULT;
        INT Result       = D3D_OK;
        INT NumTries = 0;

        while( NumTries < 3 )
        {
                // Use systemmem pool if allocation in default pool fails.
                if( NumTries == 2 )
                        PoolFlags = D3DPOOL_SYSTEMMEM;

                // Create a new Direct3D vertex buffer.
                Result = RenDev->Direct3DDevice9->CreateIndexBuffer(CachedSize,UsageFlags,IndexFormat,PoolFlags,&Direct3DIndexBuffer9, NULL);

                if( SUCCEEDED(Result) )
                                break;
#ifndef _XBOX
                        if( FAILED(RenDev->Direct3DDevice9->EvictManagedResources() ) )
                                appErrorf(TEXT("EvictManagedResources failed."));
#endif
                NumTries++;
        }

        if( FAILED(Result) )
                appErrorf(TEXT("CreateIndexBuffer failed(%s)."),*D3DError(Result));

        unguard;
}

//
//      FD3D9DynamicIndexBuffer::AddIndices
//
INT FD3D9DynamicIndexBuffer::AddIndices(FIndexBuffer* Indices)
{
        guard(FD3D9DynamicIndexBuffer::AddIndices);

    INT Size, Stride;
    guard(GetSize);
        Size = Indices->GetSize();
        Stride = Indices->GetIndexSize();
    unguard;

        // If the dynamic index buffer isn't big enough to contain all the indices, resize it.
        DWORD   LockFlags = D3DLOCK_NOOVERWRITE;

        if(Size > CachedSize)
        {
                Reallocate(Size);
#ifndef _XBOX
                LockFlags = D3DLOCK_DISCARD;
#else
                LockFlags = 0;
#endif
        }

        // If the dynamic index buffer will overflow with the additional indices, flush it.
        if(Tail + Size > CachedSize)
        {
                Tail = 0;
#ifndef _XBOX
                LockFlags = D3DLOCK_DISCARD;
#else
                LockFlags = 0;
#endif
        }

        // Determine the offset in the index buffer to allocate the indices at.
        INT     IndexBufferOffset = Tail;

        // Lock the dynamic index buffer.
        BYTE*   IndexBufferContents = NULL;

        HRESULT Result = Direct3DIndexBuffer9->Lock(IndexBufferOffset, Size, reinterpret_cast<void**>(&IndexBufferContents), LockFlags);

        if( FAILED(Result) )
                appErrorf(TEXT("IDirect3DIndexBuffer9::Lock failed(%s)."),*D3DError(Result));

        BYTE*   Buffer          = IndexBufferContents;
        DWORD*  BufferEnd       = NULL;

        // Tag memory if overflow detection is enabled.
        if( RenDev->CheckForOverflow )
        {
                if( Size+4 > RenDev->StaticBuffer.Num() )
                {
                        RenDev->StaticBuffer.Empty();
                        RenDev->StaticBuffer.Add( 2 * Max(Size,65535) );
                }
                BufferEnd       = (DWORD*) &RenDev->StaticBuffer(Size+1);
                *BufferEnd      = 0x03221977;
                Buffer          = &RenDev->StaticBuffer(0);
        }

        // Copy the indices into the index buffer.
        try
        {
                Indices->GetContents(Buffer);
        }
        catch( ... )
        {
                debugf(NAME_Error, TEXT("Locked rendering resource invalid - mode switch?"));
        }

        // Verify tag.
        if( RenDev->CheckForOverflow )
        {
                check( *BufferEnd == 0x03221977 );
                appMemcpy( IndexBufferContents, Buffer, Size );
        }

        // Unlock the dynamic index buffer.
        Result = Direct3DIndexBuffer9->Unlock();

        if( FAILED(Result) )
                appErrorf(TEXT("IDirect3DIndexBuffer9::Unlock failed(%s)."),*D3DError(Result));

        // Update the tail pointer.
        Tail = IndexBufferOffset + Size;

        return IndexBufferOffset / Stride;

        unguard;
}

INT appAnsiStrlen( ANSICHAR* p )
{
        INT i;
        for( i=0;p[i];i++ );
        return i;
}

//
// FD3D9PixelShader::FD3D9PixelShader
//
FD3D9PixelShader::FD3D9PixelShader(UD3D9RenderDevice* InRenDev, EPixelShader InType, ANSICHAR* InSource)
{
        guard(FD3D9PixelShader::FD3D9PixelShader);

        RenDev  = InRenDev;
        Type    = InType;
        Source  = InSource;

#ifdef _XBOX
        LPXGBUFFER      Object  = NULL;
        LPXGBUFFER      Errors  = NULL;
#else
        ID3DXBuffer *Object = NULL;
        ID3DXBuffer *Errors = NULL;
#endif

        guard(AssembleShader);  
        // Assemble the pixel shader source code
#ifdef _XBOX
        FString Dummy = TEXT("XBox");
        HRESULT Result = XGAssembleShader((CHAR*) *Dummy, Source, appAnsiStrlen(Source), 0, NULL, &Object, &Errors, NULL, NULL, NULL, NULL );
        if( FAILED(Result) )
        {
                if( Errors )
                        appErrorf(TEXT("XGAssembleShader failed(%s): %s"),*D3DError(Result), appFromAnsi((ANSICHAR*)XGBuffer_GetBufferPointer(Errors)) );
                else
                        appErrorf(TEXT("XGAssembleShader failed(%s).  Len was %d"),*D3DError(Result), appAnsiStrlen(Source) );
        }
#else
        HRESULT Result = D3DXAssembleShader( Source, appAnsiStrlen(Source), 0, NULL, 0, &Object, &Errors );
        if( FAILED(Result) )
        {
                if( Errors )
                        appErrorf(TEXT("DXAssembleShader failed(%s): %s"),*D3DError(Result), appFromAnsi((ANSICHAR*)Errors->GetBufferPointer()) );
                else
                        appErrorf(TEXT("DXAssembleShader failed(%s).  Len was %d"),*D3DError(Result), appAnsiStrlen(Source) );
        }
#endif
        unguard;

        guard(CreateShader);
        // Create the pixel shader
#ifdef _XBOX
        HRESULT Result = RenDev->Direct3DDevice9->CreatePixelShader( (D3DPIXELSHADERDEF*) XGBuffer_GetBufferPointer(Object), &Handle );
#else
        HRESULT Result = RenDev->Direct3DDevice9->CreatePixelShader( (DWORD*) Object->GetBufferPointer(), &Shader );
#endif
        if( FAILED(Result) )
                appErrorf(TEXT("CreatePixelShader failed(%s)."),*D3DError(Result));
        unguard;

#ifndef _XBOX
        //!!vogel: FIXME
        Object->Release();
#endif

        // Add the Pixel shader to the device Pixel shader list.
        NextPixelShader = RenDev->PixelShaders;
        RenDev->PixelShaders = this;

        unguard;
}

//
//      FD3D9PixelShader::~FD3D9PixelShader
//
FD3D9PixelShader::~FD3D9PixelShader()
{
        guard(FD3D9PixelShader::~FD3D9PixelShader);

        // Remove the Pixel shader from the device Pixel shader list.
        FD3D9PixelShader*       ShaderPtr;

        if(RenDev->PixelShaders != this)
        {
                ShaderPtr = RenDev->PixelShaders;

                while(ShaderPtr && ShaderPtr->NextPixelShader != this)
                        ShaderPtr = ShaderPtr->NextPixelShader;

                if(ShaderPtr)
                        ShaderPtr->NextPixelShader = NextPixelShader;

                NextPixelShader = NULL;
        }
        else
        {
                RenDev->PixelShaders = NextPixelShader;
                NextPixelShader = NULL;
        }

        // Delete the Pixel shader.
        if( Shader )
                Shader->Release();

        Shader = NULL;

        unguard;
}

你可能感兴趣的:(D3D9Resource.cpp)