gfxGLDevice.cpp
Engine/source/gfx/gl/gfxGLDevice.cpp
Classes:
class
Namespaces:
namespace
Public Variables
Public Functions
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
