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