Torque3D Documentation / _generateds / gfxGLDevice.cpp

gfxGLDevice.cpp

Engine/source/gfx/gl/gfxGLDevice.cpp

More...

Classes:

Namespaces:

namespace

Public Functions

DefineEngineFunction(cycleResources , void , () , "" )
glAmdDebugCallback(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar * message, GLvoid * userParam)
glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * message, const void * userParam)

Detailed Description

Public Variables

GFXGLRegisterDevice pGLRegisterDevice 

Public Functions

DefineEngineFunction(cycleResources , void , () , "" )

glAmdDebugCallback(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar * message, GLvoid * userParam)

glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * message, const void * userParam)

loadGLCore()

loadGLExtensions(void * context)

   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#include "gfx/gl/gfxGLDevice.h"
  26
  27#include "gfxGLTextureArray.h"
  28#include "platform/platformGL.h"
  29
  30#include "gfx/gfxCubemap.h"
  31#include "gfx/gl/screenshotGL.h"
  32#include "gfx/gfxDrawUtil.h"
  33
  34#include "gfx/gl/gfxGLEnumTranslate.h"
  35#include "gfx/gl/gfxGLVertexBuffer.h"
  36#include "gfx/gl/gfxGLPrimitiveBuffer.h"
  37#include "gfx/gl/gfxGLTextureTarget.h"
  38#include "gfx/gl/gfxGLTextureManager.h"
  39#include "gfx/gl/gfxGLTextureObject.h"
  40#include "gfx/gl/gfxGLCubemap.h"
  41#include "gfx/gl/gfxGLCardProfiler.h"
  42#include "gfx/gl/gfxGLWindowTarget.h"
  43#include "platform/platformDlibrary.h"
  44#include "gfx/gl/gfxGLShader.h"
  45#include "gfx/primBuilder.h"
  46#include "console/console.h"
  47#include "gfx/gl/gfxGLOcclusionQuery.h"
  48#include "materials/shaderData.h"
  49#include "gfx/gl/gfxGLStateCache.h"
  50#include "gfx/gl/gfxGLVertexAttribLocation.h"
  51#include "gfx/gl/gfxGLVertexDecl.h"
  52#include "shaderGen/shaderGen.h"
  53#include "gfxGLUtils.h"
  54
  55GFXAdapter::CreateDeviceInstanceDelegate GFXGLDevice::mCreateDeviceInstance(GFXGLDevice::createInstance); 
  56
  57GFXDevice *GFXGLDevice::createInstance( U32 adapterIndex )
  58{
  59   return new GFXGLDevice(adapterIndex);
  60}
  61
  62namespace GL
  63{
  64   extern void gglPerformBinds();
  65   extern void gglPerformExtensionBinds(void *context);
  66}
  67
  68void loadGLCore()
  69{
  70   static bool coreLoaded = false; // Guess what this is for.
  71   if(coreLoaded)
  72      return;
  73   coreLoaded = true;
  74   
  75   // Make sure we've got our GL bindings.
  76   GL::gglPerformBinds();
  77}
  78
  79void loadGLExtensions(void *context)
  80{
  81   static bool extensionsLoaded = false;
  82   if(extensionsLoaded)
  83      return;
  84   extensionsLoaded = true;
  85   
  86   GL::gglPerformExtensionBinds(context);
  87}
  88
  89void STDCALL glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, 
  90   const GLchar *message, const void *userParam)
  91{
  92    // JTH [11/24/2016]: This is a temporary fix so that we do not get spammed for redundant fbo changes.
  93    // This only happens on Intel cards. This should be looked into sometime in the near future.
  94    if (dStrStartsWith(message, "API_ID_REDUNDANT_FBO"))
  95        return;
  96    if (severity == GL_DEBUG_SEVERITY_HIGH)
  97        Con::errorf("OPENGL: %s", message);
  98    else if (severity == GL_DEBUG_SEVERITY_MEDIUM)
  99        Con::warnf("OPENGL: %s", message);
 100    else if (severity == GL_DEBUG_SEVERITY_LOW)
 101        Con::printf("OPENGL: %s", message);
 102}
 103
 104void STDCALL glAmdDebugCallback(GLuint id, GLenum category, GLenum severity, GLsizei length,
 105    const GLchar* message, GLvoid* userParam)
 106{
 107    if (severity == GL_DEBUG_SEVERITY_HIGH)
 108        Con::errorf("AMDOPENGL: %s", message);
 109    else if (severity == GL_DEBUG_SEVERITY_MEDIUM)
 110        Con::warnf("AMDOPENGL: %s", message);
 111    else if (severity == GL_DEBUG_SEVERITY_LOW)
 112        Con::printf("AMDOPENGL: %s", message);
 113}
 114
 115void GFXGLDevice::initGLState()
 116{  
 117   // We don't currently need to sync device state with a known good place because we are
 118   // going to set everything in GFXGLStateBlock, but if we change our GFXGLStateBlock strategy, this may
 119   // need to happen.
 120   
 121   // Deal with the card profiler here when we know we have a valid context.
 122   mCardProfiler = new GFXGLCardProfiler();
 123   mCardProfiler->init(); 
 124   glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint*)&mMaxShaderTextures);
 125   // JTH: Needs removed, ffp
 126   //glGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&mMaxFFTextures);
 127   glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, (GLint*)&mMaxTRColors);
 128   mMaxTRColors = getMin( mMaxTRColors, (U32)(GFXTextureTarget::MaxRenderSlotId-1) );
 129   
 130   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 131   
 132   // [JTH 5/6/2016] GLSL 1.50 is really SM 4.0
 133   // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run.   
 134   mPixelShaderVersion = 3.0;
 135
 136   // Set capability extensions.
 137   mCapabilities.anisotropicFiltering = mCardProfiler->queryProfile("GL_EXT_texture_filter_anisotropic");
 138   mCapabilities.bufferStorage = mCardProfiler->queryProfile("GL_ARB_buffer_storage");
 139   mCapabilities.textureStorage = mCardProfiler->queryProfile("GL_ARB_texture_storage");
 140   mCapabilities.copyImage = mCardProfiler->queryProfile("GL_ARB_copy_image");
 141   mCapabilities.vertexAttributeBinding = mCardProfiler->queryProfile("GL_ARB_vertex_attrib_binding");
 142   mCapabilities.khrDebug = mCardProfiler->queryProfile("GL_KHR_debug");
 143   mCapabilities.extDebugMarker = mCardProfiler->queryProfile("GL_EXT_debug_marker");
 144
 145   String vendorStr = (const char*)glGetString( GL_VENDOR );
 146   if( vendorStr.find("NVIDIA", 0, String::NoCase | String::Left) != String::NPos)
 147      mUseGlMap = false;
 148   
 149   // Workaround for all Mac's, has a problem using glMap* with volatile buffers
 150#ifdef TORQUE_OS_MAC
 151   mUseGlMap = false;
 152#endif
 153
 154#if TORQUE_DEBUG
 155   if( gglHasExtension(ARB_debug_output) )
 156   {
 157      glEnable(GL_DEBUG_OUTPUT);
 158      glDebugMessageCallbackARB(glDebugCallback, NULL);
 159      glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
 160      GLuint unusedIds = 0;
 161      glDebugMessageControlARB(GL_DONT_CARE,
 162            GL_DONT_CARE,
 163            GL_DONT_CARE,
 164            0,
 165            &unusedIds,
 166            GL_TRUE);
 167   }
 168   else if(gglHasExtension(AMD_debug_output))
 169   {
 170      glEnable(GL_DEBUG_OUTPUT);
 171      glDebugMessageCallbackAMD(glAmdDebugCallback, NULL);      
 172      //glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
 173      GLuint unusedIds = 0;
 174      glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0,&unusedIds, GL_TRUE);
 175   }
 176#endif
 177
 178   PlatformGL::setVSync(smDisableVSync ? 0 : 1);
 179
 180   //install vsync callback
 181   Con::NotifyDelegate clbk(this, &GFXGLDevice::vsyncCallback);
 182   Con::addVariableNotify("$pref::Video::disableVerticalSync", clbk);
 183
 184   //OpenGL 3 need a binded VAO for render
 185   GLuint vao;
 186   glGenVertexArrays(1, &vao);
 187   glBindVertexArray(vao);
 188
 189   //enable sRGB
 190   glEnable(GL_FRAMEBUFFER_SRGB);
 191}
 192
 193void GFXGLDevice::vsyncCallback()
 194{
 195   PlatformGL::setVSync(smDisableVSync ? 0 : 1);
 196}
 197
 198GFXGLDevice::GFXGLDevice(U32 adapterIndex) :
 199   mAdapterIndex(adapterIndex),
 200   mNeedUpdateVertexAttrib(false),
 201   mCurrentPB(NULL),
 202   mDrawInstancesCount(0),
 203   mCurrentShader( NULL ),
 204   m_mCurrentWorld(true),
 205   m_mCurrentView(true),
 206   mContext(NULL),
 207   mPixelFormat(NULL),
 208   mPixelShaderVersion(0.0f),
 209   mMaxShaderTextures(2),
 210   mMaxFFTextures(2),
 211   mMaxTRColors(1),
 212   mClip(0, 0, 0, 0),
 213   mWindowRT(NULL),
 214   mUseGlMap(true)
 215{
 216   for(int i = 0; i < VERTEX_STREAM_COUNT; ++i)
 217   {
 218      mCurrentVB[i] = NULL;
 219      mCurrentVB_Divisor[i] = 0;
 220   }
 221
 222   // Initiailize capabilities to false.
 223   memset(&mCapabilities, 0, sizeof(GLCapabilities));
 224
 225   loadGLCore();
 226
 227   GFXGLEnumTranslate::init();
 228
 229   GFXVertexColor::setSwizzle( &Swizzles::rgba );
 230
 231   // OpenGL have native RGB, no need swizzle
 232   mDeviceSwizzle32 = &Swizzles::rgba;
 233   mDeviceSwizzle24 = &Swizzles::rgb;
 234
 235   mTextureManager = new GFXGLTextureManager();
 236   gScreenShot = new ScreenShotGL();
 237
 238   for(U32 i = 0; i < GFX_TEXTURE_STAGE_COUNT; i++)
 239      mActiveTextureType[i] = GL_ZERO;
 240
 241   mNumVertexStream = 2;
 242   mSupportsAnisotropic = false;
 243
 244   for(int i = 0; i < GS_COUNT; ++i)
 245      mModelViewProjSC[i] = NULL;
 246
 247   mOpenglStateCache = new GFXGLStateCache;
 248}
 249
 250GFXGLDevice::~GFXGLDevice()
 251{
 252   mCurrentStateBlock = NULL;
 253
 254   for(int i = 0; i < VERTEX_STREAM_COUNT; ++i)      
 255      mCurrentVB[i] = NULL;
 256   mCurrentPB = NULL;
 257   
 258   for(U32 i = 0; i < mVolatileVBs.size(); i++)
 259      mVolatileVBs[i] = NULL;
 260   for(U32 i = 0; i < mVolatilePBs.size(); i++)
 261      mVolatilePBs[i] = NULL;
 262
 263   // Clear out our current texture references
 264   for (U32 i = 0; i < GFX_TEXTURE_STAGE_COUNT; i++)
 265   {
 266      mCurrentTexture[i] = NULL;
 267      mNewTexture[i] = NULL;
 268      mCurrentCubemap[i] = NULL;
 269      mNewCubemap[i] = NULL;
 270   }
 271
 272   mRTStack.clear();
 273   mCurrentRT = NULL;
 274
 275   if( mTextureManager )
 276   {
 277      mTextureManager->zombify();
 278      mTextureManager->kill();
 279   }
 280
 281   GFXResource* walk = mResourceListHead;
 282   while(walk)
 283   {
 284      walk->zombify();
 285      walk = walk->getNextResource();
 286   }
 287      
 288   if( mCardProfiler )
 289      SAFE_DELETE( mCardProfiler );
 290
 291   SAFE_DELETE( gScreenShot );
 292
 293   SAFE_DELETE( mOpenglStateCache );
 294}
 295
 296void GFXGLDevice::zombify()
 297{
 298   mTextureManager->zombify();
 299
 300   for(int i = 0; i < VERTEX_STREAM_COUNT; ++i)   
 301      if(mCurrentVB[i])
 302         mCurrentVB[i]->finish();
 303   if(mCurrentPB)
 304         mCurrentPB->finish();
 305   
 306   //mVolatileVBs.clear();
 307   //mVolatilePBs.clear();
 308   GFXResource* walk = mResourceListHead;
 309   while(walk)
 310   {
 311      walk->zombify();
 312      walk = walk->getNextResource();
 313   }
 314}
 315
 316void GFXGLDevice::resurrect()
 317{
 318   GFXResource* walk = mResourceListHead;
 319   while(walk)
 320   {
 321      walk->resurrect();
 322      walk = walk->getNextResource();
 323   }
 324   for(int i = 0; i < VERTEX_STREAM_COUNT; ++i)   
 325      if(mCurrentVB[i])
 326         mCurrentVB[i]->prepare();
 327   if(mCurrentPB)
 328      mCurrentPB->prepare();
 329   
 330   mTextureManager->resurrect();
 331}
 332
 333GFXVertexBuffer* GFXGLDevice::findVolatileVBO(U32 numVerts, const GFXVertexFormat *vertexFormat, U32 vertSize)
 334{
 335   PROFILE_SCOPE(GFXGLDevice_findVBPool);
 336   for(U32 i = 0; i < mVolatileVBs.size(); i++)
 337      if (  mVolatileVBs[i]->mNumVerts >= numVerts &&
 338            mVolatileVBs[i]->mVertexFormat.isEqual( *vertexFormat ) &&
 339            mVolatileVBs[i]->mVertexSize == vertSize &&
 340            mVolatileVBs[i]->getRefCount() == 1 )
 341         return mVolatileVBs[i];
 342
 343   // No existing VB, so create one
 344   PROFILE_SCOPE(GFXGLDevice_createVBPool);
 345   StrongRefPtr<GFXGLVertexBuffer> buf(new GFXGLVertexBuffer(GFX, numVerts, vertexFormat, vertSize, GFXBufferTypeVolatile));
 346   buf->registerResourceWithDevice(this);
 347   mVolatileVBs.push_back(buf);
 348   return buf.getPointer();
 349}
 350
 351GFXPrimitiveBuffer* GFXGLDevice::findVolatilePBO(U32 numIndices, U32 numPrimitives)
 352{
 353   for(U32 i = 0; i < mVolatilePBs.size(); i++)
 354      if((mVolatilePBs[i]->mIndexCount >= numIndices) && (mVolatilePBs[i]->getRefCount() == 1))
 355         return mVolatilePBs[i];
 356   
 357   // No existing PB, so create one
 358   StrongRefPtr<GFXGLPrimitiveBuffer> buf(new GFXGLPrimitiveBuffer(GFX, numIndices, numPrimitives, GFXBufferTypeVolatile));
 359   buf->registerResourceWithDevice(this);
 360   mVolatilePBs.push_back(buf);
 361   return buf.getPointer();
 362}
 363
 364GFXVertexBuffer *GFXGLDevice::allocVertexBuffer(   U32 numVerts, 
 365                                                   const GFXVertexFormat *vertexFormat, 
 366                                                   U32 vertSize, 
 367                                                   GFXBufferType bufferType,
 368                                                   void* data )  
 369{
 370   PROFILE_SCOPE(GFXGLDevice_allocVertexBuffer);
 371   if(bufferType == GFXBufferTypeVolatile)
 372      return findVolatileVBO(numVerts, vertexFormat, vertSize);
 373         
 374   GFXGLVertexBuffer* buf = new GFXGLVertexBuffer( GFX, numVerts, vertexFormat, vertSize, bufferType );
 375   buf->registerResourceWithDevice(this);   
 376
 377   if(data)
 378   {
 379      void* dest;
 380      buf->lock(0, numVerts, &dest);
 381      dMemcpy(dest, data, vertSize * numVerts);
 382      buf->unlock();
 383   }
 384
 385   return buf;
 386}
 387
 388GFXPrimitiveBuffer *GFXGLDevice::allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType, void* data ) 
 389{
 390   GFXPrimitiveBuffer* buf;
 391   
 392   if(bufferType == GFXBufferTypeVolatile)
 393   {
 394      buf = findVolatilePBO(numIndices, numPrimitives);
 395   }
 396   else
 397   {
 398      buf = new GFXGLPrimitiveBuffer(GFX, numIndices, numPrimitives, bufferType);
 399      buf->registerResourceWithDevice(this);
 400   }
 401   
 402   if(data)
 403   {
 404      void* dest;
 405      buf->lock(0, numIndices, &dest);
 406      dMemcpy(dest, data, sizeof(U16) * numIndices);
 407      buf->unlock();
 408   }
 409   return buf;
 410}
 411
 412void GFXGLDevice::setVertexStream( U32 stream, GFXVertexBuffer *buffer )
 413{
 414   AssertFatal(stream <= 1, "GFXGLDevice::setVertexStream only support 2 stream (0: data, 1: instancing)");
 415
 416   //if(mCurrentVB[stream] != buffer)
 417   {
 418      // Reset the state the old VB required, then set the state the new VB requires.
 419      if( mCurrentVB[stream] )
 420      {     
 421         mCurrentVB[stream]->finish();
 422      }
 423
 424      mCurrentVB[stream] = static_cast<GFXGLVertexBuffer*>( buffer );
 425
 426      mNeedUpdateVertexAttrib = true;
 427   }
 428}
 429
 430void GFXGLDevice::setVertexStreamFrequency( U32 stream, U32 frequency )
 431{
 432   if( stream == 0 )
 433   {
 434      mCurrentVB_Divisor[stream] = 0; // non instanced, is vertex buffer
 435      mDrawInstancesCount = frequency; // instances count
 436   }
 437   else
 438   {
 439      AssertFatal(frequency <= 1, "GFXGLDevice::setVertexStreamFrequency only support 0/1 for this stream" );
 440      if( stream == 1 && frequency == 1 )
 441         mCurrentVB_Divisor[stream] = 1; // instances data need a frequency of 1
 442      else
 443         mCurrentVB_Divisor[stream] = 0;
 444   }
 445
 446   mNeedUpdateVertexAttrib = true;
 447}
 448
 449GFXCubemap* GFXGLDevice::createCubemap()
 450{ 
 451   GFXGLCubemap* cube = new GFXGLCubemap();
 452   cube->registerResourceWithDevice(this);
 453   return cube; 
 454};
 455
 456GFXCubemapArray *GFXGLDevice::createCubemapArray()
 457{
 458   GFXGLCubemapArray* cubeArray = new GFXGLCubemapArray();
 459   cubeArray->registerResourceWithDevice(this);
 460   return cubeArray;
 461}
 462
 463GFXTextureArray* GFXGLDevice::createTextureArray()
 464{
 465   GFXGLTextureArray* textureArray = new GFXGLTextureArray();
 466   textureArray->registerResourceWithDevice(this);
 467   return textureArray;
 468}
 469
 470void GFXGLDevice::endSceneInternal() 
 471{
 472   // nothing to do for opengl
 473   mCanCurrentlyRender = false;
 474}
 475
 476void GFXGLDevice::copyResource(GFXTextureObject* pDst, GFXCubemap* pSrc, const U32 face)
 477{
 478   AssertFatal(pDst, "GFXGLDevice::copyResource: Destination texture is null");
 479   AssertFatal(pSrc, "GFXGLDevice::copyResource: Source cubemap is null");
 480
 481   GFXGLTextureObject* gGLDst = static_cast<GFXGLTextureObject*>(pDst);
 482   GFXGLCubemap* pGLSrc = static_cast<GFXGLCubemap*>(pSrc);
 483
 484   const GFXFormat format = pGLSrc->getFormat();
 485   const bool isCompressed = ImageUtil::isCompressedFormat(format);
 486   const U32 mipLevels = pGLSrc->getMipMapLevels();
 487   const U32 texSize = pGLSrc->getSize();
 488
 489   //set up pbo if we don't have copyImage support
 490   if (!GFXGL->mCapabilities.copyImage)
 491   {
 492      const GLuint pbo = gGLDst->getBuffer();
 493      glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
 494      //allocate data
 495      glBufferData(GL_PIXEL_PACK_BUFFER, texSize * texSize * GFXFormat_getByteSize(format), NULL, GL_STREAM_COPY);
 496   }
 497
 498   for (U32 mip = 0; mip < mipLevels; mip++)
 499   {
 500      const U32 mipSize =  texSize >> mip;
 501      if (GFXGL->mCapabilities.copyImage)
 502      {
 503         glCopyImageSubData(pGLSrc->mCubemap, GL_TEXTURE_CUBE_MAP, mip, 0, 0, face, gGLDst->getHandle(), GL_TEXTURE_2D, mip, 0, 0, 0, mipSize, mipSize, 1);
 504      }
 505      else
 506      {
 507         //pbo id
 508         const GLuint pbo = gGLDst->getBuffer();
 509
 510         //copy source texture data to pbo
 511         glBindTexture(GL_TEXTURE_CUBE_MAP, pGLSrc->mCubemap);
 512         glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
 513
 514         if (isCompressed)
 515            glGetCompressedTexImage(GFXGLFaceType[face], mip, NULL);
 516         else
 517            glGetTexImage(GFXGLFaceType[face], mip, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
 518
 519         glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
 520         glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
 521
 522         //copy data from pbo to destination
 523         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
 524         glBindTexture(gGLDst->getBinding(), gGLDst->getHandle());
 525
 526         if (isCompressed)
 527         {
 528            const U32 mipDataSize = getCompressedSurfaceSize(format, pGLSrc->getSize(), pGLSrc->getSize(), 0);
 529            glCompressedTexSubImage2D(gGLDst->getBinding(), mip, 0, 0, mipSize, mipSize, GFXGLTextureFormat[format], mipDataSize, NULL);
 530         }
 531         else
 532         {
 533            glTexSubImage2D(gGLDst->getBinding(), mip, 0, 0, mipSize, mipSize, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
 534         }
 535
 536         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
 537         glBindTexture(gGLDst->getBinding(), 0);
 538      }
 539   }
 540}
 541
 542void GFXGLDevice::clear(U32 flags, const LinearColorF& color, F32 z, U32 stencil)
 543{
 544   // Make sure we have flushed our render target state.
 545   _updateRenderTargets();
 546   
 547   bool writeAllColors = true;
 548   bool zwrite = true;   
 549   bool writeAllStencil = true;
 550   const GFXStateBlockDesc *desc = NULL;
 551   if (mCurrentGLStateBlock)
 552   {
 553      desc = &mCurrentGLStateBlock->getDesc();
 554      zwrite = desc->zWriteEnable;
 555      writeAllColors = desc->colorWriteRed && desc->colorWriteGreen && desc->colorWriteBlue && desc->colorWriteAlpha;
 556      writeAllStencil = desc->stencilWriteMask == 0xFFFFFFFF;
 557   }
 558   
 559   glColorMask(true, true, true, true);
 560   glDepthMask(true);
 561   glStencilMask(0xFFFFFFFF);
 562   glClearColor(color.red, color.green, color.blue, color.alpha);
 563   glClearDepth(z);
 564   glClearStencil(stencil);
 565
 566   GLbitfield clearflags = 0;
 567   clearflags |= (flags & GFXClearTarget)   ? GL_COLOR_BUFFER_BIT : 0;
 568   clearflags |= (flags & GFXClearZBuffer)  ? GL_DEPTH_BUFFER_BIT : 0;
 569   clearflags |= (flags & GFXClearStencil)  ? GL_STENCIL_BUFFER_BIT : 0;
 570
 571   glClear(clearflags);
 572
 573   if(!writeAllColors)
 574      glColorMask(desc->colorWriteRed, desc->colorWriteGreen, desc->colorWriteBlue, desc->colorWriteAlpha);
 575   
 576   if(!zwrite)
 577      glDepthMask(false);
 578
 579   if(!writeAllStencil)
 580      glStencilMask(desc->stencilWriteMask);
 581}
 582
 583void GFXGLDevice::clearColorAttachment(const U32 attachment, const LinearColorF& color)
 584{
 585   const GLfloat clearColor[4] = { color.red, color.green, color.blue, color.alpha };
 586   glClearBufferfv(GL_COLOR, attachment, clearColor);
 587}
 588
 589// Given a primitive type and a number of primitives, return the number of indexes/vertexes used.
 590inline GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32 primitiveCount)
 591{
 592   switch (primType)
 593   {
 594      case GFXPointList :
 595         return primitiveCount;
 596         break;
 597      case GFXLineList :
 598         return primitiveCount * 2;
 599         break;
 600      case GFXLineStrip :
 601         return primitiveCount + 1;
 602         break;
 603      case GFXTriangleList :
 604         return primitiveCount * 3;
 605         break;
 606      case GFXTriangleStrip :
 607         return 2 + primitiveCount;
 608         break;
 609      default:
 610         AssertFatal(false, "GFXGLDevice::primCountToIndexCount - unrecognized prim type");
 611         break;
 612   }
 613   
 614   return 0;
 615}
 616
 617GFXVertexDecl* GFXGLDevice::allocVertexDecl( const GFXVertexFormat *vertexFormat ) 
 618{
 619   PROFILE_SCOPE(GFXGLDevice_allocVertexDecl);
 620   typedef Map<void*, GFXGLVertexDecl> GFXGLVertexDeclMap;
 621   static GFXGLVertexDeclMap declMap;   
 622   GFXGLVertexDeclMap::Iterator itr = declMap.find( (void*)vertexFormat->getDescription().c_str() ); // description string are interned, safe to use c_str()
 623   if(itr != declMap.end())
 624      return &itr->value;
 625
 626   GFXGLVertexDecl &decl = declMap[(void*)vertexFormat->getDescription().c_str()];   
 627   decl.init(vertexFormat);
 628   return &decl;
 629}
 630
 631void GFXGLDevice::setVertexDecl( const GFXVertexDecl *decl )
 632{
 633   static_cast<const GFXGLVertexDecl*>(decl)->prepareVertexFormat();
 634}
 635
 636inline void GFXGLDevice::preDrawPrimitive()
 637{
 638   if( mStateDirty )
 639   {
 640      updateStates();
 641   }
 642   
 643   if(mCurrentShaderConstBuffer)
 644      setShaderConstBufferInternal(mCurrentShaderConstBuffer);
 645
 646   if( mNeedUpdateVertexAttrib )
 647   {
 648      AssertFatal(mCurrVertexDecl, "");
 649      const GFXGLVertexDecl* decl = static_cast<const GFXGLVertexDecl*>(mCurrVertexDecl);
 650      
 651      for(int i = 0; i < getNumVertexStreams(); ++i)
 652      {
 653         if(mCurrentVB[i])
 654         {
 655            mCurrentVB[i]->prepare(i, mCurrentVB_Divisor[i]);    // GL_ARB_vertex_attrib_binding  
 656            decl->prepareBuffer_old( i, mCurrentVB[i]->mBuffer, mCurrentVB_Divisor[i] ); // old vertex buffer/format
 657         }
 658      }
 659
 660      decl->updateActiveVertexAttrib( GFXGL->getOpenglCache()->getCacheVertexAttribActive() );         
 661   }   
 662
 663   mNeedUpdateVertexAttrib = false;
 664}
 665
 666inline void GFXGLDevice::postDrawPrimitive(U32 primitiveCount)
 667{
 668   mDeviceStatistics.mDrawCalls++;
 669   mDeviceStatistics.mPolyCount += primitiveCount;
 670}
 671
 672void GFXGLDevice::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ) 
 673{
 674   preDrawPrimitive();
 675  
 676   if(mCurrentVB[0])
 677      vertexStart += mCurrentVB[0]->mBufferVertexOffset;
 678
 679   if(mDrawInstancesCount)
 680      glDrawArraysInstanced(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount), mDrawInstancesCount);
 681   else
 682      glDrawArrays(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount));   
 683
 684   postDrawPrimitive(primitiveCount);
 685}
 686
 687void GFXGLDevice::drawIndexedPrimitive(   GFXPrimitiveType primType, 
 688                                          U32 startVertex, 
 689                                          U32 minIndex, 
 690                                          U32 numVerts, 
 691                                          U32 startIndex, 
 692                                          U32 primitiveCount )
 693{
 694   preDrawPrimitive();
 695
 696   U16* buf = (U16*)static_cast<GFXGLPrimitiveBuffer*>(mCurrentPrimitiveBuffer.getPointer())->getBuffer() + startIndex + mCurrentPrimitiveBuffer->mVolatileStart;
 697
 698   const U32 baseVertex = mCurrentVB[0]->mBufferVertexOffset + startVertex;
 699
 700   if(mDrawInstancesCount)
 701      glDrawElementsInstancedBaseVertex(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf, mDrawInstancesCount, baseVertex);
 702   else
 703      glDrawElementsBaseVertex(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf, baseVertex);
 704
 705   postDrawPrimitive(primitiveCount);
 706}
 707
 708void GFXGLDevice::setPB(GFXGLPrimitiveBuffer* pb)
 709{
 710   if(mCurrentPB)
 711      mCurrentPB->finish();
 712   mCurrentPB = pb;
 713}
 714
 715void GFXGLDevice::setTextureInternal(U32 textureUnit, const GFXTextureObject*texture)
 716{
 717   GFXGLTextureObject *tex = static_cast<GFXGLTextureObject*>(const_cast<GFXTextureObject*>(texture));
 718   if (tex)
 719   {
 720      mActiveTextureType[textureUnit] = tex->getBinding();
 721      tex->bind(textureUnit);
 722   } 
 723   else if(mActiveTextureType[textureUnit] != GL_ZERO)
 724   {
 725      glActiveTexture(GL_TEXTURE0 + textureUnit);
 726      glBindTexture(mActiveTextureType[textureUnit], 0);
 727      getOpenglCache()->setCacheBindedTex(textureUnit, mActiveTextureType[textureUnit], 0);
 728      mActiveTextureType[textureUnit] = GL_ZERO;
 729   }
 730}
 731
 732void GFXGLDevice::setCubemapInternal(U32 textureUnit, const GFXGLCubemap* texture)
 733{
 734   if(texture)
 735   {
 736      mActiveTextureType[textureUnit] = GL_TEXTURE_CUBE_MAP;
 737      texture->bind(textureUnit);
 738   }
 739   else if(mActiveTextureType[textureUnit] != GL_ZERO)
 740   {
 741      glActiveTexture(GL_TEXTURE0 + textureUnit);
 742      glBindTexture(mActiveTextureType[textureUnit], 0);
 743      getOpenglCache()->setCacheBindedTex(textureUnit, mActiveTextureType[textureUnit], 0);
 744      mActiveTextureType[textureUnit] = GL_ZERO;
 745   }
 746}
 747
 748void GFXGLDevice::setCubemapArrayInternal(U32 textureUnit, const GFXGLCubemapArray* texture)
 749{
 750   if (texture)
 751   {
 752      mActiveTextureType[textureUnit] = GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
 753      texture->bind(textureUnit);
 754   }
 755   else if (mActiveTextureType[textureUnit] != GL_ZERO)
 756   {
 757      glActiveTexture(GL_TEXTURE0 + textureUnit);
 758      glBindTexture(mActiveTextureType[textureUnit], 0);
 759      getOpenglCache()->setCacheBindedTex(textureUnit, mActiveTextureType[textureUnit], 0);
 760      mActiveTextureType[textureUnit] = GL_ZERO;
 761   }
 762}
 763
 764void GFXGLDevice::setTextureArrayInternal(U32 textureUnit, const GFXGLTextureArray* texture)
 765{
 766   if (texture)
 767   {
 768      mActiveTextureType[textureUnit] = GL_TEXTURE_2D_ARRAY;
 769      texture->bind(textureUnit);
 770   }
 771   else if (mActiveTextureType[textureUnit] != GL_ZERO)
 772   {
 773      glActiveTexture(GL_TEXTURE0 + textureUnit);
 774      glBindTexture(mActiveTextureType[textureUnit], 0);
 775      getOpenglCache()->setCacheBindedTex(textureUnit, mActiveTextureType[textureUnit], 0);
 776      mActiveTextureType[textureUnit] = GL_ZERO;
 777   }
 778}
 779
 780void GFXGLDevice::setClipRect( const RectI &inRect )
 781{
 782   AssertFatal(mCurrentRT.isValid(), "GFXGLDevice::setClipRect - must have a render target set to do any rendering operations!");
 783
 784   // Clip the rect against the renderable size.
 785   Point2I size = mCurrentRT->getSize();
 786   RectI maxRect(Point2I(0,0), size);
 787   mClip = inRect;
 788   mClip.intersect(maxRect);
 789
 790   // Create projection matrix.  See http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/ortho.html
 791   const F32 left = mClip.point.x;
 792   const F32 right = mClip.point.x + mClip.extent.x;
 793   const F32 bottom = mClip.extent.y;
 794   const F32 top = 0.0f;
 795   const F32 nearPlane = 0.0f;
 796   const F32 farPlane = 1.0f;
 797   
 798   const F32 tx = -(right + left)/(right - left);
 799   const F32 ty = -(top + bottom)/(top - bottom);
 800   const F32 tz = -(farPlane + nearPlane)/(farPlane - nearPlane);
 801   
 802   static Point4F pt;
 803   pt.set(2.0f / (right - left), 0.0f, 0.0f, 0.0f);
 804   mProjectionMatrix.setColumn(0, pt);
 805   
 806   pt.set(0.0f, 2.0f/(top - bottom), 0.0f, 0.0f);
 807   mProjectionMatrix.setColumn(1, pt);
 808   
 809   pt.set(0.0f, 0.0f, -2.0f/(farPlane - nearPlane), 0.0f);
 810   mProjectionMatrix.setColumn(2, pt);
 811   
 812   pt.set(tx, ty, tz, 1.0f);
 813   mProjectionMatrix.setColumn(3, pt);
 814   
 815   // Translate projection matrix.
 816   static MatrixF translate(true);
 817   pt.set(0.0f, -mClip.point.y, 0.0f, 1.0f);
 818   translate.setColumn(3, pt);
 819   
 820   mProjectionMatrix *= translate;
 821   
 822   MatrixF mTempMatrix(true);
 823   setViewMatrix( mTempMatrix );
 824   setWorldMatrix( mTempMatrix );
 825
 826   // Set the viewport to the clip rect
 827   RectI viewport(mClip.point.x, mClip.point.y, mClip.extent.x, mClip.extent.y);
 828   setViewport(viewport);
 829}
 830
 831/// Creates a state block object based on the desc passed in.  This object
 832/// represents an immutable state.
 833GFXStateBlockRef GFXGLDevice::createStateBlockInternal(const GFXStateBlockDesc& desc)
 834{
 835   return GFXStateBlockRef(new GFXGLStateBlock(desc));
 836}
 837
 838/// Activates a stateblock
 839void GFXGLDevice::setStateBlockInternal(GFXStateBlock* block, bool force)
 840{
 841   AssertFatal(dynamic_cast<GFXGLStateBlock*>(block), "GFXGLDevice::setStateBlockInternal - Incorrect stateblock type for this device!");
 842   GFXGLStateBlock* glBlock = static_cast<GFXGLStateBlock*>(block);
 843   GFXGLStateBlock* glCurrent = static_cast<GFXGLStateBlock*>(mCurrentStateBlock.getPointer());
 844   if (force)
 845      glCurrent = NULL;
 846      
 847   glBlock->activate(glCurrent); // Doesn't use current yet.
 848   mCurrentGLStateBlock = glBlock;
 849}
 850
 851//------------------------------------------------------------------------------
 852
 853GFXTextureTarget * GFXGLDevice::allocRenderToTextureTarget(bool genMips)
 854{
 855   GFXGLTextureTarget *targ = new GFXGLTextureTarget(genMips);
 856   targ->registerResourceWithDevice(this);
 857   return targ;
 858}
 859
 860GFXFence * GFXGLDevice::createFence()
 861{
 862   GFXFence* fence = _createPlatformSpecificFence();
 863   if(!fence)
 864      fence = new GFXGeneralFence( this );
 865      
 866   fence->registerResourceWithDevice(this);
 867   return fence;
 868}
 869
 870GFXOcclusionQuery* GFXGLDevice::createOcclusionQuery()
 871{   
 872   GFXOcclusionQuery *query = new GFXGLOcclusionQuery( this );
 873   query->registerResourceWithDevice(this);
 874   return query;
 875}
 876
 877void GFXGLDevice::setupGenericShaders( GenericShaderType type ) 
 878{
 879   AssertFatal(type != GSTargetRestore, "");
 880
 881   if( mGenericShader[GSColor] == NULL )
 882   {
 883      ShaderData *shaderData;
 884
 885      shaderData = new ShaderData();
 886      shaderData->setField("OGLVertexShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/colorV.glsl"));
 887      shaderData->setField("OGLPixelShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/colorP.glsl"));
 888      shaderData->setField("pixVersion", "2.0");
 889      shaderData->registerObject();
 890      mGenericShader[GSColor] =  shaderData->getShader();
 891      mGenericShaderBuffer[GSColor] = mGenericShader[GSColor]->allocConstBuffer();
 892      mModelViewProjSC[GSColor] = mGenericShader[GSColor]->getShaderConstHandle( "$modelView" );
 893      Sim::getRootGroup()->addObject(shaderData);
 894
 895      shaderData = new ShaderData();
 896      shaderData->setField("OGLVertexShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/modColorTextureV.glsl"));
 897      shaderData->setField("OGLPixelShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/modColorTextureP.glsl"));
 898      shaderData->setSamplerName("$diffuseMap", 0);
 899      shaderData->setField("pixVersion", "2.0");
 900      shaderData->registerObject();
 901      mGenericShader[GSModColorTexture] = shaderData->getShader();
 902      mGenericShaderBuffer[GSModColorTexture] = mGenericShader[GSModColorTexture]->allocConstBuffer();
 903      mModelViewProjSC[GSModColorTexture] = mGenericShader[GSModColorTexture]->getShaderConstHandle( "$modelView" );
 904      Sim::getRootGroup()->addObject(shaderData);
 905
 906      shaderData = new ShaderData();
 907      shaderData->setField("OGLVertexShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/addColorTextureV.glsl"));
 908      shaderData->setField("OGLPixelShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/addColorTextureP.glsl"));
 909      shaderData->setSamplerName("$diffuseMap", 0);
 910      shaderData->setField("pixVersion", "2.0");
 911      shaderData->registerObject();
 912      mGenericShader[GSAddColorTexture] = shaderData->getShader();
 913      mGenericShaderBuffer[GSAddColorTexture] = mGenericShader[GSAddColorTexture]->allocConstBuffer();
 914      mModelViewProjSC[GSAddColorTexture] = mGenericShader[GSAddColorTexture]->getShaderConstHandle( "$modelView" );
 915      Sim::getRootGroup()->addObject(shaderData);
 916
 917      shaderData = new ShaderData();
 918      shaderData->setField("OGLVertexShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/textureV.glsl"));
 919      shaderData->setField("OGLPixelShaderFile", ShaderGen::smCommonShaderPath + String("/fixedFunction/gl/textureP.glsl"));
 920      shaderData->setSamplerName("$diffuseMap", 0);
 921      shaderData->setField("pixVersion", "2.0");
 922      shaderData->registerObject();
 923      mGenericShader[GSTexture] = shaderData->getShader();
 924      mGenericShaderBuffer[GSTexture] = mGenericShader[GSTexture]->allocConstBuffer();
 925      mModelViewProjSC[GSTexture] = mGenericShader[GSTexture]->getShaderConstHandle( "$modelView" );
 926      Sim::getRootGroup()->addObject(shaderData);
 927   }
 928
 929   MatrixF tempMatrix =  mProjectionMatrix * mViewMatrix * mWorldMatrix[mWorldStackSize];  
 930   mGenericShaderBuffer[type]->setSafe(mModelViewProjSC[type], tempMatrix);
 931
 932   setShader( mGenericShader[type] );
 933   setShaderConstBuffer( mGenericShaderBuffer[type] );
 934}
 935GFXShader* GFXGLDevice::createShader()
 936{
 937   GFXGLShader* shader = new GFXGLShader();
 938   shader->registerResourceWithDevice( this );
 939   return shader;
 940}
 941
 942void GFXGLDevice::setShader(GFXShader *shader, bool force)
 943{
 944   if(mCurrentShader == shader && !force)
 945      return;
 946
 947   if ( shader )
 948   {
 949      GFXGLShader *glShader = static_cast<GFXGLShader*>( shader );
 950      glShader->useProgram();
 951      mCurrentShader = shader;
 952   }
 953   else
 954   {
 955      setupGenericShaders();
 956   }
 957}
 958
 959void GFXGLDevice::setShaderConstBufferInternal(GFXShaderConstBuffer* buffer)
 960{
 961   PROFILE_SCOPE(GFXGLDevice_setShaderConstBufferInternal);
 962   static_cast<GFXGLShaderConstBuffer*>(buffer)->activate();
 963}
 964
 965U32 GFXGLDevice::getNumSamplers() const
 966{
 967   return getMin((U32)GFX_TEXTURE_STAGE_COUNT,mPixelShaderVersion > 0.001f ? mMaxShaderTextures : mMaxFFTextures);
 968}
 969
 970GFXTextureObject* GFXGLDevice::getDefaultDepthTex() const 
 971{
 972   if(mWindowRT && mWindowRT->getPointer())
 973      return static_cast<GFXGLWindowTarget*>( mWindowRT->getPointer() )->mBackBufferDepthTex.getPointer();
 974
 975   return NULL;
 976}
 977
 978U32 GFXGLDevice::getNumRenderTargets() const 
 979{ 
 980   return mMaxTRColors; 
 981}
 982
 983void GFXGLDevice::_updateRenderTargets()
 984{
 985   if ( mRTDirty || mCurrentRT->isPendingState() )
 986   {
 987      if ( mRTDeactivate )
 988      {
 989         mRTDeactivate->deactivate();
 990         mRTDeactivate = NULL;   
 991      }
 992      
 993      // NOTE: The render target changes is not really accurate
 994      // as the GFXTextureTarget supports MRT internally.  So when
 995      // we activate a GFXTarget it could result in multiple calls
 996      // to SetRenderTarget on the actual device.
 997      mDeviceStatistics.mRenderTargetChanges++;
 998
 999      GFXGLTextureTarget *tex = dynamic_cast<GFXGLTextureTarget*>( mCurrentRT.getPointer() );
1000      if ( tex )
1001      {
1002         tex->applyState();
1003         tex->makeActive();
1004      }
1005      else
1006      {
1007         GFXGLWindowTarget *win = dynamic_cast<GFXGLWindowTarget*>( mCurrentRT.getPointer() );
1008         AssertFatal( win != NULL, 
1009                     "GFXGLDevice::_updateRenderTargets() - invalid target subclass passed!" );
1010         
1011         win->makeActive();
1012         
1013         if( win->mContext != static_cast<GFXGLDevice*>(GFX)->mContext )
1014         {
1015            mRTDirty = false;
1016            GFX->updateStates(true);
1017         }
1018      }
1019      
1020      mRTDirty = false;
1021   }
1022   
1023   if ( mViewportDirty )
1024   {
1025      glViewport( mViewport.point.x, mViewport.point.y, mViewport.extent.x, mViewport.extent.y ); 
1026      mViewportDirty = false;
1027   }
1028}
1029
1030GFXFormat GFXGLDevice::selectSupportedFormat(   GFXTextureProfile* profile, 
1031                                                const Vector<GFXFormat>& formats, 
1032                                                bool texture, 
1033                                                bool mustblend,
1034                                                bool mustfilter )
1035{
1036   for(U32 i = 0; i < formats.size(); i++)
1037   {
1038      // Single channel textures are not supported by FBOs.
1039      if(profile->testFlag(GFXTextureProfile::RenderTarget) && (formats[i] == GFXFormatA8 || formats[i] == GFXFormatL8 || formats[i] == GFXFormatL16))
1040         continue;
1041      if(GFXGLTextureInternalFormat[formats[i]] == GL_ZERO)
1042         continue;
1043      
1044      return formats[i];
1045   }
1046   
1047   return GFXFormatR8G8B8A8;
1048}
1049
1050U32 GFXGLDevice::getTotalVideoMemory_GL_EXT()
1051{
1052   // Source: http://www.opengl.org/registry/specs/ATI/meminfo.txt
1053   if( gglHasExtension(ATI_meminfo) )
1054   {
1055      GLint mem[4] = {0};
1056      glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, mem);  // Retrieve the texture pool
1057      
1058      /* With mem[0] i get only the total memory free in the pool in KB
1059      *
1060      * mem[0] - total memory free in the pool
1061      * mem[1] - largest available free block in the pool
1062      * mem[2] - total auxiliary memory free
1063      * mem[3] - largest auxiliary free block
1064      */
1065
1066      return  mem[0] / 1024;
1067   }
1068   
1069   //source http://www.opengl.org/registry/specs/NVX/gpu_memory_info.txt
1070   else if( gglHasExtension(NVX_gpu_memory_info) )
1071   {
1072      GLint mem = 0;
1073      glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &mem);
1074      return mem / 1024;
1075   }
1076
1077   // TODO OPENGL, add supprt for INTEL cards.
1078   
1079   return 0;
1080}
1081
1082//
1083// Register this device with GFXInit
1084//
1085class GFXGLRegisterDevice
1086{
1087public:
1088   GFXGLRegisterDevice()
1089   {
1090      GFXInit::getRegisterDeviceSignal().notify(&GFXGLDevice::enumerateAdapters);
1091   }
1092};
1093
1094static GFXGLRegisterDevice pGLRegisterDevice;
1095
1096DefineEngineFunction(cycleResources, void, (),, "")
1097{
1098   static_cast<GFXGLDevice*>(GFX)->zombify();
1099   static_cast<GFXGLDevice*>(GFX)->resurrect();
1100}
1101