Torque3D Documentation / _generateds / gfxD3D9Shader.cpp

gfxD3D9Shader.cpp

Engine/source/gfx/D3D9/gfxD3D9Shader.cpp

More...

Classes:

class

D3DXInclude plugin.

Public Variables

Detailed Description

Public Variables

bool gDisassembleAllShaders 
   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "platform/platform.h"
  25
  26#if defined(TORQUE_OS_XENON)
  27#  include <xtl.h>
  28#else
  29#  include <d3d9.h>
  30#endif
  31
  32#include "gfx/D3D9/gfxD3D9Shader.h"
  33#include "gfx/D3D9/gfxD3D9Device.h"
  34
  35#include "core/frameAllocator.h"
  36#include "core/stream/fileStream.h"
  37#include "core/util/safeDelete.h"
  38#include "console/console.h"
  39#include "math/mMathFn.h"
  40
  41
  42using namespace Torque;
  43
  44extern bool gDisassembleAllShaders;
  45
  46/// D3DXInclude plugin
  47class _gfxD3DXInclude : public ID3DXInclude, public StrongRefBase
  48{
  49private:
  50
  51   Vector<String> mLastPath;
  52
  53public:
  54
  55   void setPath( const String &path )
  56   {
  57      mLastPath.clear();
  58      mLastPath.push_back( path );
  59   }
  60
  61   _gfxD3DXInclude() {}
  62   virtual ~_gfxD3DXInclude() {}
  63
  64   STDMETHOD(Close)(THIS_ LPCVOID pData);
  65
  66   // 360 
  67   STDMETHOD(Open)(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes, /* OUT */ LPSTR pFullPath, DWORD cbFullPath);
  68
  69   // PC
  70   STDMETHOD(Open)(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes)
  71   {
  72      return Open( IncludeType, pFileName, pParentData, ppData, pBytes, NULL, 0 );
  73   }
  74};
  75
  76_gfxD3DXIncludeRef GFXD3D9Shader::smD3DXInclude = NULL;
  77
  78HRESULT _gfxD3DXInclude::Open(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, 
  79                              LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes, 
  80                              LPSTR pFullPath, DWORD cbFullPath)
  81{
  82   // First try making the path relative to the parent.
  83   Torque::Path path = Torque::Path::Join( mLastPath.last(), '/', pFileName );
  84   path = Torque::Path::CompressPath( path );
  85
  86   if ( !Torque::FS::ReadFile( path, (void *&)*ppData, *pBytes, true ) )
  87   {
  88      // Ok... now try using the path as is.
  89      path = String( pFileName );
  90      path = Torque::Path::CompressPath( path );
  91
  92      if ( !Torque::FS::ReadFile( path, (void *&)*ppData, *pBytes, true ) )
  93      {
  94         AssertISV(false, avar( "Failed to open include '%s'.", pFileName));
  95         return E_FAIL;
  96      }
  97   }
  98
  99   // If the data was of zero size then we cannot recurse
 100   // into this file and DX won't call Close() below.
 101   //
 102   // So in this case don't push on the path.
 103   if ( *pBytes > 0 )
 104      mLastPath.push_back( path.getRootAndPath() );
 105
 106   return S_OK;
 107}
 108
 109HRESULT _gfxD3DXInclude::Close( THIS_ LPCVOID pData )
 110{
 111   // Free the data file and pop its path off the stack.
 112   delete [] (U8*)pData;
 113   mLastPath.pop_back();
 114
 115   return S_OK;
 116}
 117
 118GFXD3D9ShaderConstHandle::GFXD3D9ShaderConstHandle()
 119{
 120   clear();
 121}
 122
 123const String& GFXD3D9ShaderConstHandle::getName() const
 124{
 125   if ( mVertexConstant )
 126      return mVertexHandle.name;
 127   else
 128      return mPixelHandle.name;
 129}
 130
 131GFXShaderConstType GFXD3D9ShaderConstHandle::getType() const
 132{
 133   if ( mVertexConstant )
 134      return mVertexHandle.constType;
 135   else
 136      return mPixelHandle.constType;
 137}
 138
 139U32 GFXD3D9ShaderConstHandle::getArraySize() const
 140{
 141   if ( mVertexConstant )
 142      return mVertexHandle.arraySize;
 143   else
 144      return mPixelHandle.arraySize;
 145}
 146
 147S32 GFXD3D9ShaderConstHandle::getSamplerRegister() const
 148{
 149   if ( !mValid || !isSampler() )
 150      return -1;
 151
 152   // We always store sampler type and register index in the pixelHandle,
 153   // sampler registers are shared between vertex and pixel shaders anyway.
 154
 155   return mPixelHandle.offset;   
 156}
 157
 158//------------------------------------------------------------------------------
 159//------------------------------------------------------------------------------
 160
 161
 162bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer)
 163{
 164   PROFILE_SCOPE(GFXD3D9ShaderBufferLayout_setMatrix);
 165
 166   if (pd.constType == GFXSCT_Float4x4)
 167   {
 168      // Special case, we can just blast this guy.
 169      AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!");
 170      if (dMemcmp(basePointer+pd.offset, data, size) != 0)
 171      {
 172         dMemcpy(basePointer+pd.offset, data, size);         
 173         return true;
 174      }
 175
 176      return false;
 177   }
 178   else if (pd.constType == GFXSCT_Float4x3)
 179   {
 180      const U32 csize = 48;
 181
 182      // Loop through and copy 
 183      bool ret = false;
 184      U8* currDestPointer = basePointer + pd.offset;
 185      const U8* currSourcePointer = static_cast<const U8*>(data);
 186      const U8* endData = currSourcePointer + size;
 187      while (currSourcePointer < endData)
 188      {
 189#ifdef TORQUE_DOUBLE_CHECK_43MATS
 190         Point4F col;
 191         ((MatrixF*)currSourcePointer)->getRow(3, &col);
 192         AssertFatal(col.x == 0.0f && col.y == 0.0f && col.z == 0.0f && col.w == 1.0f, "3rd row used");
 193#endif
 194
 195         if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0)
 196         {
 197            dMemcpy(currDestPointer, currSourcePointer, csize);
 198            ret = true;
 199         }
 200         else if (pd.constType == GFXSCT_Float4x3)
 201         {
 202            ret = true;
 203         }
 204
 205         currDestPointer += csize;
 206         currSourcePointer += sizeof(MatrixF);
 207      }
 208
 209      return ret;
 210   }
 211   else
 212   {
 213      PROFILE_SCOPE(GFXD3D9ShaderBufferLayout_setMatrix_not4x4);
 214
 215      // Figure out how big of a chunk we are copying.  We're going to copy 4 columns by N rows of data
 216      U32 csize;
 217      switch (pd.constType)
 218      {
 219      case GFXSCT_Float2x2 :
 220         csize = 32;
 221         break;
 222      case GFXSCT_Float3x3 :
 223         csize = 48;
 224         break;
 225      case GFXSCT_Float3x4 :
 226         csize = 64;
 227         break;
 228      default:
 229         AssertFatal(false, "Unhandled case!");
 230         return false;
 231         break;
 232      }
 233
 234      // Loop through and copy 
 235      bool ret = false;
 236      U8* currDestPointer = basePointer+pd.offset;
 237      const U8* currSourcePointer = static_cast<const U8*>(data);
 238      const U8* endData = currSourcePointer + size;
 239      while (currSourcePointer < endData)
 240      {
 241         if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0)
 242         {
 243            dMemcpy(currDestPointer, currSourcePointer, csize);            
 244            ret = true;
 245         }
 246         else if (pd.constType == GFXSCT_Float4x3)
 247         {
 248            ret = true;
 249         }
 250
 251         currDestPointer += csize;
 252         currSourcePointer += sizeof(MatrixF);
 253      }
 254
 255      return ret;
 256   }
 257}
 258
 259//------------------------------------------------------------------------------
 260GFXD3D9ShaderConstBuffer::GFXD3D9ShaderConstBuffer( GFXD3D9Shader* shader, 
 261                                                    GFXD3D9ShaderBufferLayout* vertexLayoutF, 
 262                                                    GFXD3D9ShaderBufferLayout* vertexLayoutI, 
 263                                                    GFXD3D9ShaderBufferLayout* pixelLayoutF, 
 264                                                    GFXD3D9ShaderBufferLayout* pixelLayoutI ) 
 265{
 266   AssertFatal( shader, "GFXD3D9ShaderConstBuffer() - Got a null shader!" );
 267
 268   // We hold on to this so we don't have to call
 269   // this virtual method during activation.
 270   mDevice = static_cast<GFXD3D9Device*>( GFX )->getDevice();
 271   
 272   mShader = shader;
 273
 274   // TODO: Remove buffers and layouts that don't exist for performance?
 275
 276   mVertexConstBufferLayoutF = vertexLayoutF;
 277   mVertexConstBufferF = new GenericConstBuffer(vertexLayoutF);   
 278   mVertexConstBufferLayoutI = vertexLayoutI;
 279   mVertexConstBufferI = new GenericConstBuffer(vertexLayoutI);   
 280   mPixelConstBufferLayoutF = pixelLayoutF;
 281   mPixelConstBufferF = new GenericConstBuffer(pixelLayoutF);   
 282   mPixelConstBufferLayoutI = pixelLayoutI;
 283   mPixelConstBufferI = new GenericConstBuffer(pixelLayoutI);   
 284}
 285
 286GFXD3D9ShaderConstBuffer::~GFXD3D9ShaderConstBuffer()
 287{   
 288   SAFE_DELETE(mVertexConstBufferF);
 289   SAFE_DELETE(mPixelConstBufferF);
 290   SAFE_DELETE(mVertexConstBufferI);
 291   SAFE_DELETE(mPixelConstBufferI);
 292
 293   if ( mShader )
 294      mShader->_unlinkBuffer( this );
 295}
 296
 297GFXShader* GFXD3D9ShaderConstBuffer::getShader()
 298{
 299   return mShader;
 300}
 301
 302// This is kind of cheesy, but I don't think templates would work well here because 
 303// these functions potentially need to be handled differently by other derived types
 304template<class T>
 305inline void GFXD3D9ShaderConstBuffer::SET_CONSTANT( GFXShaderConstHandle* handle, const T& fv, GenericConstBuffer *vBuffer, GenericConstBuffer *pBuffer )
 306{
 307   AssertFatal(dynamic_cast<const GFXD3D9ShaderConstHandle*>(handle), "Incorrect const buffer type!");
 308   const GFXD3D9ShaderConstHandle* h = static_cast<const GFXD3D9ShaderConstHandle*>(handle);
 309   AssertFatal(h, "Handle is NULL!" );
 310   AssertFatal(h->isValid(), "Handle is not valid!" );
 311   AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
 312   AssertFatal(!mShader.isNull(), "Buffer's shader is null!" );
 313   AssertFatal(!h->mShader.isNull(), "Handle's shader is null!" );
 314   AssertFatal(h->mShader.getPointer() == mShader.getPointer(), "Mismatched shaders!");
 315   if ( h->mInstancingConstant )
 316   {
 317      dMemcpy( mInstPtr+h->mPixelHandle.offset, &fv, sizeof( fv ) );
 318      return;
 319   }
 320   if (h->mVertexConstant)
 321      vBuffer->set(h->mVertexHandle, fv);
 322   if (h->mPixelConstant)
 323      pBuffer->set(h->mPixelHandle, fv);
 324}
 325
 326void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) 
 327{
 328   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 329}
 330
 331void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2F& fv) 
 332{ 
 333   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 334}
 335
 336void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3F& fv) 
 337{ 
 338   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 339}
 340
 341void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4F& fv) 
 342{ 
 343   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 344}
 345
 346void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const PlaneF& fv) 
 347{ 
 348   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 349}
 350
 351void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const ColorF& fv)
 352{ 
 353   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 354}
 355
 356void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const S32 f)
 357{ 
 358   // This is the only type that is allowed to be used
 359   // with a sampler shader constant type, but it is only
 360   // allowed to be set from GLSL.
 361   //
 362   // So we ignore it here... all other cases will assert.
 363   //
 364   if ( ((GFXD3D9ShaderConstHandle*)handle)->isSampler() )
 365      return;
 366
 367   SET_CONSTANT(handle, f, mVertexConstBufferI, mPixelConstBufferI);
 368}
 369
 370void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2I& fv)
 371{ 
 372   SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI);
 373}
 374
 375void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3I& fv)
 376{ 
 377   SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI);
 378}
 379
 380void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4I& fv)
 381{ 
 382   SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI);
 383}
 384
 385void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<F32>& fv)
 386{ 
 387   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 388}
 389
 390void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2F>& fv)
 391{ 
 392   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 393}
 394
 395void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3F>& fv)
 396{ 
 397   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 398}
 399
 400void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4F>& fv)
 401{ 
 402   SET_CONSTANT(handle, fv, mVertexConstBufferF, mPixelConstBufferF);
 403}
 404
 405void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<S32>& fv)
 406{ 
 407   SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI);
 408}
 409
 410void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point2I>& fv)
 411{ 
 412   SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI);
 413}
 414
 415void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point3I>& fv)
 416{ 
 417   SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI);
 418}
 419
 420void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray<Point4I>& fv)
 421{ 
 422   SET_CONSTANT(handle, fv, mVertexConstBufferI, mPixelConstBufferI);
 423}
 424#undef SET_CONSTANT
 425
 426void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matrixType) 
 427{    
 428   AssertFatal(handle, "Handle is NULL!" );
 429   AssertFatal(handle->isValid(), "Handle is not valid!" );
 430
 431   AssertFatal(dynamic_cast<const GFXD3D9ShaderConstHandle*>(handle), "Incorrect const buffer type!"); 
 432   const GFXD3D9ShaderConstHandle* h = static_cast<const GFXD3D9ShaderConstHandle*>(handle); 
 433   AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
 434   AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 
 435
 436   MatrixF transposed;
 437   if (matrixType == GFXSCT_Float4x3)
 438   {
 439      transposed = mat;
 440   }
 441   else
 442   {
 443      mat.transposeTo(transposed);
 444   }
 445
 446   if (h->mInstancingConstant) 
 447   {
 448      if ( matrixType == GFXSCT_Float4x4 )
 449         dMemcpy( mInstPtr+h->mPixelHandle.offset, mat, sizeof( mat ) );
 450         
 451      // TODO: Support 3x3 and 2x2 matricies?      
 452      return;
 453   }
 454
 455   if (h->mVertexConstant) 
 456      mVertexConstBufferF->set(h->mVertexHandle, transposed, matrixType); 
 457   if (h->mPixelConstant) 
 458      mPixelConstBufferF->set(h->mPixelHandle, transposed, matrixType);   
 459}
 460
 461void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType)
 462{
 463   AssertFatal(handle, "Handle is NULL!" );
 464   AssertFatal(handle->isValid(), "Handle is not valid!" );
 465
 466   AssertFatal(dynamic_cast<const GFXD3D9ShaderConstHandle*>(handle), "Incorrect const buffer type!"); 
 467   const GFXD3D9ShaderConstHandle* h = static_cast<const GFXD3D9ShaderConstHandle*>(handle); 
 468   AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
 469   AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 
 470
 471   static Vector<MatrixF> transposed;
 472   if (arraySize > transposed.size())
 473      transposed.setSize(arraySize);
 474
 475   if (matrixType == GFXSCT_Float4x3)
 476   {
 477      dMemcpy(transposed.address(), mat, arraySize * sizeof(MatrixF));
 478   }
 479   else
 480   {
 481      for (U32 i = 0; i < arraySize; i++)
 482         mat[i].transposeTo(transposed[i]);
 483   }
 484
 485   // TODO: Maybe support this in the future?
 486   if (h->mInstancingConstant) 
 487      return;
 488
 489   if (h->mVertexConstant) 
 490      mVertexConstBufferF->set(h->mVertexHandle, transposed.begin(), arraySize, matrixType);
 491   if (h->mPixelConstant) 
 492      mPixelConstBufferF->set(h->mPixelHandle, transposed.begin(), arraySize, matrixType);              
 493}
 494
 495const String GFXD3D9ShaderConstBuffer::describeSelf() const
 496{
 497   String ret;
 498   ret = String("   GFXD3D9ShaderConstBuffer\n");
 499
 500   for (U32 i = 0; i < mVertexConstBufferLayoutF->getParameterCount(); i++)
 501   {
 502      GenericConstBufferLayout::ParamDesc pd;
 503      mVertexConstBufferLayoutF->getDesc(i, pd);
 504
 505      ret += String::ToString("      Constant name: %s", pd.name.c_str());
 506   }
 507
 508   return ret;
 509}
 510
 511void GFXD3D9ShaderConstBuffer::zombify()
 512{
 513}
 514
 515void GFXD3D9ShaderConstBuffer::resurrect()
 516{
 517}
 518
 519bool GFXD3D9ShaderConstBuffer::isDirty()
 520{
 521   bool ret = mVertexConstBufferF->isDirty();
 522   ret |= mVertexConstBufferI->isDirty();
 523   ret |= mPixelConstBufferF->isDirty();
 524   ret |= mPixelConstBufferI->isDirty();
 525   return ret;
 526}
 527
 528void GFXD3D9ShaderConstBuffer::activate( GFXD3D9ShaderConstBuffer *prevShaderBuffer )
 529{
 530   PROFILE_SCOPE(GFXD3D9ShaderConstBuffer_activate);
 531
 532   // NOTE: This is a really critical function as it gets
 533   // called between every draw call to update the constants.
 534   //
 535   // Alot of the calls here are inlined... be careful 
 536   // what you change.
 537
 538   // If the buffer has changed we need to compare it
 539   // with the new buffer to see if we can skip copying
 540   // equal buffer content.
 541   //
 542   // If the buffer hasn't changed then we only will
 543   // be copying the changes that have occured since
 544   // the last activate call.
 545   //
 546   if ( prevShaderBuffer != this )
 547   {
 548      // If the previous buffer is dirty, than we can't compare 
 549      // against it, because it hasn't sent its contents to the
 550      // card yet and must be copied.
 551      if ( prevShaderBuffer && !prevShaderBuffer->isDirty() )
 552      {
 553         PROFILE_SCOPE(GFXD3D9ShaderConstBuffer_activate_dirty_check_1);
 554
 555         // If the buffer content is equal then we set the dirty
 556         // flag to false knowing the current state of the card matches
 557         // the new buffer.
 558         //
 559         // If the content is not equal we set the dirty flag to
 560         // true which causes the full content of the buffer to be
 561         // copied to the card.
 562         //
 563         mVertexConstBufferF->setDirty( !prevShaderBuffer->mVertexConstBufferF->isEqual( mVertexConstBufferF ) );
 564         mPixelConstBufferF->setDirty( !prevShaderBuffer->mPixelConstBufferF->isEqual( mPixelConstBufferF ) );
 565         mVertexConstBufferI->setDirty( !prevShaderBuffer->mVertexConstBufferF->isEqual( mVertexConstBufferI ) );
 566         mPixelConstBufferI->setDirty( !prevShaderBuffer->mPixelConstBufferF->isEqual( mPixelConstBufferI ) );
 567      } 
 568      else
 569      {
 570         // This happens rarely... but it can happen.
 571         //
 572         // We copy the entire dirty state to the card.
 573
 574         PROFILE_SCOPE(GFXD3D9ShaderConstBuffer_activate_dirty_check_2);
 575
 576         mVertexConstBufferF->setDirty( true );
 577         mPixelConstBufferF->setDirty( true );
 578         mVertexConstBufferI->setDirty( true );
 579         mPixelConstBufferI->setDirty( true );
 580      }      
 581   }
 582
 583   const U32 bytesToFloat4 = 16;
 584   const U32 bytesToInt4 = 16;
 585   U32 start, bufferSize;      
 586   const U8* buf;
 587
 588   if ( mVertexConstBufferF->isDirty() )
 589   {
 590      buf = mVertexConstBufferF->getDirtyBuffer( &start, &bufferSize );
 591      mDevice->SetVertexShaderConstantF( start / bytesToFloat4, (float*)buf, bufferSize / bytesToFloat4 );
 592   }
 593
 594   if ( mPixelConstBufferF->isDirty() )    
 595   {
 596      buf = mPixelConstBufferF->getDirtyBuffer( &start, &bufferSize );
 597      mDevice->SetPixelShaderConstantF( start / bytesToFloat4, (float*)buf, bufferSize / bytesToFloat4 );      
 598   }
 599
 600   if ( mVertexConstBufferI->isDirty() )
 601   {
 602      buf = mVertexConstBufferI->getDirtyBuffer( &start, &bufferSize );
 603      mDevice->SetVertexShaderConstantI( start / bytesToInt4, (int*)buf, bufferSize / bytesToInt4 );
 604   }
 605
 606   if ( mPixelConstBufferI->isDirty() )    
 607   {
 608      buf = mPixelConstBufferI->getDirtyBuffer( &start, &bufferSize );
 609      mDevice->SetPixelShaderConstantI( start / bytesToInt4, (int*)buf, bufferSize / bytesToInt4 );      
 610   }
 611
 612   #ifdef TORQUE_DEBUG
 613
 614      // Make sure all the constants for this buffer were assigned.
 615      if ( mWasLost )
 616      {
 617         mVertexConstBufferF->assertUnassignedConstants( mShader->getVertexShaderFile().c_str() );
 618         mVertexConstBufferI->assertUnassignedConstants( mShader->getVertexShaderFile().c_str() );
 619         mPixelConstBufferF->assertUnassignedConstants( mShader->getPixelShaderFile().c_str() );
 620         mPixelConstBufferI->assertUnassignedConstants( mShader->getPixelShaderFile().c_str() );
 621      }
 622
 623   #endif
 624
 625   // Clear the lost state.
 626   mWasLost = false;
 627}
 628
 629void GFXD3D9ShaderConstBuffer::onShaderReload( GFXD3D9Shader *shader )
 630{
 631   AssertFatal( shader == mShader, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" );
 632
 633   SAFE_DELETE( mVertexConstBufferF );
 634   SAFE_DELETE( mPixelConstBufferF );
 635   SAFE_DELETE( mVertexConstBufferI );
 636   SAFE_DELETE( mPixelConstBufferI );
 637        
 638   AssertFatal( mVertexConstBufferLayoutF == shader->mVertexConstBufferLayoutF, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" );   
 639   AssertFatal( mPixelConstBufferLayoutF == shader->mPixelConstBufferLayoutF, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" );   
 640   AssertFatal( mVertexConstBufferLayoutI == shader->mVertexConstBufferLayoutI, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" );   
 641   AssertFatal( mPixelConstBufferLayoutI == shader->mPixelConstBufferLayoutI, "GFXD3D9ShaderConstBuffer::onShaderReload is hosed!" );      
 642
 643   mVertexConstBufferF = new GenericConstBuffer( mVertexConstBufferLayoutF );      
 644   mVertexConstBufferI = new GenericConstBuffer( mVertexConstBufferLayoutI );      
 645   mPixelConstBufferF = new GenericConstBuffer( mPixelConstBufferLayoutF );      
 646   mPixelConstBufferI = new GenericConstBuffer( mPixelConstBufferLayoutI ); 
 647   
 648   // Set the lost state.
 649   mWasLost = true;
 650}
 651
 652//------------------------------------------------------------------------------
 653
 654GFXD3D9Shader::GFXD3D9Shader()
 655{
 656   VECTOR_SET_ASSOCIATION( mShaderConsts );
 657
 658   mD3D9Device = dynamic_cast<GFXD3D9Device *>(GFX)->getDevice();
 659   AssertFatal(mD3D9Device, "Invalid device for shader.");
 660   mVertShader = NULL;
 661   mPixShader = NULL;
 662   mVertexConstBufferLayoutF = NULL;
 663   mPixelConstBufferLayoutF = NULL;
 664   mVertexConstBufferLayoutI = NULL;
 665   mPixelConstBufferLayoutI = NULL;
 666
 667   if( smD3DXInclude == NULL )
 668      smD3DXInclude = new _gfxD3DXInclude;
 669}
 670
 671//------------------------------------------------------------------------------
 672
 673GFXD3D9Shader::~GFXD3D9Shader()
 674{
 675   for (HandleMap::Iterator i = mHandles.begin(); i != mHandles.end(); i++)
 676      delete i->value;
 677   SAFE_DELETE(mVertexConstBufferLayoutF);
 678   SAFE_DELETE(mPixelConstBufferLayoutF);
 679   SAFE_DELETE(mVertexConstBufferLayoutI);
 680   SAFE_DELETE(mPixelConstBufferLayoutI);
 681   SAFE_RELEASE(mVertShader);
 682   SAFE_RELEASE(mPixShader);
 683}
 684
 685bool GFXD3D9Shader::_init()
 686{
 687   PROFILE_SCOPE( GFXD3D9Shader_Init );
 688   
 689   if ( mPixVersion > GFX->getPixelShaderVersion() )
 690   {
 691      if ( smLogErrors )
 692         Con::errorf( "GFXD3D9Shader::init - Bad pixel shader version!" );
 693
 694      return false;
 695   }
 696
 697   if ( mPixVersion < 1.0f && mPixelFile.getFileName().isNotEmpty() )
 698   {
 699      if ( smLogErrors )
 700         Con::errorf( "GFXD3D9Shader::init - Pixel shaders not supported on SM %.1f!", mPixVersion );
 701
 702      return false;
 703   }
 704
 705   SAFE_RELEASE(mVertShader);
 706   SAFE_RELEASE(mPixShader);
 707
 708   U32 mjVer = (U32)mFloor( mPixVersion );
 709   U32 mnVer = (U32)( ( mPixVersion - F32( mjVer ) ) * 10.01f ); // 10.01 instead of 10.0 because of floating point issues
 710
 711   String vertTarget = String::ToString("vs_%d_%d", mjVer, mnVer);
 712   String pixTarget = String::ToString("ps_%d_%d", mjVer, mnVer);
 713
 714   // Adjust version for vertex shaders
 715   if (mjVer == 2 && mnVer == 1)
 716   {      
 717      pixTarget  = "ps_2_a";
 718      vertTarget = "vs_2_0";
 719   }
 720   else if ( mjVer == 2 && mnVer == 2 )
 721   {      
 722      pixTarget  = "ps_2_b";
 723      vertTarget = "vs_2_0";
 724   }
 725   else if ( ( mPixVersion < 2.0f ) && ( mPixVersion > 1.101f ) )
 726      vertTarget = "vs_1_1";      
 727
 728   // Create the macro array including the system wide macros.
 729   const U32 macroCount = smGlobalMacros.size() + mMacros.size() + 2;
 730   FrameTemp<D3DXMACRO> d3dXMacros( macroCount );
 731   for ( U32 i=0; i < smGlobalMacros.size(); i++ )
 732   {
 733      d3dXMacros[i].Name = smGlobalMacros[i].name.c_str();
 734      d3dXMacros[i].Definition = smGlobalMacros[i].value.c_str();
 735   }
 736   for ( U32 i=0; i < mMacros.size(); i++ )
 737   {
 738      d3dXMacros[i+smGlobalMacros.size()].Name = mMacros[i].name.c_str();
 739      d3dXMacros[i+smGlobalMacros.size()].Definition = mMacros[i].value.c_str();
 740   }
 741   String smVersion = String::ToString( mjVer * 10 + mnVer );
 742   d3dXMacros[macroCount - 2].Name = "TORQUE_SM";
 743   d3dXMacros[macroCount - 2].Definition = smVersion.c_str();
 744   d3dXMacros[macroCount - 1].Name = NULL;
 745   d3dXMacros[macroCount - 1].Definition = NULL;
 746
 747   if ( !mVertexConstBufferLayoutF )
 748      mVertexConstBufferLayoutF = new GFXD3D9ShaderBufferLayout();
 749   else
 750      mVertexConstBufferLayoutF->clear();
 751
 752   if ( !mVertexConstBufferLayoutI )
 753      mVertexConstBufferLayoutI = new GFXD3D9ShaderBufferLayout();
 754   else
 755      mVertexConstBufferLayoutI->clear();
 756      
 757   if ( !mPixelConstBufferLayoutF )
 758      mPixelConstBufferLayoutF = new GFXD3D9ShaderBufferLayout();
 759   else
 760      mPixelConstBufferLayoutF->clear();
 761
 762   if ( !mPixelConstBufferLayoutI )
 763      mPixelConstBufferLayoutI = new GFXD3D9ShaderBufferLayout();
 764   else
 765      mPixelConstBufferLayoutI->clear();
 766   
 767   mSamplerDescriptions.clear();
 768   mShaderConsts.clear();
 769
 770   if ( GFXD3DX.isLoaded && !Con::getBoolVariable( "$shaders::forceLoadCSF", false ) )
 771   {
 772      if (  !mVertexFile.isEmpty() &&
 773            !_compileShader( mVertexFile, vertTarget, d3dXMacros, mVertexConstBufferLayoutF, mVertexConstBufferLayoutI, mSamplerDescriptions ) )
 774         return false;
 775
 776      if (  !mPixelFile.isEmpty() &&
 777            !_compileShader( mPixelFile, pixTarget, d3dXMacros, mPixelConstBufferLayoutF, mPixelConstBufferLayoutI, mSamplerDescriptions ) )
 778         return false;
 779   } 
 780   else 
 781   {
 782      if ( !_loadCompiledOutput( mVertexFile, vertTarget, mVertexConstBufferLayoutF, mVertexConstBufferLayoutI, mSamplerDescriptions ) )
 783      {
 784         if ( smLogErrors )
 785            Con::errorf( "GFXD3D9Shader::init - Unable to load precompiled vertex shader for '%s'.", 
 786               mVertexFile.getFullPath().c_str() );
 787
 788         return false;
 789      }
 790
 791      if ( !_loadCompiledOutput( mPixelFile, pixTarget, mPixelConstBufferLayoutF, mPixelConstBufferLayoutI, mSamplerDescriptions ) )
 792      {
 793         if ( smLogErrors )
 794            Con::errorf( "GFXD3D9Shader::init - Unable to load precompiled pixel shader for '%s'.", 
 795               mPixelFile.getFullPath().c_str() );
 796
 797         return false;
 798      }
 799   }
 800
 801   // Existing handles are resored to an uninitialized state.
 802   // Those that are found when parsing the layout parameters
 803   // will then be re-initialized.
 804   HandleMap::Iterator iter = mHandles.begin();
 805   for ( ; iter != mHandles.end(); iter++ )        
 806      (iter->value)->clear();      
 807
 808   _buildShaderConstantHandles(mVertexConstBufferLayoutF, true);
 809   _buildShaderConstantHandles(mVertexConstBufferLayoutI, true);
 810   _buildShaderConstantHandles(mPixelConstBufferLayoutF, false);
 811   _buildShaderConstantHandles(mPixelConstBufferLayoutI, false);
 812   _buildSamplerShaderConstantHandles( mSamplerDescriptions );
 813   _buildInstancingShaderConstantHandles();
 814
 815   // Notify any existing buffers that the buffer 
 816   // layouts have changed and they need to update.
 817   Vector<GFXShaderConstBuffer*>::iterator biter = mActiveBuffers.begin();
 818   for ( ; biter != mActiveBuffers.end(); biter++ )
 819      ((GFXD3D9ShaderConstBuffer*)(*biter))->onShaderReload( this );
 820
 821   return true;
 822}
 823
 824bool GFXD3D9Shader::_compileShader( const Torque::Path &filePath, 
 825                                    const String& target,                                  
 826                                    const D3DXMACRO *defines, 
 827                                    GenericConstBufferLayout* bufferLayoutF, 
 828                                    GenericConstBufferLayout* bufferLayoutI,
 829                                    Vector<GFXShaderConstDesc> &samplerDescriptions )
 830{
 831   PROFILE_SCOPE( GFXD3D9Shader_CompileShader );
 832
 833   HRESULT res = D3DERR_INVALIDCALL;
 834   LPD3DXBUFFER code = NULL;
 835   LPD3DXBUFFER errorBuff = NULL;
 836
 837#ifdef TORQUE_DEBUG
 838   U32 flags = D3DXSHADER_DEBUG;
 839#else
 840   U32 flags = 0;
 841#endif
 842
 843#ifdef TORQUE_OS_XENON
 844   flags |= D3DXSHADER_PREFER_FLOW_CONTROL;
 845#endif
 846
 847#ifdef D3DXSHADER_USE_LEGACY_D3DX9_31_DLL
 848   if( D3DX_SDK_VERSION >= 32 )
 849   {
 850      // will need to use old compiler for 1_1 shaders - check for pixel
 851      // or vertex shader with appropriate version.
 852      if ((target.compare("vs1", 3) == 0) || (target.compare("vs_1", 4) == 0))      
 853         flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;
 854
 855      if ((target.compare("ps1", 3) == 0) || (target.compare("ps_1", 4) == 0))
 856         flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;
 857   }
 858#endif
 859
 860#if !defined(TORQUE_OS_XENON) && (D3DX_SDK_VERSION <= 40)
 861#error This version of the DirectX SDK is too old. Please install a newer version of the DirectX SDK: http://msdn.microsoft.com/en-us/directx/default.aspx
 862#endif
 863
 864   ID3DXConstantTable* table = NULL;
 865
 866   static String sHLSLStr( "hlsl" );
 867   static String sOBJStr( "obj" );
 868
 869   // Is it an HLSL shader?
 870   if ( filePath.getExtension().equal(sHLSLStr, String::NoCase) )   
 871   {
 872      FrameAllocatorMarker fam;
 873      char *buffer = NULL;
 874
 875      // Set this so that the D3DXInclude::Open will have this 
 876      // information for relative paths.
 877      smD3DXInclude->setPath( filePath.getRootAndPath() );
 878
 879      FileStream s;
 880      if ( !s.open( filePath, Torque::FS::File::Read ) )
 881      {
 882         AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str()));
 883
 884         if ( smLogErrors )
 885            Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", 
 886               filePath.getFullPath().c_str() );
 887
 888         return false;
 889      }
 890
 891      // Convert the path which might have virtualized
 892      // mount paths to a real file system path.
 893      Torque::Path realPath;
 894      if ( !FS::GetFSPath( filePath, realPath ) )
 895         realPath = filePath;
 896
 897      // Add a #line pragma so that error and warning messages
 898      // returned by the HLSL compiler report the right file.
 899      String linePragma = String::ToString( "#line 1 \"%s\"\r\n", realPath.getFullPath().c_str() );
 900      U32 linePragmaLen = linePragma.length();
 901
 902      U32 bufSize = s.getStreamSize();
 903      buffer = (char *)fam.alloc( bufSize + linePragmaLen + 1 );
 904      dStrncpy( buffer, linePragma.c_str(), linePragmaLen );
 905      s.read( bufSize, buffer + linePragmaLen );
 906      buffer[bufSize+linePragmaLen] = 0;
 907
 908      res = GFXD3DX.D3DXCompileShader( buffer, bufSize + linePragmaLen, defines, smD3DXInclude, "main", 
 909         target, flags, &code, &errorBuff, &table );
 910   }
 911
 912   // Is it a precompiled obj shader?
 913   else if ( filePath.getExtension().equal( sOBJStr, String::NoCase ) )
 914   {     
 915      FileStream  s;
 916      if(!s.open(filePath, Torque::FS::File::Read))
 917      {
 918         AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str()));
 919
 920         if ( smLogErrors )
 921            Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", 
 922               filePath.getFullPath().c_str() );
 923
 924         return false;
 925      }
 926
 927      res = GFXD3DX.D3DXCreateBuffer(s.getStreamSize(), &code);
 928      AssertISV(res == D3D_OK, "Unable to create buffer!");
 929      s.read(s.getStreamSize(), code->GetBufferPointer());
 930      
 931      if (res == D3D_OK)
 932      {
 933         DWORD* data = (DWORD*) code->GetBufferPointer();
 934         res = GFXD3DX.D3DXGetShaderConstantTable(data, &table);
 935      }
 936   }
 937   else
 938   {
 939      if ( smLogErrors )
 940         Con::errorf( "GFXD3D9Shader::_compileShader - Unsupported shader file type '%s'.", 
 941            filePath.getFullPath().c_str() );
 942
 943      return false;
 944   }
 945
 946   if ( res != D3D_OK && smLogErrors )
 947      Con::errorf( "GFXD3D9Shader::_compileShader - Error compiling shader: %s: %s (%x)", 
 948         DXGetErrorStringA(res), DXGetErrorDescriptionA(res), res );
 949
 950   if ( errorBuff )
 951   {
 952      // remove \n at end of buffer
 953      U8 *buffPtr = (U8*) errorBuff->GetBufferPointer();
 954      U32 len = dStrlen( (const char*) buffPtr );
 955      buffPtr[len-1] = '\0';
 956
 957      if( res != D3D_OK )
 958      {
 959         if ( smLogErrors )
 960            Con::errorf( "   %s", (const char*) errorBuff->GetBufferPointer() );
 961      }
 962      else
 963      {
 964         if ( smLogWarnings )
 965            Con::warnf( "%s", (const char*) errorBuff->GetBufferPointer() );
 966      }
 967   }
 968   else if ( code == NULL && smLogErrors )
 969      Con::errorf( "GFXD3D9Shader::_compileShader - no compiled code produced; possibly missing file '%s'.", 
 970         filePath.getFullPath().c_str() );
 971
 972   // Create the proper shader if we have code
 973   if( code != NULL )
 974   {
 975      #ifndef TORQUE_SHIPPING
 976
 977         LPD3DXBUFFER disassem = NULL;
 978         D3DXDisassembleShader( (DWORD*)code->GetBufferPointer(), false, NULL, &disassem );
 979         mDissasembly = (const char*)disassem->GetBufferPointer();         
 980         SAFE_RELEASE( disassem );
 981
 982         if ( gDisassembleAllShaders )
 983         {
 984             String filename = filePath.getFullPath();
 985            filename.replace( ".hlsl", "_dis.txt" );
 986
 987            FileStream *fstream = FileStream::createAndOpen( filename, Torque::FS::File::Write );
 988            if ( fstream )
 989            {            
 990               fstream->write( mDissasembly );
 991               fstream->close();
 992               delete fstream;   
 993            }
 994         }
 995
 996      #endif
 997
 998      if (target.compare("ps_", 3) == 0)      
 999         res = mD3D9Device->CreatePixelShader( (DWORD*)code->GetBufferPointer(), &mPixShader );
1000      else
1001         res = mD3D9Device->CreateVertexShader( (DWORD*)code->GetBufferPointer(), &mVertShader );
1002
1003      if (res == S_OK)
1004         _getShaderConstants(table, bufferLayoutF, bufferLayoutI, samplerDescriptions);
1005
1006#ifdef TORQUE_ENABLE_CSF_GENERATION
1007
1008      // Ok, we've got a valid shader and constants, let's write them all out.
1009      if ( !_saveCompiledOutput(filePath, code, bufferLayoutF, bufferLayoutI) && smLogErrors )
1010         Con::errorf( "GFXD3D9Shader::_compileShader - Unable to save shader compile output for: %s", 
1011            filePath.getFullPath().c_str() );
1012
1013#endif
1014
1015      SAFE_RELEASE(table);
1016
1017      if ( res != S_OK && smLogErrors )
1018         Con::errorf( "GFXD3D9Shader::_compileShader - Unable to create shader for '%s'.", 
1019            filePath.getFullPath().c_str() );
1020   }
1021
1022   bool result = code != NULL && res == S_OK;
1023
1024   SAFE_RELEASE( code );
1025   SAFE_RELEASE( errorBuff );
1026
1027   return result;
1028}
1029
1030void GFXD3D9Shader::_getShaderConstants( ID3DXConstantTable *table, 
1031                                         GenericConstBufferLayout *bufferLayoutF, 
1032                                         GenericConstBufferLayout* bufferLayoutI,
1033                                         Vector<GFXShaderConstDesc> &samplerDescriptions )
1034{
1035   PROFILE_SCOPE( GFXD3D9Shader_GetShaderConstants );
1036
1037   AssertFatal(table, "NULL constant table not allowed, is this an assembly shader?");
1038
1039   D3DXCONSTANTTABLE_DESC tableDesc;
1040   D3D9Assert(table->GetDesc(&tableDesc), "Unable to get constant table info.");
1041
1042   for (U32 i = 0; i < tableDesc.Constants; i++)
1043   {
1044      D3DXHANDLE handle = table->GetConstant(0, i);
1045      const U32 descSize=16;
1046      D3DXCONSTANT_DESC constantDescArray[descSize];
1047      U32 size = descSize;
1048      if (table->GetConstantDesc(handle, constantDescArray, &size) == S_OK)
1049      {
1050         D3DXCONSTANT_DESC& constantDesc = constantDescArray[0];
1051         GFXShaderConstDesc desc;
1052                  
1053         desc.name = String(constantDesc.Name);
1054         // Prepend a "$" if it doesn't exist.  Just to make things consistent.
1055         if (desc.name.find("$") != 0)
1056            desc.name = String::ToString("$%s", desc.name.c_str());
1057         //Con::printf("name %s: , offset: %d, size: %d, constantDesc.Elements: %d", desc.name.c_str(), constantDesc.RegisterIndex, constantDesc.Bytes, constantDesc.Elements);
1058         desc.arraySize = constantDesc.Elements;         
1059                  
1060         GenericConstBufferLayout* bufferLayout = NULL;
1061         switch (constantDesc.RegisterSet)
1062         {
1063            case D3DXRS_INT4 :   
1064               {
1065                  bufferLayout = bufferLayoutI;
1066                  switch (constantDesc.Class)
1067                  {
1068                     case D3DXPC_SCALAR :
1069                        desc.constType = GFXSCT_Int;
1070                        break;
1071                     case D3DXPC_VECTOR :
1072                        {
1073                           switch (constantDesc.Columns)
1074                           {
1075                           case 1 :
1076                              desc.constType = GFXSCT_Int;
1077                              break;
1078                           case 2 :
1079                              desc.constType = GFXSCT_Int2;
1080                              break;
1081                           case 3 :
1082                              desc.constType = GFXSCT_Int3;
1083                              break;
1084                           case 4 :
1085                              desc.constType = GFXSCT_Int4;
1086                              break;                           
1087                           default:
1088                              AssertFatal(false, "Unknown int vector type!");
1089                              break;
1090                           }
1091                        }
1092                        break;
1093                  }
1094                  desc.constType = GFXSCT_Int4;
1095                  break;
1096               }
1097            case D3DXRS_FLOAT4 :
1098               {  
1099                  bufferLayout = bufferLayoutF;
1100                  switch (constantDesc.Class)
1101                  {
1102                  case D3DXPC_SCALAR:                     
1103                     desc.constType = GFXSCT_Float;
1104                     break;
1105                  case D3DXPC_VECTOR :               
1106                     {                     
1107                        switch (constantDesc.Columns)
1108                        {
1109                           case 1 :
1110                              desc.constType = GFXSCT_Float;
1111                              break;
1112                           case 2 :
1113                              desc.constType = GFXSCT_Float2;
1114                              break;
1115                           case 3 :
1116                              desc.constType = GFXSCT_Float3;
1117                              break;
1118                           case 4 :
1119                              desc.constType = GFXSCT_Float4;
1120                              break;                           
1121                           default:
1122                              AssertFatal(false, "Unknown float vector type!");
1123                              break;
1124                        }
1125                     }
1126                     break;
1127                  case D3DXPC_MATRIX_ROWS :
1128                  case D3DXPC_MATRIX_COLUMNS :                     
1129                     {
1130                        S32 fd, sd;
1131                        fd = constantDesc.RegisterCount / constantDesc.Elements;
1132                        sd = constantDesc.Class == D3DXPC_MATRIX_ROWS ? constantDesc.Columns : constantDesc.Rows;
1133
1134                        switch (fd)
1135                        {
1136                           case 2 :
1137                              AssertFatal(sd == 2, "non-square 2x? mats not supported");
1138                              desc.constType = GFXSCT_Float2x2;
1139                              break;
1140                           case 3 :
1141                              switch (sd)
1142                              {
1143                              case 3 :
1144                                 desc.constType = GFXSCT_Float3x3;
1145                                 break;
1146                              case 4 :
1147                                 desc.constType = GFXSCT_Float4x3;
1148                                 break;
1149                              default:
1150                                 AssertFatal(false, "Unsupported matrix size");
1151                                 break;
1152                              }
1153                              break;
1154                           case 4 :
1155                              switch (sd)
1156                              {
1157                              case 3:
1158                                 desc.constType = GFXSCT_Float3x4;
1159                                 break;
1160                              case 4:
1161                                 desc.constType = GFXSCT_Float4x4;
1162                                 break;
1163                              default:
1164                                 AssertFatal(false, "Unsupported matrix size");
1165                                 break;
1166                              }
1167                              break;
1168                        }
1169                     }
1170                     break;
1171                  case D3DXPC_OBJECT :
1172                  case D3DXPC_STRUCT :
1173                     bufferLayout = NULL;
1174                     break;
1175                  }
1176               }
1177               break;
1178            case D3DXRS_SAMPLER :
1179               {
1180                  AssertFatal( constantDesc.Elements == 1, "Sampler Arrays not yet supported!" );
1181
1182                  switch (constantDesc.Type)
1183                  {
1184                     case D3DXPT_SAMPLER :
1185                     case D3DXPT_SAMPLER1D :
1186                     case D3DXPT_SAMPLER2D :
1187                     case D3DXPT_SAMPLER3D :
1188                        // Hi-jack the desc's arraySize to store the registerIndex.
1189                        desc.constType = GFXSCT_Sampler;
1190                        desc.arraySize = constantDesc.RegisterIndex;
1191                        samplerDescriptions.push_back( desc );
1192                        mShaderConsts.push_back(desc);
1193                        break;
1194                     case D3DXPT_SAMPLERCUBE :
1195                        desc.constType = GFXSCT_SamplerCube;
1196                        desc.arraySize = constantDesc.RegisterIndex;
1197                        samplerDescriptions.push_back( desc );
1198                        mShaderConsts.push_back(desc);
1199                        break;
1200                  }
1201               }
1202               break;
1203            default:               
1204               AssertFatal(false, "Unknown shader constant class enum");               
1205               break;
1206         }         
1207         
1208         if (bufferLayout)
1209         {
1210            mShaderConsts.push_back(desc);
1211
1212            U32 alignBytes = getAlignmentValue(desc.constType);
1213            U32 paramSize = alignBytes * desc.arraySize;
1214            bufferLayout->addParameter(   desc.name, 
1215                                          desc.constType, 
1216                                          constantDesc.RegisterIndex * sizeof(Point4F), 
1217                                          paramSize, 
1218                                          desc.arraySize, 
1219                                          alignBytes );
1220         }
1221      }
1222      else
1223         AssertFatal(false, "Unable to get shader constant description! (may need more elements of constantDesc");
1224   }
1225}
1226
1227const U32 GFXD3D9Shader::smCompiledShaderTag = MakeFourCC('t','c','s','f');
1228
1229bool GFXD3D9Shader::_saveCompiledOutput( const Torque::Path &filePath, 
1230                                         LPD3DXBUFFER buffer, 
1231                                         GenericConstBufferLayout *bufferLayoutF, 
1232                                         GenericConstBufferLayout *bufferLayoutI,
1233                                         Vector<GFXShaderConstDesc> &samplerDescriptions )
1234{
1235   Torque::Path outputPath(filePath);
1236   outputPath.setExtension("csf");     // "C"ompiled "S"hader "F"ile (fancy!)
1237
1238   FileStream f;
1239   if (!f.open(outputPath, Torque::FS::File::Write))
1240      return false;
1241   if (!f.write(smCompiledShaderTag))
1242      return false;
1243   // We could reverse engineer the structure in the compiled output, but this
1244   // is a bit easier because we can just read it into the struct that we want.
1245   if (!bufferLayoutF->write(&f))
1246      return false;
1247   if (!bufferLayoutI->write(&f))
1248      return false;
1249   U32 bufferSize = buffer->GetBufferSize();
1250   if (!f.write(bufferSize))
1251      return false;
1252   if (!f.write(bufferSize, buffer->GetBufferPointer()))
1253      return false;
1254
1255   // Write out sampler descriptions.
1256
1257   f.write( samplerDescriptions.size() );   
1258
1259   for ( U32 i = 0; i < samplerDescriptions.size(); i++ )
1260   {
1261      f.write( samplerDescriptions[i].name );
1262      f.write( (U32)(samplerDescriptions[i].constType) );
1263      f.write( samplerDescriptions[i].arraySize );
1264   }
1265
1266   f.close();
1267
1268   return true;
1269}
1270
1271bool GFXD3D9Shader::_loadCompiledOutput( const Torque::Path &filePath, 
1272                                         const String &target, 
1273                                         GenericConstBufferLayout *bufferLayoutF, 
1274                                         GenericConstBufferLayout *bufferLayoutI,
1275                                         Vector<GFXShaderConstDesc> &samplerDescriptions )
1276{
1277   Torque::Path outputPath(filePath);
1278   outputPath.setExtension("csf");     // "C"ompiled "S"hader "F"ile (fancy!)
1279
1280   FileStream f;
1281   if (!f.open(outputPath, Torque::FS::File::Read))
1282      return false;
1283   U32 fileTag;
1284   if (!f.read(&fileTag))
1285      return false;
1286   if (fileTag != smCompiledShaderTag)
1287      return false;
1288   if (!bufferLayoutF->read(&f))
1289      return false;
1290   if (!bufferLayoutI->read(&f))
1291      return false;
1292   U32 bufferSize;
1293   if (!f.read(&bufferSize))
1294      return false;
1295   U32 waterMark = FrameAllocator::getWaterMark();
1296   DWORD* buffer = static_cast<DWORD*>(FrameAllocator::alloc(bufferSize));
1297   if (!f.read(bufferSize, buffer))
1298      return false;
1299
1300   // Read sampler descriptions.
1301
1302   U32 samplerCount;
1303   f.read( &samplerCount );   
1304
1305   for ( U32 i = 0; i < samplerCount; i++ )
1306   {
1307      GFXShaderConstDesc samplerDesc;
1308      f.read( &(samplerDesc.name) );
1309      f.read( (U32*)&(samplerDesc.constType) );
1310      f.read( &(samplerDesc.arraySize) );
1311
1312      samplerDescriptions.push_back( samplerDesc );
1313   }
1314
1315   f.close();
1316
1317   HRESULT res;
1318   if (target.compare("ps_", 3) == 0)      
1319      res = mD3D9Device->CreatePixelShader(buffer, &mPixShader );
1320   else
1321      res = mD3D9Device->CreateVertexShader(buffer, &mVertShader );
1322   AssertFatal(SUCCEEDED(res), "Unable to load shader!");
1323
1324   FrameAllocator::setWaterMark(waterMark);
1325   return SUCCEEDED(res);
1326}
1327
1328void GFXD3D9Shader::_buildShaderConstantHandles(GenericConstBufferLayout* layout, bool vertexConst)
1329{                     
1330   for (U32 i = 0; i < layout->getParameterCount(); i++)
1331   {
1332      GenericConstBufferLayout::ParamDesc pd;
1333      layout->getDesc(i, pd);
1334
1335      GFXD3D9ShaderConstHandle* handle;
1336      HandleMap::Iterator j = mHandles.find(pd.name);
1337
1338      if (j != mHandles.end())
1339      {
1340         handle = j->value;         
1341         handle->mShader = this;
1342         handle->setValid( true );
1343      } 
1344      else
1345      {
1346         handle = new GFXD3D9ShaderConstHandle();
1347         handle->mShader = this;
1348         mHandles[pd.name] = handle;
1349         handle->setValid( true );
1350      }
1351
1352      if ( vertexConst )
1353      {
1354         handle->mVertexConstant = true;
1355         handle->mVertexHandle = pd;
1356      } 
1357      else 
1358      {
1359         handle->mPixelConstant = true;
1360         handle->mPixelHandle = pd;
1361      }
1362   }
1363}
1364
1365void GFXD3D9Shader::_buildSamplerShaderConstantHandles( Vector<GFXShaderConstDesc> &samplerDescriptions )
1366{                     
1367   Vector<GFXShaderConstDesc>::iterator iter = samplerDescriptions.begin();
1368   for ( ; iter != samplerDescriptions.end(); iter++ )
1369   {
1370      const GFXShaderConstDesc &desc = *iter;
1371
1372      AssertFatal(   desc.constType == GFXSCT_Sampler || 
1373                     desc.constType == GFXSCT_SamplerCube, 
1374                     "GFXD3D9Shader::_buildSamplerShaderConstantHandles - Invalid samplerDescription type!" );
1375
1376      GFXD3D9ShaderConstHandle *handle;
1377      HandleMap::Iterator j = mHandles.find(desc.name);
1378
1379      if ( j != mHandles.end() )
1380         handle = j->value;
1381      else
1382      {
1383         handle = new GFXD3D9ShaderConstHandle();
1384         mHandles[desc.name] = handle;         
1385      }
1386
1387      handle->mShader = this;         
1388      handle->setValid( true );         
1389      handle->mPixelConstant = true;
1390      handle->mPixelHandle.name = desc.name;
1391      handle->mPixelHandle.constType = desc.constType;
1392      handle->mPixelHandle.offset = desc.arraySize;         
1393   }
1394}
1395
1396void GFXD3D9Shader::_buildInstancingShaderConstantHandles()
1397{
1398   // If we have no instancing than just return
1399   if (!mInstancingFormat)
1400      return;
1401
1402   U32 offset = 0;
1403
1404   for ( U32 i=0; i < mInstancingFormat->getElementCount(); i++ )
1405   {
1406      const GFXVertexElement &element = mInstancingFormat->getElement( i );
1407      
1408      String constName = String::ToString( "$%s", element.getSemantic().c_str() );
1409
1410      GFXD3D9ShaderConstHandle *handle;
1411      HandleMap::Iterator j = mHandles.find( constName );
1412
1413      if ( j != mHandles.end() )
1414         handle = j->value; 
1415      else
1416      {
1417         handle = new GFXD3D9ShaderConstHandle();
1418         mHandles[ constName ] = handle;         
1419      }
1420
1421      handle->mShader = this;
1422      handle->setValid( true );         
1423      handle->mInstancingConstant = true;
1424
1425      // We shouldn't have an instancing constant that is also 
1426      // a vertex or pixel constant!  This means the shader features
1427      // are confused as to what is instanced.
1428      //
1429      AssertFatal(   !handle->mVertexConstant &&
1430                     !handle->mPixelConstant,
1431                     "GFXD3D9Shader::_buildInstancingShaderConstantHandles - Bad instanced constant!" );
1432
1433      // HACK:  The GFXD3D9ShaderConstHandle will check mVertexConstant then
1434      // fall back to reading the mPixelHandle values.  We depend on this here
1435      // and store the data we need in the mPixelHandle constant although its
1436      // not a pixel shader constant.
1437      //
1438      handle->mPixelHandle.name = constName;
1439      handle->mPixelHandle.offset = offset;
1440
1441      // If this is a matrix we will have 2 or 3 more of these
1442      // semantics with the same name after it.
1443      for ( ; i < mInstancingFormat->getElementCount(); i++ )
1444      {
1445         const GFXVertexElement &nextElement = mInstancingFormat->getElement( i );
1446         if ( nextElement.getSemantic() != element.getSemantic() )
1447         {
1448            i--;
1449            break;
1450         }
1451         offset += nextElement.getSizeInBytes();
1452      }
1453   }
1454}
1455
1456GFXShaderConstBufferRef GFXD3D9Shader::allocConstBuffer()
1457{
1458   if (mVertexConstBufferLayoutF && mPixelConstBufferLayoutF)
1459   {
1460      GFXD3D9ShaderConstBuffer* buffer = new GFXD3D9ShaderConstBuffer(this, mVertexConstBufferLayoutF, mVertexConstBufferLayoutI, mPixelConstBufferLayoutF, mPixelConstBufferLayoutI);
1461      mActiveBuffers.push_back( buffer );
1462      buffer->registerResourceWithDevice(getOwningDevice());
1463      return buffer;
1464   } else {
1465      return NULL;
1466   }
1467}
1468
1469/// Returns a shader constant handle for name
1470GFXShaderConstHandle* GFXD3D9Shader::getShaderConstHandle(const String& name)
1471{
1472   HandleMap::Iterator i = mHandles.find(name);   
1473   if ( i != mHandles.end() )
1474   {
1475      return i->value;
1476   } 
1477   else 
1478   {     
1479      GFXD3D9ShaderConstHandle *handle = new GFXD3D9ShaderConstHandle();
1480      handle->setValid( false );
1481      handle->mShader = this;
1482      mHandles[name] = handle;
1483
1484      return handle;      
1485   }      
1486}
1487
1488/// Returns a shader constant handle for name, if the variable doesn't exist NULL is returned.
1489GFXShaderConstHandle* GFXD3D9Shader::findShaderConstHandle(const String& name)
1490{
1491   HandleMap::Iterator i = mHandles.find(name);   
1492   if ( i != mHandles.end() )
1493   {
1494      return i->value;
1495   } 
1496   else 
1497   {     
1498      return NULL;
1499   }      
1500}
1501
1502const Vector<GFXShaderConstDesc>& GFXD3D9Shader::getShaderConstDesc() const
1503{
1504   return mShaderConsts;
1505}
1506
1507U32 GFXD3D9Shader::getAlignmentValue(const GFXShaderConstType constType) const
1508{   
1509   const U32 mRowSizeF = 16;
1510   const U32 mRowSizeI = 16;
1511
1512   switch (constType)
1513   {
1514      case GFXSCT_Float :
1515      case GFXSCT_Float2 :
1516      case GFXSCT_Float3 : 
1517      case GFXSCT_Float4 :
1518         return mRowSizeF;
1519         break;
1520         // Matrices
1521      case GFXSCT_Float2x2 :
1522         return mRowSizeF * 2;
1523         break;
1524      case GFXSCT_Float3x3 : 
1525         return mRowSizeF * 3;
1526         break;
1527      case GFXSCT_Float3x4 : 
1528         return mRowSizeF * 4;
1529         break;
1530      case GFXSCT_Float4x4 :
1531         return mRowSizeF * 4;
1532         break;   
1533      case GFXSCT_Float4x3 : 
1534         return mRowSizeF * 3;
1535         break;
1536      //// Scalar
1537      case GFXSCT_Int :
1538      case GFXSCT_Int2 :
1539      case GFXSCT_Int3 : 
1540      case GFXSCT_Int4 :
1541         return mRowSizeI;
1542         break;
1543      default:
1544         AssertFatal(false, "Unsupported type!");
1545         return 0;
1546         break;
1547   }
1548}
1549
1550void GFXD3D9Shader::zombify()
1551{
1552   // Shaders don't need zombification
1553}
1554
1555void GFXD3D9Shader::resurrect()
1556{
1557   // Shaders are never zombies, and therefore don't have to be brought back.
1558}
1559