diff options
| author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 20:51:58 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-22 20:51:58 +0300 |
| commit | 6cc7dd09d5e69cf57e6de7fb568a0ad2693f9c9a (patch) | |
| tree | fab23811a5cedc1ebf01479c852ee92ff62b636c /indra/newview/lldrawpoolalpha.cpp | |
| parent | ef8f4819822288e044ea719feb6af7a1f4df4c4e (diff) | |
| parent | 7bb5afc11ee5a6af78302a8d76a9a619e2baaab2 (diff) | |
Merge pull request #1545 from Ansariel/DRTVWR-600-maint-A
Merge main into DRTVWR-600-maint-a
Diffstat (limited to 'indra/newview/lldrawpoolalpha.cpp')
| -rw-r--r-- | indra/newview/lldrawpoolalpha.cpp | 1870 |
1 files changed, 935 insertions, 935 deletions
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 5a868ae887..7e4c1287ff 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -1,935 +1,935 @@ -/** - * @file lldrawpoolalpha.cpp - * @brief LLDrawPoolAlpha class implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lldrawpoolalpha.h" - -#include "llglheaders.h" -#include "llviewercontrol.h" -#include "llcriticaldamp.h" -#include "llfasttimer.h" -#include "llrender.h" - -#include "llcubemap.h" -#include "llsky.h" -#include "lldrawable.h" -#include "llface.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" // For debugging -#include "llviewerobjectlist.h" // For debugging -#include "llviewerwindow.h" -#include "pipeline.h" -#include "llviewershadermgr.h" -#include "llviewerregion.h" -#include "lldrawpoolwater.h" -#include "llspatialpartition.h" -#include "llglcommonfunc.h" -#include "llvoavatar.h" - -#include "llenvironment.h" - -bool LLDrawPoolAlpha::sShowDebugAlpha = false; - -#define current_shader (LLGLSLShader::sCurBoundShaderPtr) - -LLVector4 LLDrawPoolAlpha::sWaterPlane; - -// minimum alpha before discarding a fragment -static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255 - -// minimum alpha before discarding a fragment when rendering impostors -static const F32 MINIMUM_IMPOSTOR_ALPHA = 0.1f; - -LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) : - LLRenderPass(type), target_shader(NULL), - mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF), - mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF) -{ - -} - -LLDrawPoolAlpha::~LLDrawPoolAlpha() -{ -} - - -void LLDrawPoolAlpha::prerender() -{ - mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); - - // TODO: is this even necessay? These are probably set to never discard - LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f); - LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f); -} - -S32 LLDrawPoolAlpha::getNumPostDeferredPasses() -{ - return 1; -} - -// set some common parameters on the given shader to prepare for alpha rendering -static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment, F32 water_sign) -{ - static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma"); - F32 gamma = displayGamma; - - static LLStaticHashedString waterSign("waterSign"); - - // Does this deferred shader need environment uniforms set such as sun_dir, etc. ? - // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering - // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms() - // i.e. shaders\class1\deferred\alphaF.glsl - if (deferredEnvironment) - { - shader->mCanBindFast = false; - } - - shader->bind(); - shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); - - if (LLPipeline::sRenderingHUDs) - { // for HUD attachments, only the pre-water pass is executed and we never want to clip anything - LLVector4 near_clip(0, 0, -1, 0); - shader->uniform1f(waterSign, 1.f); - shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, near_clip.mV); - } - else - { - shader->uniform1f(waterSign, water_sign); - shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV); - } - - if (LLPipeline::sImpostorRender) - { - shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA); - } - else - { - shader->setMinimumAlpha(MINIMUM_ALPHA); - } - if (textureGamma) - { - shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - } - - //also prepare rigged variant - if (shader->mRiggedVariant && shader->mRiggedVariant != shader) - { - prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment, water_sign); - } -} - -extern bool gCubeSnapshot; - -void LLDrawPoolAlpha::renderPostDeferred(S32 pass) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - - if (LLPipeline::isWaterClip() && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER) - { // don't render alpha objects on the other side of the water plane if water is opaque - return; - } - - F32 water_sign = 1.f; - - if (getType() == LLDrawPool::POOL_ALPHA_PRE_WATER) - { - water_sign = -1.f; - } - - if (LLPipeline::sUnderWaterRender) - { - water_sign *= -1.f; - } - - // prepare shaders - llassert(LLPipeline::sRenderDeferred); - - emissive_shader = &gDeferredEmissiveProgram; - prepare_alpha_shader(emissive_shader, true, false, water_sign); - - pbr_emissive_shader = &gPBRGlowProgram; - prepare_alpha_shader(pbr_emissive_shader, true, false, water_sign); - - - fullbright_shader = - (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram : - (LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram : - &gDeferredFullbrightAlphaMaskAlphaProgram; - prepare_alpha_shader(fullbright_shader, true, true, water_sign); - - simple_shader = - (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : - (LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram : - &gDeferredAlphaProgram; - - prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms) - - LLGLSLShader* materialShader = gDeferredMaterialProgram; - for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) - { - prepare_alpha_shader(&materialShader[i], false, true, water_sign); - } - - pbr_shader = - (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram : - &gDeferredPBRAlphaProgram; - - prepare_alpha_shader(pbr_shader, false, true, water_sign); - - // explicitly unbind here so render loop doesn't make assumptions about the last shader - // already being setup for rendering - LLGLSLShader::unbind(); - - if (!LLPipeline::sRenderingHUDs) - { - // first pass, render rigged objects only and render to depth buffer - forwardRender(true); - } - - // second pass, regular forward alpha rendering - forwardRender(); - - // final pass, render to depth for depth of field effects - if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot && !LLPipeline::sRenderingHUDs && getType() == LLDrawPool::POOL_ALPHA_POST_WATER) - { - //update depth buffer sampler - simple_shader = fullbright_shader = &gDeferredFullbrightAlphaMaskProgram; - - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.33f); - - // mask off color buffer writes as we're only writing to depth buffer - gGL.setColorMask(false, false); - - // If the face is more than 90% transparent, then don't update the Depth buffer for Dof - // We don't want the nearly invisible objects to cause of DoF effects - renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, - true); // <--- discard mostly transparent faces - - gGL.setColorMask(true, false); - } -} - -void LLDrawPoolAlpha::forwardRender(bool rigged) -{ - gPipeline.enableLightsDynamic(); - - LLGLSPipelineAlpha gls_pipeline_alpha; - - //enable writing to alpha for emissive effects - gGL.setColorMask(true, true); - - bool write_depth = rigged || - LLDrawPoolWater::sSkipScreenCopy - // we want depth written so that rendered alpha will - // contribute to the alpha mask used for impostors - || LLPipeline::sImpostorRenderAlphaDepthPass - || getType() == LLDrawPoolAlpha::POOL_ALPHA_PRE_WATER; // needed for accurate water fog - - - LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE); - - mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend - mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } - mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression - mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - // If the face is more than 90% transparent, then don't update the Depth buffer for Dof - // We don't want the nearly invisible objects to cause of DoF effects - renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged); - - gGL.setColorMask(true, false); - - if (!rigged) - { //render "highlight alpha" on final non-rigged pass - // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender" - // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state - // variables above are still in scope - renderDebugAlpha(); - } -} - -void LLDrawPoolAlpha::renderDebugAlpha() -{ - if (sShowDebugAlpha) - { - gHighlightProgram.bind(); - gGL.diffuseColor4f(1, 0, 0, 1); - gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::getSmokeImage()); - - - renderAlphaHighlight(); - - pushUntexturedBatches(LLRenderPass::PASS_ALPHA_MASK); - pushUntexturedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE); - - // Material alpha mask - gGL.diffuseColor4f(0, 0, 1, 1); - pushUntexturedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK); - pushUntexturedBatches(LLRenderPass::PASS_NORMMAP_MASK); - pushUntexturedBatches(LLRenderPass::PASS_SPECMAP_MASK); - pushUntexturedBatches(LLRenderPass::PASS_NORMSPEC_MASK); - pushUntexturedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); - pushUntexturedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK); - - gGL.diffuseColor4f(0, 1, 0, 1); - pushUntexturedBatches(LLRenderPass::PASS_INVISIBLE); - - gHighlightProgram.mRiggedVariant->bind(); - gGL.diffuseColor4f(1, 0, 0, 1); - - pushRiggedBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, false); - pushRiggedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE_RIGGED, false); - - // Material alpha mask - gGL.diffuseColor4f(0, 0, 1, 1); - pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, false); - pushRiggedBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, false); - pushRiggedBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, false); - pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, false); - pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, false); - pushRiggedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK_RIGGED, false); - - gGL.diffuseColor4f(0, 1, 0, 1); - pushRiggedBatches(LLRenderPass::PASS_INVISIBLE_RIGGED, false); - LLGLSLShader::sCurBoundShaderPtr->unbind(); - } -} - -void LLDrawPoolAlpha::renderAlphaHighlight() -{ - for (int pass = 0; pass < 2; ++pass) - { //two passes, one rigged and one not - LLVOAvatar* lastAvatar = nullptr; - U64 lastMeshId = 0; - - LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups(); - LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups(); - - for (LLCullResult::sg_iterator i = begin; i != end; ++i) - { - LLSpatialGroup* group = *i; - if (group->getSpatialPartition()->mRenderByGroup && - !group->isDead()) - { - LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass - - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) - { - LLDrawInfo& params = **k; - - bool rigged = (params.mAvatar != nullptr); - gHighlightProgram.bind(rigged); - gGL.diffuseColor4f(1, 0, 0, 1); - - if (rigged) - { - if (lastAvatar != params.mAvatar || - lastMeshId != params.mSkinInfo->mHash) - { - if (!uploadMatrixPalette(params)) - { - continue; - } - lastAvatar = params.mAvatar; - lastMeshId = params.mSkinInfo->mHash; - } - } - - LLRenderPass::applyModelMatrix(params); - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); - } - } - } - } - - // make sure static version of highlight shader is bound before returning - gHighlightProgram.bind(); -} - -inline bool IsFullbright(LLDrawInfo& params) -{ - return params.mFullbright; -} - -inline bool IsMaterial(LLDrawInfo& params) -{ - return params.mMaterial != nullptr; -} - -inline bool IsEmissive(LLDrawInfo& params) -{ - return params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); -} - -inline void Draw(LLDrawInfo* draw, U32 mask) -{ - draw->mVertexBuffer->setBuffer(); - LLRenderPass::applyModelMatrix(*draw); - draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); -} - -bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material) -{ - bool tex_setup = false; - - if (draw->mGLTFMaterial) - { - if (draw->mTextureMatrix) - { - tex_setup = true; - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix); - gPipeline.mTextureMatrixOps++; - } - } - else - { - if (!LLPipeline::sRenderingHUDs && use_material && current_shader) - { - if (draw->mNormalMap) - { - current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap); - } - - if (draw->mSpecularMap) - { - current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap); - } - } - else if (current_shader == simple_shader || current_shader == simple_shader->mRiggedVariant) - { - current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); - current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); - } - if (draw->mTextureList.size() > 1) - { - for (U32 i = 0; i < draw->mTextureList.size(); ++i) - { - if (draw->mTextureList[i].notNull()) - { - gGL.getTexUnit(i)->bindFast(draw->mTextureList[i]); - } - } - } - else - { //not batching textures or batch has only 1 texture -- might need a texture matrix - if (draw->mTexture.notNull()) - { - if (use_material) - { - current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, draw->mTexture); - } - else - { - gGL.getTexUnit(0)->bindFast(draw->mTexture); - } - - if (draw->mTextureMatrix) - { - tex_setup = true; - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix); - gPipeline.mTextureMatrixOps++; - } - } - else - { - gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE); - } - } - } - - return tex_setup; -} - -void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup) -{ - if (tex_setup) - { - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } -} - -void LLDrawPoolAlpha::drawEmissive(LLDrawInfo* draw) -{ - LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - draw->mVertexBuffer->setBuffer(); - draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); -} - - -void LLDrawPoolAlpha::renderEmissives(std::vector<LLDrawInfo*>& emissives) -{ - emissive_shader->bind(); - emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - - for (LLDrawInfo* draw : emissives) - { - bool tex_setup = TexSetup(draw, false); - drawEmissive(draw); - RestoreTexSetup(tex_setup); - } -} - -void LLDrawPoolAlpha::renderPbrEmissives(std::vector<LLDrawInfo*>& emissives) -{ - pbr_emissive_shader->bind(); - - for (LLDrawInfo* draw : emissives) - { - llassert(draw->mGLTFMaterial); - LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0); - draw->mGLTFMaterial->bind(draw->mTexture); - draw->mVertexBuffer->setBuffer(); - draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); - } -} - -void LLDrawPoolAlpha::renderRiggedEmissives(std::vector<LLDrawInfo*>& emissives) -{ - LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter - LLGLSLShader* shader = emissive_shader->mRiggedVariant; - shader->bind(); - shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - - LLVOAvatar* lastAvatar = nullptr; - U64 lastMeshId = 0; - - for (LLDrawInfo* draw : emissives) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("Emissives"); - - bool tex_setup = TexSetup(draw, false); - if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash) - { - if (!uploadMatrixPalette(*draw)) - { // failed to upload matrix palette, skip rendering - continue; - } - lastAvatar = draw->mAvatar; - lastMeshId = draw->mSkinInfo->mHash; - } - drawEmissive(draw); - RestoreTexSetup(tex_setup); - } -} - -void LLDrawPoolAlpha::renderRiggedPbrEmissives(std::vector<LLDrawInfo*>& emissives) -{ - LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter - pbr_emissive_shader->bind(true); - - LLVOAvatar* lastAvatar = nullptr; - U64 lastMeshId = 0; - - for (LLDrawInfo* draw : emissives) - { - if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash) - { - if (!uploadMatrixPalette(*draw)) - { // failed to upload matrix palette, skip rendering - continue; - } - lastAvatar = draw->mAvatar; - lastMeshId = draw->mSkinInfo->mHash; - } - - LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0); - draw->mGLTFMaterial->bind(draw->mTexture); - draw->mVertexBuffer->setBuffer(); - draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); - } -} - -void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - bool initialized_lighting = false; - bool light_enabled = true; - - LLVOAvatar* lastAvatar = nullptr; - U64 lastMeshId = 0; - LLGLSLShader* lastAvatarShader = nullptr; - - LLCullResult::sg_iterator begin; - LLCullResult::sg_iterator end; - - if (rigged) - { - begin = gPipeline.beginRiggedAlphaGroups(); - end = gPipeline.endRiggedAlphaGroups(); - } - else - { - begin = gPipeline.beginAlphaGroups(); - end = gPipeline.endAlphaGroups(); - } - - LLEnvironment& env = LLEnvironment::instance(); - F32 water_height = env.getWaterHeight(); - - bool above_water = getType() == LLDrawPool::POOL_ALPHA_POST_WATER; - if (LLPipeline::sUnderWaterRender) - { - above_water = !above_water; - } - - - for (LLCullResult::sg_iterator i = begin; i != end; ++i) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group"); - LLSpatialGroup* group = *i; - llassert(group); - llassert(group->getSpatialPartition()); - - if (group->getSpatialPartition()->mRenderByGroup && - !group->isDead()) - { - - LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); - const LLVector4a* ext = bridge ? bridge->getSpatialExtents() : group->getExtents(); - - if (!LLPipeline::sRenderingHUDs) // ignore above/below water for HUD render - { - if (above_water) - { // reject any spatial groups that have no part above water - if (ext[1].getF32ptr()[2] < water_height) - { - continue; - } - } - else - { // reject any spatial groups that he no part below water - if (ext[0].getF32ptr()[2] > water_height) - { - continue; - } - } - } - - static std::vector<LLDrawInfo*> emissives; - static std::vector<LLDrawInfo*> rigged_emissives; - static std::vector<LLDrawInfo*> pbr_emissives; - static std::vector<LLDrawInfo*> pbr_rigged_emissives; - - emissives.resize(0); - rigged_emissives.resize(0); - pbr_emissives.resize(0); - pbr_rigged_emissives.resize(0); - - bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE - || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE; - - bool disable_cull = is_particle_or_hud_particle; - LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0); - - LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA]; - - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) - { - LLDrawInfo& params = **k; - if ((bool)params.mAvatar != rigged) - { - continue; - } - - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch"); - - LLRenderPass::applyModelMatrix(params); - - LLMaterial* mat = NULL; - LLGLTFMaterial *gltf_mat = params.mGLTFMaterial; - - LLGLDisable cull_face(gltf_mat && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0); - - if (gltf_mat && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) - { - target_shader = pbr_shader; - if (params.mAvatar != nullptr) - { - target_shader = target_shader->mRiggedVariant; - } - - // shader must be bound before LLGLTFMaterial::bind - if (current_shader != target_shader) - { - gPipeline.bindDeferredShaderFast(*target_shader); - } - - params.mGLTFMaterial->bind(params.mTexture); - } - else - { - mat = LLPipeline::sRenderingHUDs ? nullptr : params.mMaterial; - - if (params.mFullbright) - { - // Turn off lighting if it hasn't already been so. - if (light_enabled || !initialized_lighting) - { - initialized_lighting = true; - target_shader = fullbright_shader; - - light_enabled = false; - } - } - // Turn on lighting if it isn't already. - else if (!light_enabled || !initialized_lighting) - { - initialized_lighting = true; - target_shader = simple_shader; - light_enabled = true; - } - - if (LLPipeline::sRenderingHUDs) - { - target_shader = fullbright_shader; - } - else if (mat) - { - U32 mask = params.mShaderMask; - - llassert(mask < LLMaterial::SHADER_COUNT); - target_shader = &(gDeferredMaterialProgram[mask]); - } - else if (!params.mFullbright) - { - target_shader = simple_shader; - } - else - { - target_shader = fullbright_shader; - } - - if (params.mAvatar != nullptr) - { - llassert(target_shader->mRiggedVariant != nullptr); - target_shader = target_shader->mRiggedVariant; - } - - if (current_shader != target_shader) - {// If we need shaders, and we're not ALREADY using the proper shader, then bind it - // (this way we won't rebind shaders unnecessarily). - gPipeline.bindDeferredShaderFast(*target_shader); - - if (params.mFullbright) - { // make sure the bind the exposure map for fullbright shaders so they can cancel out exposure - S32 channel = target_shader->enableTexture(LLShaderMgr::EXPOSURE_MAP); - if (channel > -1) - { - gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap); - } - } - } - - LLVector4 spec_color(1, 1, 1, 1); - F32 env_intensity = 0.0f; - F32 brightness = 1.0f; - - // We have a material. Supply the appropriate data here. - if (mat) - { - spec_color = params.mSpecColor; - env_intensity = params.mEnvIntensity; - brightness = params.mFullbright ? 1.f : 0.f; - } - - if (current_shader) - { - current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]); - current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity); - current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness); - } - } - - if (params.mAvatar != nullptr) - { - if (lastAvatar != params.mAvatar || - lastMeshId != params.mSkinInfo->mHash || - lastAvatarShader != LLGLSLShader::sCurBoundShaderPtr) - { - if (!uploadMatrixPalette(params)) - { - continue; - } - lastAvatar = params.mAvatar; - lastMeshId = params.mSkinInfo->mHash; - lastAvatarShader = LLGLSLShader::sCurBoundShaderPtr; - } - } - - bool tex_setup = TexSetup(¶ms, (mat != nullptr)); - - { - gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); - - bool reset_minimum_alpha = false; - if (!LLPipeline::sImpostorRender && - params.mBlendFuncDst != LLRender::BF_SOURCE_ALPHA && - params.mBlendFuncSrc != LLRender::BF_SOURCE_ALPHA) - { // this draw call has a custom blend function that may require rendering of "invisible" fragments - current_shader->setMinimumAlpha(0.f); - reset_minimum_alpha = true; - } - - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); - - if (reset_minimum_alpha) - { - current_shader->setMinimumAlpha(MINIMUM_ALPHA); - } - } - - // If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow). Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha. - if (getType() != LLDrawPool::POOL_ALPHA_PRE_WATER && - params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE)) - { - if (params.mAvatar != nullptr) - { - if (params.mGLTFMaterial.isNull()) - { - rigged_emissives.push_back(¶ms); - } - else - { - pbr_rigged_emissives.push_back(¶ms); - } - } - else - { - if (params.mGLTFMaterial.isNull()) - { - emissives.push_back(¶ms); - } - else - { - pbr_emissives.push_back(¶ms); - } - } - } - - if (tex_setup) - { - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } - } - - // render emissive faces into alpha channel for bloom effects - if (!depth_only) - { - gPipeline.enableLightsDynamic(); - - // install glow-accumulating blend mode - // don't touch color, add to alpha (glow) - gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); - - bool rebind = false; - LLGLSLShader* lastShader = current_shader; - if (!emissives.empty()) - { - light_enabled = true; - renderEmissives(emissives); - rebind = true; - } - - if (!pbr_emissives.empty()) - { - light_enabled = true; - renderPbrEmissives(pbr_emissives); - rebind = true; - } - - if (!rigged_emissives.empty()) - { - light_enabled = true; - renderRiggedEmissives(rigged_emissives); - rebind = true; - } - - if (!pbr_rigged_emissives.empty()) - { - light_enabled = true; - renderRiggedPbrEmissives(pbr_rigged_emissives); - rebind = true; - } - - // restore our alpha blend mode - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - if (lastShader && rebind) - { - lastShader->bind(); - } - } - } - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - LLVertexBuffer::unbind(); - - if (!light_enabled) - { - gPipeline.enableLightsDynamic(); - } -} - -bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params) -{ - if (params.mAvatar.isNull()) - { - return false; - } - const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo); - U32 count = mpc.mMatrixPalette.size(); - - if (count == 0) - { - //skin info not loaded yet, don't render - return false; - } - - LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, - count, - false, - (GLfloat*)&(mpc.mGLMp[0])); - - return true; -} +/**
+ * @file lldrawpoolalpha.cpp
+ * @brief LLDrawPoolAlpha class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldrawpoolalpha.h"
+
+#include "llglheaders.h"
+#include "llviewercontrol.h"
+#include "llcriticaldamp.h"
+#include "llfasttimer.h"
+#include "llrender.h"
+
+#include "llcubemap.h"
+#include "llsky.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h" // For debugging
+#include "llviewerobjectlist.h" // For debugging
+#include "llviewerwindow.h"
+#include "pipeline.h"
+#include "llviewershadermgr.h"
+#include "llviewerregion.h"
+#include "lldrawpoolwater.h"
+#include "llspatialpartition.h"
+#include "llglcommonfunc.h"
+#include "llvoavatar.h"
+
+#include "llenvironment.h"
+
+bool LLDrawPoolAlpha::sShowDebugAlpha = false;
+
+#define current_shader (LLGLSLShader::sCurBoundShaderPtr)
+
+LLVector4 LLDrawPoolAlpha::sWaterPlane;
+
+// minimum alpha before discarding a fragment
+static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255
+
+// minimum alpha before discarding a fragment when rendering impostors
+static const F32 MINIMUM_IMPOSTOR_ALPHA = 0.1f;
+
+LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
+ LLRenderPass(type), target_shader(NULL),
+ mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF),
+ mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF)
+{
+
+}
+
+LLDrawPoolAlpha::~LLDrawPoolAlpha()
+{
+}
+
+
+void LLDrawPoolAlpha::prerender()
+{
+ mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
+
+ // TODO: is this even necessay? These are probably set to never discard
+ LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f);
+ LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f);
+}
+
+S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
+{
+ return 1;
+}
+
+// set some common parameters on the given shader to prepare for alpha rendering
+static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment, F32 water_sign)
+{
+ static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
+ F32 gamma = displayGamma;
+
+ static LLStaticHashedString waterSign("waterSign");
+
+ // Does this deferred shader need environment uniforms set such as sun_dir, etc. ?
+ // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering
+ // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms()
+ // i.e. shaders\class1\deferred\alphaF.glsl
+ if (deferredEnvironment)
+ {
+ shader->mCanBindFast = false;
+ }
+
+ shader->bind();
+ shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+
+ if (LLPipeline::sRenderingHUDs)
+ { // for HUD attachments, only the pre-water pass is executed and we never want to clip anything
+ LLVector4 near_clip(0, 0, -1, 0);
+ shader->uniform1f(waterSign, 1.f);
+ shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, near_clip.mV);
+ }
+ else
+ {
+ shader->uniform1f(waterSign, water_sign);
+ shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
+ }
+
+ if (LLPipeline::sImpostorRender)
+ {
+ shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA);
+ }
+ else
+ {
+ shader->setMinimumAlpha(MINIMUM_ALPHA);
+ }
+ if (textureGamma)
+ {
+ shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+ }
+
+ //also prepare rigged variant
+ if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
+ {
+ prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment, water_sign);
+ }
+}
+
+extern bool gCubeSnapshot;
+
+void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+
+ if (LLPipeline::isWaterClip() && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER)
+ { // don't render alpha objects on the other side of the water plane if water is opaque
+ return;
+ }
+
+ F32 water_sign = 1.f;
+
+ if (getType() == LLDrawPool::POOL_ALPHA_PRE_WATER)
+ {
+ water_sign = -1.f;
+ }
+
+ if (LLPipeline::sUnderWaterRender)
+ {
+ water_sign *= -1.f;
+ }
+
+ // prepare shaders
+ llassert(LLPipeline::sRenderDeferred);
+
+ emissive_shader = &gDeferredEmissiveProgram;
+ prepare_alpha_shader(emissive_shader, true, false, water_sign);
+
+ pbr_emissive_shader = &gPBRGlowProgram;
+ prepare_alpha_shader(pbr_emissive_shader, true, false, water_sign);
+
+
+ fullbright_shader =
+ (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram :
+ (LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram :
+ &gDeferredFullbrightAlphaMaskAlphaProgram;
+ prepare_alpha_shader(fullbright_shader, true, true, water_sign);
+
+ simple_shader =
+ (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
+ (LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram :
+ &gDeferredAlphaProgram;
+
+ prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms)
+
+ LLGLSLShader* materialShader = gDeferredMaterialProgram;
+ for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
+ {
+ prepare_alpha_shader(&materialShader[i], false, true, water_sign);
+ }
+
+ pbr_shader =
+ (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram :
+ &gDeferredPBRAlphaProgram;
+
+ prepare_alpha_shader(pbr_shader, false, true, water_sign);
+
+ // explicitly unbind here so render loop doesn't make assumptions about the last shader
+ // already being setup for rendering
+ LLGLSLShader::unbind();
+
+ if (!LLPipeline::sRenderingHUDs)
+ {
+ // first pass, render rigged objects only and render to depth buffer
+ forwardRender(true);
+ }
+
+ // second pass, regular forward alpha rendering
+ forwardRender();
+
+ // final pass, render to depth for depth of field effects
+ if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot && !LLPipeline::sRenderingHUDs && getType() == LLDrawPool::POOL_ALPHA_POST_WATER)
+ {
+ //update depth buffer sampler
+ simple_shader = fullbright_shader = &gDeferredFullbrightAlphaMaskProgram;
+
+ simple_shader->bind();
+ simple_shader->setMinimumAlpha(0.33f);
+
+ // mask off color buffer writes as we're only writing to depth buffer
+ gGL.setColorMask(false, false);
+
+ // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+ // We don't want the nearly invisible objects to cause of DoF effects
+ renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2,
+ true); // <--- discard mostly transparent faces
+
+ gGL.setColorMask(true, false);
+ }
+}
+
+void LLDrawPoolAlpha::forwardRender(bool rigged)
+{
+ gPipeline.enableLightsDynamic();
+
+ LLGLSPipelineAlpha gls_pipeline_alpha;
+
+ //enable writing to alpha for emissive effects
+ gGL.setColorMask(true, true);
+
+ bool write_depth = rigged ||
+ LLDrawPoolWater::sSkipScreenCopy
+ // we want depth written so that rendered alpha will
+ // contribute to the alpha mask used for impostors
+ || LLPipeline::sImpostorRenderAlphaDepthPass
+ || getType() == LLDrawPoolAlpha::POOL_ALPHA_PRE_WATER; // needed for accurate water fog
+
+
+ LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
+
+ mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend
+ mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
+ mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression
+ mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
+ gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
+ // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+ // We don't want the nearly invisible objects to cause of DoF effects
+ renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);
+
+ gGL.setColorMask(true, false);
+
+ if (!rigged)
+ { //render "highlight alpha" on final non-rigged pass
+ // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender"
+ // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state
+ // variables above are still in scope
+ renderDebugAlpha();
+ }
+}
+
+void LLDrawPoolAlpha::renderDebugAlpha()
+{
+ if (sShowDebugAlpha)
+ {
+ gHighlightProgram.bind();
+ gGL.diffuseColor4f(1, 0, 0, 1);
+ gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::getSmokeImage());
+
+
+ renderAlphaHighlight();
+
+ pushUntexturedBatches(LLRenderPass::PASS_ALPHA_MASK);
+ pushUntexturedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE);
+
+ // Material alpha mask
+ gGL.diffuseColor4f(0, 0, 1, 1);
+ pushUntexturedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK);
+ pushUntexturedBatches(LLRenderPass::PASS_NORMMAP_MASK);
+ pushUntexturedBatches(LLRenderPass::PASS_SPECMAP_MASK);
+ pushUntexturedBatches(LLRenderPass::PASS_NORMSPEC_MASK);
+ pushUntexturedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
+ pushUntexturedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK);
+
+ gGL.diffuseColor4f(0, 1, 0, 1);
+ pushUntexturedBatches(LLRenderPass::PASS_INVISIBLE);
+
+ gHighlightProgram.mRiggedVariant->bind();
+ gGL.diffuseColor4f(1, 0, 0, 1);
+
+ pushRiggedBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, false);
+ pushRiggedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE_RIGGED, false);
+
+ // Material alpha mask
+ gGL.diffuseColor4f(0, 0, 1, 1);
+ pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, false);
+ pushRiggedBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, false);
+ pushRiggedBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, false);
+ pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, false);
+ pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, false);
+ pushRiggedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK_RIGGED, false);
+
+ gGL.diffuseColor4f(0, 1, 0, 1);
+ pushRiggedBatches(LLRenderPass::PASS_INVISIBLE_RIGGED, false);
+ LLGLSLShader::sCurBoundShaderPtr->unbind();
+ }
+}
+
+void LLDrawPoolAlpha::renderAlphaHighlight()
+{
+ for (int pass = 0; pass < 2; ++pass)
+ { //two passes, one rigged and one not
+ LLVOAvatar* lastAvatar = nullptr;
+ U64 lastMeshId = 0;
+
+ LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups();
+ LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups();
+
+ for (LLCullResult::sg_iterator i = begin; i != end; ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (group->getSpatialPartition()->mRenderByGroup &&
+ !group->isDead())
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass
+
+ for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
+ {
+ LLDrawInfo& params = **k;
+
+ bool rigged = (params.mAvatar != nullptr);
+ gHighlightProgram.bind(rigged);
+ gGL.diffuseColor4f(1, 0, 0, 1);
+
+ if (rigged)
+ {
+ if (lastAvatar != params.mAvatar ||
+ lastMeshId != params.mSkinInfo->mHash)
+ {
+ if (!uploadMatrixPalette(params))
+ {
+ continue;
+ }
+ lastAvatar = params.mAvatar;
+ lastMeshId = params.mSkinInfo->mHash;
+ }
+ }
+
+ LLRenderPass::applyModelMatrix(params);
+ params.mVertexBuffer->setBuffer();
+ params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+ }
+ }
+ }
+ }
+
+ // make sure static version of highlight shader is bound before returning
+ gHighlightProgram.bind();
+}
+
+inline bool IsFullbright(LLDrawInfo& params)
+{
+ return params.mFullbright;
+}
+
+inline bool IsMaterial(LLDrawInfo& params)
+{
+ return params.mMaterial != nullptr;
+}
+
+inline bool IsEmissive(LLDrawInfo& params)
+{
+ return params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE);
+}
+
+inline void Draw(LLDrawInfo* draw, U32 mask)
+{
+ draw->mVertexBuffer->setBuffer();
+ LLRenderPass::applyModelMatrix(*draw);
+ draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
+}
+
+bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material)
+{
+ bool tex_setup = false;
+
+ if (draw->mGLTFMaterial)
+ {
+ if (draw->mTextureMatrix)
+ {
+ tex_setup = true;
+ gGL.getTexUnit(0)->activate();
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix);
+ gPipeline.mTextureMatrixOps++;
+ }
+ }
+ else
+ {
+ if (!LLPipeline::sRenderingHUDs && use_material && current_shader)
+ {
+ if (draw->mNormalMap)
+ {
+ current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap);
+ }
+
+ if (draw->mSpecularMap)
+ {
+ current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap);
+ }
+ }
+ else if (current_shader == simple_shader || current_shader == simple_shader->mRiggedVariant)
+ {
+ current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);
+ current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
+ }
+ if (draw->mTextureList.size() > 1)
+ {
+ for (U32 i = 0; i < draw->mTextureList.size(); ++i)
+ {
+ if (draw->mTextureList[i].notNull())
+ {
+ gGL.getTexUnit(i)->bindFast(draw->mTextureList[i]);
+ }
+ }
+ }
+ else
+ { //not batching textures or batch has only 1 texture -- might need a texture matrix
+ if (draw->mTexture.notNull())
+ {
+ if (use_material)
+ {
+ current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, draw->mTexture);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bindFast(draw->mTexture);
+ }
+
+ if (draw->mTextureMatrix)
+ {
+ tex_setup = true;
+ gGL.getTexUnit(0)->activate();
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix);
+ gPipeline.mTextureMatrixOps++;
+ }
+ }
+ else
+ {
+ gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE);
+ }
+ }
+ }
+
+ return tex_setup;
+}
+
+void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup)
+{
+ if (tex_setup)
+ {
+ gGL.getTexUnit(0)->activate();
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ }
+}
+
+void LLDrawPoolAlpha::drawEmissive(LLDrawInfo* draw)
+{
+ LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
+ draw->mVertexBuffer->setBuffer();
+ draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
+}
+
+
+void LLDrawPoolAlpha::renderEmissives(std::vector<LLDrawInfo*>& emissives)
+{
+ emissive_shader->bind();
+ emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
+
+ for (LLDrawInfo* draw : emissives)
+ {
+ bool tex_setup = TexSetup(draw, false);
+ drawEmissive(draw);
+ RestoreTexSetup(tex_setup);
+ }
+}
+
+void LLDrawPoolAlpha::renderPbrEmissives(std::vector<LLDrawInfo*>& emissives)
+{
+ pbr_emissive_shader->bind();
+
+ for (LLDrawInfo* draw : emissives)
+ {
+ llassert(draw->mGLTFMaterial);
+ LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0);
+ draw->mGLTFMaterial->bind(draw->mTexture);
+ draw->mVertexBuffer->setBuffer();
+ draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
+ }
+}
+
+void LLDrawPoolAlpha::renderRiggedEmissives(std::vector<LLDrawInfo*>& emissives)
+{
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter
+ LLGLSLShader* shader = emissive_shader->mRiggedVariant;
+ shader->bind();
+ shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
+
+ LLVOAvatar* lastAvatar = nullptr;
+ U64 lastMeshId = 0;
+
+ for (LLDrawInfo* draw : emissives)
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("Emissives");
+
+ bool tex_setup = TexSetup(draw, false);
+ if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash)
+ {
+ if (!uploadMatrixPalette(*draw))
+ { // failed to upload matrix palette, skip rendering
+ continue;
+ }
+ lastAvatar = draw->mAvatar;
+ lastMeshId = draw->mSkinInfo->mHash;
+ }
+ drawEmissive(draw);
+ RestoreTexSetup(tex_setup);
+ }
+}
+
+void LLDrawPoolAlpha::renderRiggedPbrEmissives(std::vector<LLDrawInfo*>& emissives)
+{
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter
+ pbr_emissive_shader->bind(true);
+
+ LLVOAvatar* lastAvatar = nullptr;
+ U64 lastMeshId = 0;
+
+ for (LLDrawInfo* draw : emissives)
+ {
+ if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash)
+ {
+ if (!uploadMatrixPalette(*draw))
+ { // failed to upload matrix palette, skip rendering
+ continue;
+ }
+ lastAvatar = draw->mAvatar;
+ lastMeshId = draw->mSkinInfo->mHash;
+ }
+
+ LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0);
+ draw->mGLTFMaterial->bind(draw->mTexture);
+ draw->mVertexBuffer->setBuffer();
+ draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
+ }
+}
+
+void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
+ bool initialized_lighting = false;
+ bool light_enabled = true;
+
+ LLVOAvatar* lastAvatar = nullptr;
+ U64 lastMeshId = 0;
+ LLGLSLShader* lastAvatarShader = nullptr;
+
+ LLCullResult::sg_iterator begin;
+ LLCullResult::sg_iterator end;
+
+ if (rigged)
+ {
+ begin = gPipeline.beginRiggedAlphaGroups();
+ end = gPipeline.endRiggedAlphaGroups();
+ }
+ else
+ {
+ begin = gPipeline.beginAlphaGroups();
+ end = gPipeline.endAlphaGroups();
+ }
+
+ LLEnvironment& env = LLEnvironment::instance();
+ F32 water_height = env.getWaterHeight();
+
+ bool above_water = getType() == LLDrawPool::POOL_ALPHA_POST_WATER;
+ if (LLPipeline::sUnderWaterRender)
+ {
+ above_water = !above_water;
+ }
+
+
+ for (LLCullResult::sg_iterator i = begin; i != end; ++i)
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");
+ LLSpatialGroup* group = *i;
+ llassert(group);
+ llassert(group->getSpatialPartition());
+
+ if (group->getSpatialPartition()->mRenderByGroup &&
+ !group->isDead())
+ {
+
+ LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
+ const LLVector4a* ext = bridge ? bridge->getSpatialExtents() : group->getExtents();
+
+ if (!LLPipeline::sRenderingHUDs) // ignore above/below water for HUD render
+ {
+ if (above_water)
+ { // reject any spatial groups that have no part above water
+ if (ext[1].getF32ptr()[2] < water_height)
+ {
+ continue;
+ }
+ }
+ else
+ { // reject any spatial groups that he no part below water
+ if (ext[0].getF32ptr()[2] > water_height)
+ {
+ continue;
+ }
+ }
+ }
+
+ static std::vector<LLDrawInfo*> emissives;
+ static std::vector<LLDrawInfo*> rigged_emissives;
+ static std::vector<LLDrawInfo*> pbr_emissives;
+ static std::vector<LLDrawInfo*> pbr_rigged_emissives;
+
+ emissives.resize(0);
+ rigged_emissives.resize(0);
+ pbr_emissives.resize(0);
+ pbr_rigged_emissives.resize(0);
+
+ bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE
+ || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
+
+ bool disable_cull = is_particle_or_hud_particle;
+ LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0);
+
+ LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA];
+
+ for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
+ {
+ LLDrawInfo& params = **k;
+ if ((bool)params.mAvatar != rigged)
+ {
+ continue;
+ }
+
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch");
+
+ LLRenderPass::applyModelMatrix(params);
+
+ LLMaterial* mat = NULL;
+ LLGLTFMaterial *gltf_mat = params.mGLTFMaterial;
+
+ LLGLDisable cull_face(gltf_mat && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0);
+
+ if (gltf_mat && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND)
+ {
+ target_shader = pbr_shader;
+ if (params.mAvatar != nullptr)
+ {
+ target_shader = target_shader->mRiggedVariant;
+ }
+
+ // shader must be bound before LLGLTFMaterial::bind
+ if (current_shader != target_shader)
+ {
+ gPipeline.bindDeferredShaderFast(*target_shader);
+ }
+
+ params.mGLTFMaterial->bind(params.mTexture);
+ }
+ else
+ {
+ mat = LLPipeline::sRenderingHUDs ? nullptr : params.mMaterial;
+
+ if (params.mFullbright)
+ {
+ // Turn off lighting if it hasn't already been so.
+ if (light_enabled || !initialized_lighting)
+ {
+ initialized_lighting = true;
+ target_shader = fullbright_shader;
+
+ light_enabled = false;
+ }
+ }
+ // Turn on lighting if it isn't already.
+ else if (!light_enabled || !initialized_lighting)
+ {
+ initialized_lighting = true;
+ target_shader = simple_shader;
+ light_enabled = true;
+ }
+
+ if (LLPipeline::sRenderingHUDs)
+ {
+ target_shader = fullbright_shader;
+ }
+ else if (mat)
+ {
+ U32 mask = params.mShaderMask;
+
+ llassert(mask < LLMaterial::SHADER_COUNT);
+ target_shader = &(gDeferredMaterialProgram[mask]);
+ }
+ else if (!params.mFullbright)
+ {
+ target_shader = simple_shader;
+ }
+ else
+ {
+ target_shader = fullbright_shader;
+ }
+
+ if (params.mAvatar != nullptr)
+ {
+ llassert(target_shader->mRiggedVariant != nullptr);
+ target_shader = target_shader->mRiggedVariant;
+ }
+
+ if (current_shader != target_shader)
+ {// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+ // (this way we won't rebind shaders unnecessarily).
+ gPipeline.bindDeferredShaderFast(*target_shader);
+
+ if (params.mFullbright)
+ { // make sure the bind the exposure map for fullbright shaders so they can cancel out exposure
+ S32 channel = target_shader->enableTexture(LLShaderMgr::EXPOSURE_MAP);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap);
+ }
+ }
+ }
+
+ LLVector4 spec_color(1, 1, 1, 1);
+ F32 env_intensity = 0.0f;
+ F32 brightness = 1.0f;
+
+ // We have a material. Supply the appropriate data here.
+ if (mat)
+ {
+ spec_color = params.mSpecColor;
+ env_intensity = params.mEnvIntensity;
+ brightness = params.mFullbright ? 1.f : 0.f;
+ }
+
+ if (current_shader)
+ {
+ current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]);
+ current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity);
+ current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness);
+ }
+ }
+
+ if (params.mAvatar != nullptr)
+ {
+ if (lastAvatar != params.mAvatar ||
+ lastMeshId != params.mSkinInfo->mHash ||
+ lastAvatarShader != LLGLSLShader::sCurBoundShaderPtr)
+ {
+ if (!uploadMatrixPalette(params))
+ {
+ continue;
+ }
+ lastAvatar = params.mAvatar;
+ lastMeshId = params.mSkinInfo->mHash;
+ lastAvatarShader = LLGLSLShader::sCurBoundShaderPtr;
+ }
+ }
+
+ bool tex_setup = TexSetup(¶ms, (mat != nullptr));
+
+ {
+ gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
+
+ bool reset_minimum_alpha = false;
+ if (!LLPipeline::sImpostorRender &&
+ params.mBlendFuncDst != LLRender::BF_SOURCE_ALPHA &&
+ params.mBlendFuncSrc != LLRender::BF_SOURCE_ALPHA)
+ { // this draw call has a custom blend function that may require rendering of "invisible" fragments
+ current_shader->setMinimumAlpha(0.f);
+ reset_minimum_alpha = true;
+ }
+
+ params.mVertexBuffer->setBuffer();
+ params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+
+ if (reset_minimum_alpha)
+ {
+ current_shader->setMinimumAlpha(MINIMUM_ALPHA);
+ }
+ }
+
+ // If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow). Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha.
+ if (getType() != LLDrawPool::POOL_ALPHA_PRE_WATER &&
+ params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE))
+ {
+ if (params.mAvatar != nullptr)
+ {
+ if (params.mGLTFMaterial.isNull())
+ {
+ rigged_emissives.push_back(¶ms);
+ }
+ else
+ {
+ pbr_rigged_emissives.push_back(¶ms);
+ }
+ }
+ else
+ {
+ if (params.mGLTFMaterial.isNull())
+ {
+ emissives.push_back(¶ms);
+ }
+ else
+ {
+ pbr_emissives.push_back(¶ms);
+ }
+ }
+ }
+
+ if (tex_setup)
+ {
+ gGL.getTexUnit(0)->activate();
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ }
+ }
+
+ // render emissive faces into alpha channel for bloom effects
+ if (!depth_only)
+ {
+ gPipeline.enableLightsDynamic();
+
+ // install glow-accumulating blend mode
+ // don't touch color, add to alpha (glow)
+ gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE);
+
+ bool rebind = false;
+ LLGLSLShader* lastShader = current_shader;
+ if (!emissives.empty())
+ {
+ light_enabled = true;
+ renderEmissives(emissives);
+ rebind = true;
+ }
+
+ if (!pbr_emissives.empty())
+ {
+ light_enabled = true;
+ renderPbrEmissives(pbr_emissives);
+ rebind = true;
+ }
+
+ if (!rigged_emissives.empty())
+ {
+ light_enabled = true;
+ renderRiggedEmissives(rigged_emissives);
+ rebind = true;
+ }
+
+ if (!pbr_rigged_emissives.empty())
+ {
+ light_enabled = true;
+ renderRiggedPbrEmissives(pbr_rigged_emissives);
+ rebind = true;
+ }
+
+ // restore our alpha blend mode
+ gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
+ if (lastShader && rebind)
+ {
+ lastShader->bind();
+ }
+ }
+ }
+ }
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ LLVertexBuffer::unbind();
+
+ if (!light_enabled)
+ {
+ gPipeline.enableLightsDynamic();
+ }
+}
+
+bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)
+{
+ if (params.mAvatar.isNull())
+ {
+ return false;
+ }
+ const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo);
+ U32 count = mpc.mMatrixPalette.size();
+
+ if (count == 0)
+ {
+ //skin info not loaded yet, don't render
+ return false;
+ }
+
+ LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+ count,
+ false,
+ (GLfloat*)&(mpc.mGLMp[0]));
+
+ return true;
+}
|
