Torque3D Documentation / _generateds / gfxGLDevice.cpp

gfxGLDevice.cpp

Engine/source/gfx/gl/gfxGLDevice.cpp

More...

Classes:

Namespaces:

namespace

Public Functions

ConsoleFunction(cycleResources , void , 1 , 1 , "" )
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

ConsoleFunction(cycleResources , void , 1 , 1 , "" )

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