/indra/newview/lldrawpoolalpha.cpp
C++ | 538 lines | 420 code | 77 blank | 41 comment | 77 complexity | 4280fa9aa473f7d3263e4a7ebeb3f68d MD5 | raw file
Possible License(s): LGPL-2.1
1/** 2 * @file lldrawpoolalpha.cpp 3 * @brief LLDrawPoolAlpha class implementation 4 * 5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$ 6 * Second Life Viewer Source Code 7 * Copyright (C) 2010, Linden Research, Inc. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; 12 * version 2.1 of the License only. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA 24 * $/LicenseInfo$ 25 */ 26 27#include "llviewerprecompiledheaders.h" 28 29#include "lldrawpoolalpha.h" 30 31#include "llglheaders.h" 32#include "llviewercontrol.h" 33#include "llcriticaldamp.h" 34#include "llfasttimer.h" 35#include "llrender.h" 36 37#include "llcubemap.h" 38#include "llsky.h" 39#include "lldrawable.h" 40#include "llface.h" 41#include "llviewercamera.h" 42#include "llviewertexturelist.h" // For debugging 43#include "llviewerobjectlist.h" // For debugging 44#include "llviewerwindow.h" 45#include "pipeline.h" 46#include "llviewershadermgr.h" 47#include "llviewerregion.h" 48#include "lldrawpoolwater.h" 49#include "llspatialpartition.h" 50 51BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE; 52 53static BOOL deferred_render = FALSE; 54 55LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) : 56 LLRenderPass(type), current_shader(NULL), target_shader(NULL), 57 simple_shader(NULL), fullbright_shader(NULL), emissive_shader(NULL), 58 mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF), 59 mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF) 60{ 61 62} 63 64LLDrawPoolAlpha::~LLDrawPoolAlpha() 65{ 66} 67 68 69void LLDrawPoolAlpha::prerender() 70{ 71 mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); 72} 73 74S32 LLDrawPoolAlpha::getNumDeferredPasses() 75{ 76 return 1; 77} 78 79void LLDrawPoolAlpha::beginDeferredPass(S32 pass) 80{ 81 82} 83 84void LLDrawPoolAlpha::endDeferredPass(S32 pass) 85{ 86 87} 88 89void LLDrawPoolAlpha::renderDeferred(S32 pass) 90{ 91 LLFastTimer t(FTM_RENDER_GRASS); 92 gDeferredDiffuseAlphaMaskProgram.bind(); 93 gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f); 94 95 //render alpha masked objects 96 LLRenderPass::pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); 97 gDeferredDiffuseAlphaMaskProgram.unbind(); 98} 99 100 101S32 LLDrawPoolAlpha::getNumPostDeferredPasses() 102{ 103 if (LLPipeline::sImpostorRender) 104 { //skip depth buffer filling pass when rendering impostors 105 return 1; 106 } 107 else if (gSavedSettings.getBOOL("RenderDepthOfField")) 108 { 109 return 2; 110 } 111 else 112 { 113 return 1; 114 } 115} 116 117void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) 118{ 119 LLFastTimer t(FTM_RENDER_ALPHA); 120 121 if (pass == 0) 122 { 123 simple_shader = &gDeferredAlphaProgram; 124 fullbright_shader = &gObjectFullbrightAlphaMaskProgram; 125 126 //prime simple shader (loads shadow relevant uniforms) 127 gPipeline.bindDeferredShader(*simple_shader); 128 } 129 else 130 { 131 //update depth buffer sampler 132 gPipeline.mScreen.flush(); 133 gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(), 134 0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); 135 gPipeline.mDeferredDepth.bindTarget(); 136 simple_shader = NULL; 137 fullbright_shader = NULL; 138 gObjectFullbrightAlphaMaskProgram.bind(); 139 gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f); 140 } 141 142 deferred_render = TRUE; 143 if (mVertexShaderLevel > 0) 144 { 145 // Start out with no shaders. 146 current_shader = target_shader = NULL; 147 } 148 gPipeline.enableLightsDynamic(); 149} 150 151void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 152{ 153 154 if (pass == 1) 155 { 156 gPipeline.mDeferredDepth.flush(); 157 gPipeline.mScreen.bindTarget(); 158 gObjectFullbrightAlphaMaskProgram.unbind(); 159 } 160 161 deferred_render = FALSE; 162 endRenderPass(pass); 163} 164 165void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 166{ 167 render(pass); 168} 169 170void LLDrawPoolAlpha::beginRenderPass(S32 pass) 171{ 172 LLFastTimer t(FTM_RENDER_ALPHA); 173 174 if (LLPipeline::sUnderWaterRender) 175 { 176 simple_shader = &gObjectSimpleWaterAlphaMaskProgram; 177 fullbright_shader = &gObjectFullbrightWaterAlphaMaskProgram; 178 emissive_shader = &gObjectEmissiveWaterProgram; 179 } 180 else 181 { 182 simple_shader = &gObjectSimpleAlphaMaskProgram; 183 fullbright_shader = &gObjectFullbrightAlphaMaskProgram; 184 emissive_shader = &gObjectEmissiveProgram; 185 } 186 187 if (mVertexShaderLevel > 0) 188 { 189 // Start out with no shaders. 190 current_shader = target_shader = NULL; 191 LLGLSLShader::bindNoShader(); 192 } 193 gPipeline.enableLightsDynamic(); 194} 195 196void LLDrawPoolAlpha::endRenderPass( S32 pass ) 197{ 198 LLFastTimer t(FTM_RENDER_ALPHA); 199 LLRenderPass::endRenderPass(pass); 200 201 if(gPipeline.canUseWindLightShaders()) 202 { 203 LLGLSLShader::bindNoShader(); 204 } 205} 206 207void LLDrawPoolAlpha::render(S32 pass) 208{ 209 LLFastTimer t(FTM_RENDER_ALPHA); 210 211 LLGLSPipelineAlpha gls_pipeline_alpha; 212 213 if (deferred_render && pass == 1) 214 { //depth only 215 gGL.setColorMask(false, false); 216 } 217 else 218 { 219 gGL.setColorMask(true, true); 220 } 221 222 if (LLPipeline::sAutoMaskAlphaNonDeferred) 223 { 224 mColorSFactor = LLRender::BF_ONE; // } 225 mColorDFactor = LLRender::BF_ZERO; // } these are like disabling blend on the color channels, but we're still blending on the alpha channel so that we can suppress glow 226 mAlphaSFactor = LLRender::BF_ZERO; 227 mAlphaDFactor = LLRender::BF_ZERO; // block (zero-out) glow where the alpha test succeeds 228 gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); 229 230 if (mVertexShaderLevel > 0) 231 { 232 if (!LLPipeline::sRenderDeferred || !deferred_render) 233 { 234 simple_shader->bind(); 235 simple_shader->setMinimumAlpha(0.33f); 236 237 pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); 238 } 239 if (fullbright_shader) 240 { 241 fullbright_shader->bind(); 242 fullbright_shader->setMinimumAlpha(0.33f); 243 } 244 pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); 245 //LLGLSLShader::bindNoShader(); 246 } 247 else 248 { 249 gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.33f); //OK 250 gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); 251 pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask()); 252 gPipeline.enableLightsDynamic(); 253 pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask()); 254 gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK 255 } 256 } 257 258 LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy || 259 (deferred_render && pass == 1) ? GL_TRUE : GL_FALSE); 260 261 if (deferred_render && pass == 1) 262 { 263 gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); 264 } 265 else 266 { 267 mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend 268 mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } 269 mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression 270 mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } 271 gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); 272 273 if (mVertexShaderLevel > 0) 274 { 275 if (LLPipeline::sImpostorRender) 276 { 277 fullbright_shader->bind(); 278 fullbright_shader->setMinimumAlpha(0.5f); 279 simple_shader->bind(); 280 simple_shader->setMinimumAlpha(0.5f); 281 } 282 else 283 { 284 fullbright_shader->bind(); 285 fullbright_shader->setMinimumAlpha(0.f); 286 simple_shader->bind(); 287 simple_shader->setMinimumAlpha(0.f); 288 } 289 } 290 else 291 { 292 if (LLPipeline::sImpostorRender) 293 { 294 gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); //OK 295 } 296 else 297 { 298 gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK 299 } 300 } 301 } 302 303 if (mVertexShaderLevel > 0) 304 { 305 renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX); 306 } 307 else 308 { 309 renderAlpha(getVertexDataMask()); 310 } 311 312 gGL.setColorMask(true, false); 313 314 if (deferred_render && pass == 1) 315 { 316 gGL.setSceneBlendType(LLRender::BT_ALPHA); 317 } 318 319 if (sShowDebugAlpha) 320 { 321 BOOL shaders = gPipeline.canUseVertexShaders(); 322 if(shaders) 323 { 324 gHighlightProgram.bind(); 325 } 326 else 327 { 328 gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); 329 } 330 331 gGL.diffuseColor4f(1,0,0,1); 332 333 LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f); 334 gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ; 335 renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX | 336 LLVertexBuffer::MAP_TEXCOORD0); 337 338 pushBatches(LLRenderPass::PASS_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); 339 pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); 340 341 if(shaders) 342 { 343 gHighlightProgram.unbind(); 344 } 345 } 346} 347 348void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) 349{ 350 for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) 351 { 352 LLSpatialGroup* group = *i; 353 if (group->mSpatialPartition->mRenderByGroup && 354 !group->isDead()) 355 { 356 LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; 357 358 for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) 359 { 360 LLDrawInfo& params = **k; 361 362 if (params.mParticle) 363 { 364 continue; 365 } 366 367 LLRenderPass::applyModelMatrix(params); 368 if (params.mGroup) 369 { 370 params.mGroup->rebuildMesh(); 371 } 372 params.mVertexBuffer->setBuffer(mask); 373 params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); 374 gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); 375 } 376 } 377 } 378} 379 380void LLDrawPoolAlpha::renderAlpha(U32 mask) 381{ 382 BOOL initialized_lighting = FALSE; 383 BOOL light_enabled = TRUE; 384 385 BOOL use_shaders = gPipeline.canUseVertexShaders(); 386 387 for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) 388 { 389 LLSpatialGroup* group = *i; 390 llassert(group); 391 llassert(group->mSpatialPartition); 392 393 if (group->mSpatialPartition->mRenderByGroup && 394 !group->isDead()) 395 { 396 bool draw_glow_for_this_partition = mVertexShaderLevel > 0 && // no shaders = no glow. 397 // All particle systems seem to come off the wire with texture entries which claim that they glow. This is probably a bug in the data. Suppress. 398 group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_PARTICLE && 399 group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD_PARTICLE; 400 401 LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; 402 403 for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) 404 { 405 LLDrawInfo& params = **k; 406 407 LLRenderPass::applyModelMatrix(params); 408 409 410 if (params.mFullbright) 411 { 412 // Turn off lighting if it hasn't already been so. 413 if (light_enabled || !initialized_lighting) 414 { 415 initialized_lighting = TRUE; 416 if (use_shaders) 417 { 418 target_shader = fullbright_shader; 419 } 420 else 421 { 422 gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); 423 } 424 light_enabled = FALSE; 425 } 426 } 427 // Turn on lighting if it isn't already. 428 else if (!light_enabled || !initialized_lighting) 429 { 430 initialized_lighting = TRUE; 431 if (use_shaders) 432 { 433 target_shader = simple_shader; 434 } 435 else 436 { 437 gPipeline.enableLightsDynamic(); 438 } 439 light_enabled = TRUE; 440 } 441 442 // If we need shaders, and we're not ALREADY using the proper shader, then bind it 443 // (this way we won't rebind shaders unnecessarily). 444 if(use_shaders && (current_shader != target_shader)) 445 { 446 llassert(target_shader != NULL); 447 current_shader = target_shader; 448 current_shader->bind(); 449 } 450 else if (!use_shaders && current_shader != NULL) 451 { 452 LLGLSLShader::bindNoShader(); 453 current_shader = NULL; 454 } 455 456 if (params.mGroup) 457 { 458 params.mGroup->rebuildMesh(); 459 } 460 461 bool tex_setup = false; 462 463 if (use_shaders && params.mTextureList.size() > 1) 464 { 465 for (U32 i = 0; i < params.mTextureList.size(); ++i) 466 { 467 if (params.mTextureList[i].notNull()) 468 { 469 gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE); 470 } 471 } 472 } 473 else 474 { //not batching textures or batch has only 1 texture -- might need a texture matrix 475 if (params.mTexture.notNull()) 476 { 477 params.mTexture->addTextureStats(params.mVSize); 478 gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ; 479 if (params.mTextureMatrix) 480 { 481 tex_setup = true; 482 gGL.getTexUnit(0)->activate(); 483 gGL.matrixMode(LLRender::MM_TEXTURE); 484 gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); 485 gPipeline.mTextureMatrixOps++; 486 } 487 } 488 else 489 { 490 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); 491 } 492 } 493 494 params.mVertexBuffer->setBuffer(mask); 495 params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); 496 gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); 497 498 // If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow). Interleaving these state-changing calls could be expensive, but glow must be drawn Z-sorted with alpha. 499 if (current_shader && 500 draw_glow_for_this_partition && 501 params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE)) 502 { 503 // install glow-accumulating blend mode 504 gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, // don't touch color 505 LLRender::BF_ONE, LLRender::BF_ONE); // add to alpha (glow) 506 507 emissive_shader->bind(); 508 509 // glow doesn't use vertex colors from the mesh data 510 params.mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE); 511 512 // do the actual drawing, again 513 params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); 514 gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); 515 516 // restore our alpha blend mode 517 gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); 518 519 current_shader->bind(); 520 } 521 522 if (tex_setup) 523 { 524 gGL.getTexUnit(0)->activate(); 525 gGL.loadIdentity(); 526 gGL.matrixMode(LLRender::MM_MODELVIEW); 527 } 528 } 529 } 530 } 531 532 LLVertexBuffer::unbind(); 533 534 if (!light_enabled) 535 { 536 gPipeline.enableLightsDynamic(); 537 } 538}