From 74c8b028d42a8c5b080bb861e427f38cedd4ad7c Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 15 Dec 2023 18:26:14 +0100 Subject: SL-20743 Use LLMutex in LLImageBase for internal data thread-safety --- indra/newview/lldrawpoolbump.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'indra/newview/lldrawpoolbump.cpp') diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index a0ce0ef6cf..77a196380b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -849,11 +849,14 @@ void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTextu void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image) { + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(nrm_image); + U8* nrm_data = nrm_image->getData(); S32 resX = src->getWidth(); S32 resY = src->getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); S32 src_cmp = src->getComponents(); @@ -911,6 +914,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLImageDataSharedLock lock(src); bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); bump_image_map_t::iterator iter = entries_list.find(source_asset_id); @@ -933,7 +937,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI U8* dst_data = dst_image->getData(); S32 dst_data_size = dst_image->getDataSize(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); S32 src_data_size = src->getDataSize(); S32 src_components = src->getComponents(); -- cgit v1.2.3 From b2c271367296744fbbe2262e55d0ea4f8f5ccdc9 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 20 Feb 2024 00:50:39 +0100 Subject: Convert BOOL to bool in llrender --- indra/newview/lldrawpoolbump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/lldrawpoolbump.cpp') diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 77a196380b..04b56f5055 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -1104,7 +1104,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI // Note: bump will still point at GPU copy of dst_image bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA); LLGLuint tex_name; - img->createGLTexture(0, nullptr, 0, 0, true, &tex_name); + img->createGLTexture(0, nullptr, false, 0, true, &tex_name); // point render target at empty buffer sRenderTarget.setColorAttachment(img, tex_name); -- cgit v1.2.3 From 60d3dd98a44230c21803c1606552ee098ed9fa7c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 21 Feb 2024 21:05:14 +0100 Subject: Convert remaining BOOL to bool --- indra/newview/lldrawpoolbump.cpp | 56 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'indra/newview/lldrawpoolbump.cpp') diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 04b56f5055..16efb36ba6 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -77,7 +77,7 @@ static LLGLSLShader* shader = NULL; static S32 cube_channel = -1; static S32 diffuse_channel = -1; static S32 bump_channel = -1; -static BOOL shiny = FALSE; +static bool shiny = false; // Enabled after changing LLViewerTexture::mNeedsCreateTexture to an // LLAtomicBool; this should work just fine, now. HB @@ -165,7 +165,7 @@ void LLStandardBumpmap::addstandard() gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id)); gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLGLTexture::LOCAL) ; - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL, NULL ); + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, true, false, NULL, NULL ); gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->forceToSaveRawImage(0, 30.f) ; LLStandardBumpmap::sStandardBumpmapCount++; } @@ -198,7 +198,7 @@ void LLStandardBumpmap::destroyGL() LLDrawPoolBump::LLDrawPoolBump() : LLRenderPass(LLDrawPool::POOL_BUMP) { - shiny = FALSE; + shiny = false; } @@ -354,7 +354,7 @@ void LLDrawPoolBump::beginFullbrightShiny() diffuse_channel = 0; } - shiny = TRUE; + shiny = true; } void LLDrawPoolBump::renderFullbrightShiny() @@ -406,7 +406,7 @@ void LLDrawPoolBump::endFullbrightShiny() diffuse_channel = -1; cube_channel = 0; - shiny = FALSE; + shiny = false; } void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, bool texture = true) @@ -426,7 +426,7 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, bool texture = // static -BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) +bool LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) { U8 bump_code = params.mBump; @@ -434,7 +434,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) } //static -BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel) +bool LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel) { const LLTextureEntry* te = face->getTextureEntry(); if (te) @@ -443,11 +443,11 @@ BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel) return bindBumpMap(bump_code, face->getTexture(), channel); } - return FALSE; + return false; } //static -BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, S32 channel) +bool LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, S32 channel) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //Note: texture atlas does not support bump texture now. @@ -455,7 +455,7 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, S32 cha if(!tex) { //if the texture is not a fetched texture - return FALSE; + return false; } LLViewerTexture* bump = NULL; @@ -491,10 +491,10 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, S32 cha gGL.getTexUnit(channel)->bind(bump); } - return TRUE; + return true; } - return FALSE; + return false; } //static @@ -549,7 +549,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - shiny = TRUE; + shiny = true; for (int i = 0; i < 2; ++i) { bool rigged = i == 1; @@ -597,7 +597,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) gGL.getTexUnit(0)->activate(); } - shiny = FALSE; + shiny = false; } @@ -705,12 +705,12 @@ void LLBumpImageList::updateImages() LLViewerTexture* image = curiter->second; if( image ) { - BOOL destroy = TRUE; + bool destroy = true; if( image->hasGLTexture()) { if( image->getBoundRecently() ) { - destroy = FALSE; + destroy = false; } else { @@ -732,12 +732,12 @@ void LLBumpImageList::updateImages() LLViewerTexture* image = curiter->second; if( image ) { - BOOL destroy = TRUE; + bool destroy = true; if( image->hasGLTexture()) { if( image->getBoundRecently() ) { - destroy = FALSE; + destroy = false; } else { @@ -764,7 +764,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText LLViewerTexture* bump = NULL; bump_image_map_t* entries_list = NULL; - void (*callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) = NULL; + void (*callback_func)( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) = NULL; switch( bump_code ) { @@ -788,7 +788,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText } else { - (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( TRUE ); + (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( true ); bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image } @@ -799,7 +799,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText //(LLPipeline::sRenderDeferred && bump->getComponents() != 4)) { src_image->setBoostLevel(LLGLTexture::BOOST_BUMP) ; - src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL ); + src_image->setLoadedCallback( callback_func, 0, true, false, new LLUUID(src_image->getID()), NULL ); src_image->forceToSaveRawImage(0) ; } } @@ -809,7 +809,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText // static -void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +void LLBumpImageList::onSourceBrightnessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLUUID* source_asset_id = (LLUUID*)userdata; @@ -821,7 +821,7 @@ void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTex } // static -void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +void LLBumpImageList::onSourceDarknessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) { LLUUID* source_asset_id = (LLUUID*)userdata; LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_DARKNESS ); @@ -831,7 +831,7 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTextu } } -void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +void LLBumpImageList::onSourceStandardLoaded( bool success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) { if (success && LLPipeline::sRenderDeferred) { @@ -906,7 +906,7 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr } // static -void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) +void LLBumpImageList::onSourceLoaded( bool success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) { LL_PROFILE_ZONE_SCOPED; @@ -925,7 +925,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI iter->second->getWidth() != src->getWidth() || iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution { //make sure an entry exists for this image - entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(TRUE); + entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(true); iter = entries_list.find(src_vi->getID()); } } @@ -1090,7 +1090,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI bump_ptr->ref(); auto create_func = [=]() { - img->setUseMipMaps(TRUE); + img->setUseMipMaps(true); // upload dst_image to GPU (greyscale in red channel) img->setExplicitFormat(GL_RED, GL_RED); @@ -1116,7 +1116,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI LLGLDepthTest depth(GL_FALSE); LLGLDisable cull(GL_CULL_FACE); LLGLDisable blend(GL_BLEND); - gGL.setColorMask(TRUE, TRUE); + gGL.setColorMask(true, true); gNormalMapGenProgram.bind(); -- cgit v1.2.3 From 7fc5f7e649c564fa8479a72a45459d0cc427d0f8 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Thu, 2 May 2024 10:57:39 -0500 Subject: #1354 Make coroutines use LLCoros::Mutex instead of LLMutex (#1356) * #1354 Make coroutines use LLCoros::Mutex instead of LLMutex * #1354 Fix some more unsafe coroutine executions. * #1354 Implement changes requested by Nat --- indra/newview/lldrawpoolbump.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview/lldrawpoolbump.cpp') diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 24df11c158..518310476b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -699,6 +699,8 @@ void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32 void LLBumpImageList::updateImages() { + llassert(LLCoros::on_main_thread_main_coro()); // This code is not thread safe + for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); ) { LLViewerTexture* image = iter->second; -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/newview/lldrawpoolbump.cpp | 2608 +++++++++++++++++++------------------- 1 file changed, 1304 insertions(+), 1304 deletions(-) (limited to 'indra/newview/lldrawpoolbump.cpp') diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 28a1077177..e26d98789e 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -1,1304 +1,1304 @@ -/** - * @file lldrawpoolbump.cpp - * @brief LLDrawPoolBump class implementation - * - * $LicenseInfo:firstyear=2003&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 "lldrawpoolbump.h" - -#include "llstl.h" -#include "llviewercontrol.h" -#include "lldir.h" -#include "m3math.h" -#include "m4math.h" -#include "v4math.h" -#include "llglheaders.h" -#include "llrender.h" - -#include "llcubemap.h" -#include "lldrawable.h" -#include "llface.h" -#include "llsky.h" -#include "llstartup.h" -#include "lltextureentry.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" -#include "pipeline.h" -#include "llspatialpartition.h" -#include "llviewershadermgr.h" -#include "llmodel.h" - -//#include "llimagebmp.h" -//#include "../tools/imdebug/imdebug.h" - -// static -LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT]; -LL::WorkQueue::weak_t LLBumpImageList::sMainQueue; -LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue; -LLRenderTarget LLBumpImageList::sRenderTarget; - -// static -U32 LLStandardBumpmap::sStandardBumpmapCount = 0; - -// static -LLBumpImageList gBumpImageList; - -const S32 STD_BUMP_LATEST_FILE_VERSION = 1; - -const U32 VERTEX_MASK_SHINY = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; -const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; - -U32 LLDrawPoolBump::sVertexMask = VERTEX_MASK_SHINY; - - -static LLGLSLShader* shader = NULL; -static S32 cube_channel = -1; -static S32 diffuse_channel = -1; -static S32 bump_channel = -1; -static bool shiny = false; - -// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an -// LLAtomicBool; this should work just fine, now. HB -#define LL_BUMPLIST_MULTITHREADED 1 - - -// static -void LLStandardBumpmap::shutdown() -{ - LLStandardBumpmap::destroyGL(); -} - -// static -void LLStandardBumpmap::restoreGL() -{ - addstandard(); -} - -// static -void LLStandardBumpmap::addstandard() -{ - if(!gTextureList.isInitialized()) - { - //Note: loading pre-configuration sometimes triggers this call. - //But it is safe to return here because bump images will be reloaded during initialization later. - return ; - } - - if (LLStartUp::getStartupState() < STATE_SEED_CAP_GRANTED) - { - // Not ready, need caps for images - return; - } - - // can't assert; we destroyGL and restoreGL a lot during *first* startup, which populates this list already, THEN we explicitly init the list as part of *normal* startup. Sigh. So clear the list every time before we (re-)add the standard bumpmaps. - //llassert( LLStandardBumpmap::sStandardBumpmapCount == 0 ); - clear(); - LL_INFOS() << "Adding standard bumpmaps." << LL_ENDL; - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("None"); // BE_NO_BUMP - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Brightness"); // BE_BRIGHTNESS - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness"); // BE_DARKNESS - - std::string file_name = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "std_bump.ini" ); - LLFILE* file = LLFile::fopen( file_name, "rt" ); /*Flawfinder: ignore*/ - if( !file ) - { - LL_WARNS() << "Could not open std_bump <" << file_name << ">" << LL_ENDL; - return; - } - - S32 file_version = 0; - - S32 fields_read = fscanf( file, "LLStandardBumpmap version %d", &file_version ); - if( fields_read != 1 ) - { - LL_WARNS() << "Bad LLStandardBumpmap header" << LL_ENDL; - return; - } - - if( file_version > STD_BUMP_LATEST_FILE_VERSION ) - { - LL_WARNS() << "LLStandardBumpmap has newer version (" << file_version << ") than viewer (" << STD_BUMP_LATEST_FILE_VERSION << ")" << LL_ENDL; - return; - } - - while( !feof(file) && (LLStandardBumpmap::sStandardBumpmapCount < (U32)TEM_BUMPMAP_COUNT) ) - { - // *NOTE: This buffer size is hard coded into scanf() below. - char label[2048] = ""; /* Flawfinder: ignore */ - char bump_image_id[2048] = ""; /* Flawfinder: ignore */ - fields_read = fscanf( /* Flawfinder: ignore */ - file, "\n%2047s %2047s", label, bump_image_id); - if( EOF == fields_read ) - { - break; - } - if( fields_read != 2 ) - { - LL_WARNS() << "Bad LLStandardBumpmap entry" << LL_ENDL; - return; - } - -// LL_INFOS() << "Loading bumpmap: " << bump_image_id << " from viewerart" << LL_ENDL; - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label; - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = - LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id)); - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLGLTexture::LOCAL) ; - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, true, false, NULL, NULL ); - gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->forceToSaveRawImage(0, 30.f) ; - LLStandardBumpmap::sStandardBumpmapCount++; - } - - fclose( file ); -} - -// static -void LLStandardBumpmap::clear() -{ - LL_INFOS() << "Clearing standard bumpmaps." << LL_ENDL; - for( U32 i = 0; i < LLStandardBumpmap::sStandardBumpmapCount; i++ ) - { - gStandardBumpmapList[i].mLabel.assign(""); - gStandardBumpmapList[i].mImage = NULL; - } - sStandardBumpmapCount = 0; -} - -// static -void LLStandardBumpmap::destroyGL() -{ - clear(); -} - - - -//////////////////////////////////////////////////////////////// - -LLDrawPoolBump::LLDrawPoolBump() -: LLRenderPass(LLDrawPool::POOL_BUMP) -{ - shiny = false; -} - - -void LLDrawPoolBump::prerender() -{ - mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); -} - -// static -S32 LLDrawPoolBump::numBumpPasses() -{ - return 1; -} - - -//static -void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) -{ - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if( cube_map && !LLPipeline::sReflectionProbesEnabled ) - { - if (shader ) - { - LLMatrix4 mat; - mat.initRows(LLVector4(gGLModelView+0), - LLVector4(gGLModelView+4), - LLVector4(gGLModelView+8), - LLVector4(gGLModelView+12)); - LLVector3 vec = LLVector3(gShinyOrigin) * mat; - LLVector4 vec4(vec, gShinyOrigin.mV[3]); - shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); - if (shader_level > 1) - { - cube_map->setMatrix(1); - // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for - // the cube map in the one pass shiny shaders - cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - cube_map->enableTexture(cube_channel); - diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - else - { - cube_map->setMatrix(0); - cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - diffuse_channel = -1; - cube_map->enable(cube_channel); - } - gGL.getTexUnit(cube_channel)->bind(cube_map); - gGL.getTexUnit(0)->activate(); - } - else - { - cube_channel = 0; - diffuse_channel = -1; - gGL.getTexUnit(0)->disable(); - cube_map->enable(0); - cube_map->setMatrix(0); - gGL.getTexUnit(0)->bind(cube_map); - } - } -} - -//static -void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) -{ - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if( cube_map && !LLPipeline::sReflectionProbesEnabled) - { - if (shader_level > 1) - { - shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - - if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) - { - if (diffuse_channel != 0) - { - shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - } - } - // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0 - // MAINT-755 - cube_map->disable(); - cube_map->restoreMatrix(); - } -} - -void LLDrawPoolBump::beginFullbrightShiny() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - - sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; - - // Second pass: environment map - shader = &gDeferredFullbrightShinyProgram; - if (LLPipeline::sRenderingHUDs) - { - shader = &gHUDFullbrightShinyProgram; - } - - if (mRigged) - { - llassert(shader->mRiggedVariant); - shader = shader->mRiggedVariant; - } - - // bind exposure map so fullbright shader can cancel out exposure - S32 channel = shader->enableTexture(LLShaderMgr::EXPOSURE_MAP); - if (channel > -1) - { - gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap); - } - - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - - if (cube_map && !LLPipeline::sReflectionProbesEnabled) - { - // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for - // the cube map in the one pass shiny shaders - gGL.getTexUnit(1)->disable(); - cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - cube_map->enableTexture(cube_channel); - diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - - gGL.getTexUnit(cube_channel)->bind(cube_map); - gGL.getTexUnit(0)->activate(); - } - - { - LLMatrix4 mat; - mat.initRows(LLVector4(gGLModelView+0), - LLVector4(gGLModelView+4), - LLVector4(gGLModelView+8), - LLVector4(gGLModelView+12)); - shader->bind(); - - LLVector3 vec = LLVector3(gShinyOrigin) * mat; - LLVector4 vec4(vec, gShinyOrigin.mV[3]); - shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); - - if (LLPipeline::sReflectionProbesEnabled) - { - gPipeline.bindReflectionProbes(*shader); - } - else - { - gPipeline.setEnvMat(*shader); - } - } - - if (mShaderLevel > 1) - { //indexed texture rendering, channel 0 is always diffuse - diffuse_channel = 0; - } - - shiny = true; -} - -void LLDrawPoolBump::renderFullbrightShiny() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - - { - LLGLEnable blend_enable(GL_BLEND); - - if (mShaderLevel > 1) - { - if (mRigged) - { - LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, true, true); - } - else - { - LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, true, true); - } - } - else - { - if (mRigged) - { - LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED); - } - else - { - LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY); - } - } - } -} - -void LLDrawPoolBump::endFullbrightShiny() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; - if( cube_map && !LLPipeline::sReflectionProbesEnabled ) - { - cube_map->disable(); - if (shader->mFeatures.hasReflectionProbes) - { - gPipeline.unbindReflectionProbes(*shader); - } - shader->unbind(); - } - - diffuse_channel = -1; - cube_channel = 0; - shiny = false; -} - -void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, bool texture = true) -{ - LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; - - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) - { - LLDrawInfo& params = **k; - - applyModelMatrix(params); - - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); - } -} - - -// static -bool LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) -{ - U8 bump_code = params.mBump; - - return bindBumpMap(bump_code, params.mTexture, channel); -} - -//static -bool LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel) -{ - const LLTextureEntry* te = face->getTextureEntry(); - if (te) - { - U8 bump_code = te->getBumpmap(); - return bindBumpMap(bump_code, face->getTexture(), channel); - } - - return false; -} - -//static -bool LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, S32 channel) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - //Note: texture atlas does not support bump texture now. - LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ; - if(!tex) - { - //if the texture is not a fetched texture - return false; - } - - LLViewerTexture* bump = NULL; - - switch( bump_code ) - { - case BE_NO_BUMP: - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code ); - break; - - default: - if( bump_code < LLStandardBumpmap::sStandardBumpmapCount ) - { - bump = gStandardBumpmapList[bump_code].mImage; - gBumpImageList.addTextureStats(bump_code, tex->getID(), tex->getMaxVirtualSize()); - } - break; - } - - if (bump) - { - if (channel == -2) - { - gGL.getTexUnit(1)->bindFast(bump); - gGL.getTexUnit(0)->bindFast(bump); - } - else - { - // NOTE: do not use bindFast here (see SL-16222) - gGL.getTexUnit(channel)->bind(bump); - } - - return true; - } - - return false; -} - -//static -void LLDrawPoolBump::beginBump() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - sVertexMask = VERTEX_MASK_BUMP; - // Optional second pass: emboss bump map - stop_glerror(); - - shader = &gObjectBumpProgram; - - if (mRigged) - { - llassert(shader->mRiggedVariant); - shader = shader->mRiggedVariant; - } - - shader->bind(); - - gGL.setSceneBlendType(LLRender::BT_MULT_X2); - stop_glerror(); -} - -//static -void LLDrawPoolBump::renderBump(U32 pass) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL); - LLGLEnable blend(GL_BLEND); - gGL.diffuseColor4f(1,1,1,1); - /// Get rid of z-fighting with non-bump pass. - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); - pushBumpBatches(pass); -} - -//static -void LLDrawPoolBump::endBump(U32 pass) -{ - LLGLSLShader::unbind(); - - gGL.setSceneBlendType(LLRender::BT_ALPHA); -} - -S32 LLDrawPoolBump::getNumDeferredPasses() -{ - return 1; -} - -void LLDrawPoolBump::renderDeferred(S32 pass) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - - shiny = true; - for (int i = 0; i < 2; ++i) - { - bool rigged = i == 1; - gDeferredBumpProgram.bind(rigged); - diffuse_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - bump_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::BUMP_MAP); - gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE); - - U32 type = rigged ? LLRenderPass::PASS_BUMP_RIGGED : LLRenderPass::PASS_BUMP; - LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); - LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); - - LLVOAvatar* avatar = nullptr; - U64 skin = 0; - - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) - { - LLDrawInfo& params = **i; - - LLCullResult::increment_iterator(i, end); - - LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff); - LLDrawPoolBump::bindBumpMap(params, bump_channel); - - if (rigged) - { - if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash) - { - uploadMatrixPalette(params); - avatar = params.mAvatar; - skin = params.mSkinInfo->mHash; - } - pushBumpBatch(params, true, false); - } - else - { - pushBumpBatch(params, true, false); - } - } - - LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::BUMP_MAP); - LLGLSLShader::sCurBoundShaderPtr->unbind(); - gGL.getTexUnit(0)->activate(); - } - - shiny = false; -} - - -void LLDrawPoolBump::renderPostDeferred(S32 pass) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - - S32 num_passes = LLPipeline::sRenderingHUDs ? 1 : 2; // skip rigged pass when rendering HUDs - - for (int i = 0; i < num_passes; ++i) - { // two passes -- static and rigged - mRigged = (i == 1); - - // render shiny - beginFullbrightShiny(); - renderFullbrightShiny(); - endFullbrightShiny(); - - //render bump - beginBump(); - renderBump(LLRenderPass::PASS_POST_BUMP); - endBump(); - } -} - - -//////////////////////////////////////////////////////////////// -// List of bump-maps created from other textures. - - -//const LLUUID TEST_BUMP_ID("3d33eaf2-459c-6f97-fd76-5fce3fc29447"); - -void LLBumpImageList::init() -{ - llassert( mBrightnessEntries.size() == 0 ); - llassert( mDarknessEntries.size() == 0 ); - - LLStandardBumpmap::restoreGL(); - sMainQueue = LL::WorkQueue::getInstance("mainloop"); - sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader. -} - -void LLBumpImageList::clear() -{ - LL_INFOS() << "Clearing dynamic bumpmaps." << LL_ENDL; - // these will be re-populated on-demand - mBrightnessEntries.clear(); - mDarknessEntries.clear(); - - sRenderTarget.release(); - - LLStandardBumpmap::clear(); -} - -void LLBumpImageList::shutdown() -{ - clear(); - LLStandardBumpmap::shutdown(); -} - -void LLBumpImageList::destroyGL() -{ - clear(); - LLStandardBumpmap::destroyGL(); -} - -void LLBumpImageList::restoreGL() -{ - if(!gTextureList.isInitialized()) - { - //safe to return here because bump images will be reloaded during initialization later. - return ; - } - - LLStandardBumpmap::restoreGL(); - // Images will be recreated as they are needed. -} - - -LLBumpImageList::~LLBumpImageList() -{ - // Shutdown should have already been called. - llassert( mBrightnessEntries.size() == 0 ); - llassert( mDarknessEntries.size() == 0 ); -} - - -// Note: Does nothing for entries in gStandardBumpmapList that are not actually standard bump images (e.g. none, brightness, and darkness) -void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32 virtual_size) -{ - bump &= TEM_BUMP_MASK; - LLViewerFetchedTexture* bump_image = gStandardBumpmapList[bump].mImage; - if( bump_image ) - { - bump_image->addTextureStats(virtual_size); - } -} - - -void LLBumpImageList::updateImages() -{ - for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); ) - { - bump_image_map_t::iterator curiter = iter++; - LLViewerTexture* image = curiter->second; - if( image ) - { - bool destroy = true; - if( image->hasGLTexture()) - { - if( image->getBoundRecently() ) - { - destroy = false; - } - else - { - image->destroyGLTexture(); - } - } - - if( destroy ) - { - //LL_INFOS() << "*** Destroying bright " << (void*)image << LL_ENDL; - mBrightnessEntries.erase(curiter); // deletes the image thanks to reference counting - } - } - } - - for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); ) - { - bump_image_map_t::iterator curiter = iter++; - LLViewerTexture* image = curiter->second; - if( image ) - { - bool destroy = true; - if( image->hasGLTexture()) - { - if( image->getBoundRecently() ) - { - destroy = false; - } - else - { - image->destroyGLTexture(); - } - } - - if( destroy ) - { - //LL_INFOS() << "*** Destroying dark " << (void*)image << LL_ENDL;; - mDarknessEntries.erase(curiter); // deletes the image thanks to reference counting - } - } - } -} - - -// Note: the caller SHOULD NOT keep the pointer that this function returns. It may be updated as more data arrives. -LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code ) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) ); - - LLViewerTexture* bump = NULL; - - bump_image_map_t* entries_list = NULL; - void (*callback_func)( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) = NULL; - - switch( bump_code ) - { - case BE_BRIGHTNESS: - entries_list = &mBrightnessEntries; - callback_func = LLBumpImageList::onSourceBrightnessLoaded; - break; - case BE_DARKNESS: - entries_list = &mDarknessEntries; - callback_func = LLBumpImageList::onSourceDarknessLoaded; - break; - default: - llassert(0); - return NULL; - } - - bump_image_map_t::iterator iter = entries_list->find(src_image->getID()); - if (iter != entries_list->end() && iter->second.notNull()) - { - bump = iter->second; - } - else - { - (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( true ); - bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image - } - - if (!src_image->hasCallbacks()) - { //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again - if (src_image->getWidth() != bump->getWidth() || - src_image->getHeight() != bump->getHeight())// || - //(LLPipeline::sRenderDeferred && bump->getComponents() != 4)) - { - src_image->setBoostLevel(LLGLTexture::BOOST_BUMP) ; - src_image->setLoadedCallback( callback_func, 0, true, false, new LLUUID(src_image->getID()), NULL ); - src_image->forceToSaveRawImage(0) ; - } - } - - return bump; -} - - -// static -void LLBumpImageList::onSourceBrightnessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - LLUUID* source_asset_id = (LLUUID*)userdata; - LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS ); - if( final ) - { - delete source_asset_id; - } -} - -// static -void LLBumpImageList::onSourceDarknessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) -{ - LLUUID* source_asset_id = (LLUUID*)userdata; - LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_DARKNESS ); - if( final ) - { - delete source_asset_id; - } -} - -void LLBumpImageList::onSourceStandardLoaded( bool success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) -{ - if (success && LLPipeline::sRenderDeferred) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - LLPointer nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4); - { - generateNormalMapFromAlpha(src, nrm_image); - } - src_vi->setExplicitFormat(GL_RGBA, GL_RGBA); - { - src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image); - } - } -} - -void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image) -{ - LLImageDataSharedLock lockIn(src); - LLImageDataLock lockOut(nrm_image); - - U8* nrm_data = nrm_image->getData(); - S32 resX = src->getWidth(); - S32 resY = src->getHeight(); - - const U8* src_data = src->getData(); - - S32 src_cmp = src->getComponents(); - - F32 norm_scale = gSavedSettings.getF32("RenderNormalMapScale"); - - U32 idx = 0; - //generate normal map from pseudo-heightfield - for (S32 j = 0; j < resY; ++j) - { - for (S32 i = 0; i < resX; ++i) - { - S32 rX = (i+1)%resX; - S32 rY = (j+1)%resY; - S32 lX = (i-1)%resX; - S32 lY = (j-1)%resY; - - if (lX < 0) - { - lX += resX; - } - if (lY < 0) - { - lY += resY; - } - - F32 cH = (F32) src_data[(j*resX+i)*src_cmp+src_cmp-1]; - - LLVector3 right = LLVector3(norm_scale, 0, (F32) src_data[(j*resX+rX)*src_cmp+src_cmp-1]-cH); - LLVector3 left = LLVector3(-norm_scale, 0, (F32) src_data[(j*resX+lX)*src_cmp+src_cmp-1]-cH); - LLVector3 up = LLVector3(0, -norm_scale, (F32) src_data[(lY*resX+i)*src_cmp+src_cmp-1]-cH); - LLVector3 down = LLVector3(0, norm_scale, (F32) src_data[(rY*resX+i)*src_cmp+src_cmp-1]-cH); - - LLVector3 norm = right%down + down%left + left%up + up%right; - - norm.normVec(); - - norm *= 0.5f; - norm += LLVector3(0.5f,0.5f,0.5f); - - idx = (j*resX+i)*4; - nrm_data[idx+0]= (U8) (norm.mV[0]*255); - nrm_data[idx+1]= (U8) (norm.mV[1]*255); - nrm_data[idx+2]= (U8) (norm.mV[2]*255); - nrm_data[idx+3]= src_data[(j*resX+i)*src_cmp+src_cmp-1]; - } - } -} - -// static -void LLBumpImageList::onSourceLoaded( bool success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) -{ - LL_PROFILE_ZONE_SCOPED; - - if( success ) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - - LLImageDataSharedLock lock(src); - - bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); - bump_image_map_t::iterator iter = entries_list.find(source_asset_id); - - { - if (iter == entries_list.end() || - iter->second.isNull() || - iter->second->getWidth() != src->getWidth() || - iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution - { //make sure an entry exists for this image - entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(true); - iter = entries_list.find(src_vi->getID()); - } - } - - if (iter->second->getWidth() != src->getWidth() || - iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution - { - LLPointer dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1); - U8* dst_data = dst_image->getData(); - S32 dst_data_size = dst_image->getDataSize(); - - const U8* src_data = src->getData(); - S32 src_data_size = src->getDataSize(); - - S32 src_components = src->getComponents(); - - // Convert to luminance and then scale and bias that to get ready for - // embossed bump mapping. (0-255 maps to 127-255) - - // Convert to fixed point so we don't have to worry about precision/clamping. - const S32 FIXED_PT = 8; - const S32 R_WEIGHT = S32(0.2995f * (1< maximum ) - { - maximum = dst_data[i]; - } - } - } - else - { - llassert(0); - dst_image->clear(); - } - } - break; - case 3: - case 4: - { - if( src_data_size == dst_data_size * src_components ) - { - for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) - { - // RGB to luminance - dst_data[i] = (R_WEIGHT * src_data[j] + G_WEIGHT * src_data[j+1] + B_WEIGHT * src_data[j+2]) >> FIXED_PT; - //llassert( dst_data[i] <= 255 );true because it's 8bit - if( dst_data[i] < minimum ) - { - minimum = dst_data[i]; - } - if( dst_data[i] > maximum ) - { - maximum = dst_data[i]; - } - } - } - else - { - llassert(0); - dst_image->clear(); - } - } - break; - default: - llassert(0); - dst_image->clear(); - break; - } - - if( maximum > minimum ) - { - U8 bias_and_scale_lut[256]; - F32 twice_one_over_range = 2.f / (maximum - minimum); - S32 i; - - const F32 ARTIFICIAL_SCALE = 2.f; // Advantage: exaggerates the effect in midrange. Disadvantage: clamps at the extremes. - if (BE_DARKNESS == bump_code) - { - for( i = minimum; i <= maximum; i++ ) - { - F32 minus_one_to_one = F32(maximum - i) * twice_one_over_range - 1.f; - bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); - } - } - else - { - for( i = minimum; i <= maximum; i++ ) - { - F32 minus_one_to_one = F32(i - minimum) * twice_one_over_range - 1.f; - bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); - } - } - - for( i = 0; i < dst_data_size; i++ ) - { - dst_data[i] = bias_and_scale_lut[dst_data[i]]; - } - } - - //--------------------------------------------------- - // immediately assign bump to a smart pointer in case some local smart pointer - // accidentally releases it. - LLPointer bump = iter->second; - - if (!LLPipeline::sRenderDeferred) - { - bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); - -#if LL_BUMPLIST_MULTITHREADED - auto tex_queue = LLImageGLThread::sEnabledTextures ? sTexUpdateQueue.lock() : nullptr; - - if (tex_queue) - { //dispatch creation to background thread - LLImageRaw* dst_ptr = dst_image; - LLViewerTexture* bump_ptr = bump; - dst_ptr->ref(); - bump_ptr->ref(); - tex_queue->post( - [=]() - { - LL_PROFILE_ZONE_NAMED("bil - create texture"); - bump_ptr->createGLTexture(0, dst_ptr); - bump_ptr->unref(); - dst_ptr->unref(); - }); - - } - else -#endif - { - bump->createGLTexture(0, dst_image); - } - } - else - { //convert to normal map - LL_PROFILE_ZONE_NAMED("bil - create normal map"); - LLImageGL* img = bump->getGLTexture(); - LLImageRaw* dst_ptr = dst_image.get(); - LLGLTexture* bump_ptr = bump.get(); - - dst_ptr->ref(); - img->ref(); - bump_ptr->ref(); - auto create_func = [=]() - { - img->setUseMipMaps(true); - // upload dst_image to GPU (greyscale in red channel) - img->setExplicitFormat(GL_RED, GL_RED); - - bump_ptr->createGLTexture(0, dst_ptr); - dst_ptr->unref(); - }; - - auto generate_func = [=]() - { - // Allocate an empty RGBA texture at "tex_name" the same size as bump - // Note: bump will still point at GPU copy of dst_image - bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA); - LLGLuint tex_name; - img->createGLTexture(0, nullptr, false, 0, true, &tex_name); - - // point render target at empty buffer - sRenderTarget.setColorAttachment(img, tex_name); - - // generate normal map in empty texture - { - sRenderTarget.bindTarget(); - - LLGLDepthTest depth(GL_FALSE); - LLGLDisable cull(GL_CULL_FACE); - LLGLDisable blend(GL_BLEND); - gGL.setColorMask(true, true); - - gNormalMapGenProgram.bind(); - - static LLStaticHashedString sNormScale("norm_scale"); - static LLStaticHashedString sStepX("stepX"); - static LLStaticHashedString sStepY("stepY"); - - gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); - gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); - gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight()); - - gGL.getTexUnit(0)->bind(bump_ptr); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(0, 0); - gGL.vertex2f(0, 0); - - gGL.texCoord2f(0, 1); - gGL.vertex2f(0, 1); - - gGL.texCoord2f(1, 0); - gGL.vertex2f(1, 0); - - gGL.texCoord2f(1, 1); - gGL.vertex2f(1, 1); - - gGL.end(); - - gGL.flush(); - - gNormalMapGenProgram.unbind(); - - sRenderTarget.flush(); - sRenderTarget.releaseColorAttachment(); - } - - // point bump at normal map and free gpu copy of dst_image - img->syncTexName(tex_name); - - // generate mipmap - gGL.getTexUnit(0)->bind(img); - glGenerateMipmap(GL_TEXTURE_2D); - gGL.getTexUnit(0)->disable(); - - bump_ptr->unref(); - img->unref(); - }; - -#if LL_BUMPLIST_MULTITHREADED - auto main_queue = LLImageGLThread::sEnabledTextures ? sMainQueue.lock() : nullptr; - - if (main_queue) - { //dispatch texture upload to background thread, issue GPU commands to generate normal map on main thread - main_queue->postTo( - sTexUpdateQueue, - create_func, - generate_func); - } - else -#endif - { // immediate upload texture and generate normal map - create_func(); - generate_func(); - } - - - } - - iter->second = bump; // derefs (and deletes) old image - //--------------------------------------------------- - } - } -} - -void LLDrawPoolBump::pushBumpBatches(U32 type) -{ - LLVOAvatar* avatar = nullptr; - U64 skin = 0; - - if (mRigged) - { // nudge type enum and include skinweights for rigged pass - type += 1; - } - - LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); - LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); - - for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) - { - LLDrawInfo& params = **i; - - if (LLDrawPoolBump::bindBumpMap(params)) - { - if (mRigged) - { - if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash) - { - if (uploadMatrixPalette(params)) - { - avatar = params.mAvatar; - skin = params.mSkinInfo->mHash; - } - else - { - continue; - } - } - } - pushBumpBatch(params, false); - } - } -} - -void LLRenderPass::pushBumpBatch(LLDrawInfo& params, bool texture, bool batch_textures) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - applyModelMatrix(params); - - bool tex_setup = false; - - if (batch_textures && params.mTextureList.size() > 1) - { - for (U32 i = 0; i < params.mTextureList.size(); ++i) - { - if (params.mTextureList[i].notNull()) - { - gGL.getTexUnit(i)->bindFast(params.mTextureList[i]); - } - } - } - else - { //not batching textures or batch has only 1 texture -- might need a texture matrix - if (params.mTextureMatrix) - { - if (shiny) - { - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - } - else - { - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); - gPipeline.mTextureMatrixOps++; - } - - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); - gPipeline.mTextureMatrixOps++; - - tex_setup = true; - } - - if (shiny && mShaderLevel > 1 && texture) - { - if (params.mTexture.notNull()) - { - gGL.getTexUnit(diffuse_channel)->bindFast(params.mTexture); - } - else - { - gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); - } - } - } - - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); - - if (tex_setup) - { - if (shiny) - { - gGL.getTexUnit(0)->activate(); - } - else - { - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - } - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } -} - +/** + * @file lldrawpoolbump.cpp + * @brief LLDrawPoolBump class implementation + * + * $LicenseInfo:firstyear=2003&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 "lldrawpoolbump.h" + +#include "llstl.h" +#include "llviewercontrol.h" +#include "lldir.h" +#include "m3math.h" +#include "m4math.h" +#include "v4math.h" +#include "llglheaders.h" +#include "llrender.h" + +#include "llcubemap.h" +#include "lldrawable.h" +#include "llface.h" +#include "llsky.h" +#include "llstartup.h" +#include "lltextureentry.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "pipeline.h" +#include "llspatialpartition.h" +#include "llviewershadermgr.h" +#include "llmodel.h" + +//#include "llimagebmp.h" +//#include "../tools/imdebug/imdebug.h" + +// static +LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT]; +LL::WorkQueue::weak_t LLBumpImageList::sMainQueue; +LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue; +LLRenderTarget LLBumpImageList::sRenderTarget; + +// static +U32 LLStandardBumpmap::sStandardBumpmapCount = 0; + +// static +LLBumpImageList gBumpImageList; + +const S32 STD_BUMP_LATEST_FILE_VERSION = 1; + +const U32 VERTEX_MASK_SHINY = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; +const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; + +U32 LLDrawPoolBump::sVertexMask = VERTEX_MASK_SHINY; + + +static LLGLSLShader* shader = NULL; +static S32 cube_channel = -1; +static S32 diffuse_channel = -1; +static S32 bump_channel = -1; +static bool shiny = false; + +// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an +// LLAtomicBool; this should work just fine, now. HB +#define LL_BUMPLIST_MULTITHREADED 1 + + +// static +void LLStandardBumpmap::shutdown() +{ + LLStandardBumpmap::destroyGL(); +} + +// static +void LLStandardBumpmap::restoreGL() +{ + addstandard(); +} + +// static +void LLStandardBumpmap::addstandard() +{ + if(!gTextureList.isInitialized()) + { + //Note: loading pre-configuration sometimes triggers this call. + //But it is safe to return here because bump images will be reloaded during initialization later. + return ; + } + + if (LLStartUp::getStartupState() < STATE_SEED_CAP_GRANTED) + { + // Not ready, need caps for images + return; + } + + // can't assert; we destroyGL and restoreGL a lot during *first* startup, which populates this list already, THEN we explicitly init the list as part of *normal* startup. Sigh. So clear the list every time before we (re-)add the standard bumpmaps. + //llassert( LLStandardBumpmap::sStandardBumpmapCount == 0 ); + clear(); + LL_INFOS() << "Adding standard bumpmaps." << LL_ENDL; + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("None"); // BE_NO_BUMP + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Brightness"); // BE_BRIGHTNESS + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness"); // BE_DARKNESS + + std::string file_name = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "std_bump.ini" ); + LLFILE* file = LLFile::fopen( file_name, "rt" ); /*Flawfinder: ignore*/ + if( !file ) + { + LL_WARNS() << "Could not open std_bump <" << file_name << ">" << LL_ENDL; + return; + } + + S32 file_version = 0; + + S32 fields_read = fscanf( file, "LLStandardBumpmap version %d", &file_version ); + if( fields_read != 1 ) + { + LL_WARNS() << "Bad LLStandardBumpmap header" << LL_ENDL; + return; + } + + if( file_version > STD_BUMP_LATEST_FILE_VERSION ) + { + LL_WARNS() << "LLStandardBumpmap has newer version (" << file_version << ") than viewer (" << STD_BUMP_LATEST_FILE_VERSION << ")" << LL_ENDL; + return; + } + + while( !feof(file) && (LLStandardBumpmap::sStandardBumpmapCount < (U32)TEM_BUMPMAP_COUNT) ) + { + // *NOTE: This buffer size is hard coded into scanf() below. + char label[2048] = ""; /* Flawfinder: ignore */ + char bump_image_id[2048] = ""; /* Flawfinder: ignore */ + fields_read = fscanf( /* Flawfinder: ignore */ + file, "\n%2047s %2047s", label, bump_image_id); + if( EOF == fields_read ) + { + break; + } + if( fields_read != 2 ) + { + LL_WARNS() << "Bad LLStandardBumpmap entry" << LL_ENDL; + return; + } + +// LL_INFOS() << "Loading bumpmap: " << bump_image_id << " from viewerart" << LL_ENDL; + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label; + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = + LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id)); + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLGLTexture::LOCAL) ; + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, true, false, NULL, NULL ); + gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->forceToSaveRawImage(0, 30.f) ; + LLStandardBumpmap::sStandardBumpmapCount++; + } + + fclose( file ); +} + +// static +void LLStandardBumpmap::clear() +{ + LL_INFOS() << "Clearing standard bumpmaps." << LL_ENDL; + for( U32 i = 0; i < LLStandardBumpmap::sStandardBumpmapCount; i++ ) + { + gStandardBumpmapList[i].mLabel.assign(""); + gStandardBumpmapList[i].mImage = NULL; + } + sStandardBumpmapCount = 0; +} + +// static +void LLStandardBumpmap::destroyGL() +{ + clear(); +} + + + +//////////////////////////////////////////////////////////////// + +LLDrawPoolBump::LLDrawPoolBump() +: LLRenderPass(LLDrawPool::POOL_BUMP) +{ + shiny = false; +} + + +void LLDrawPoolBump::prerender() +{ + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); +} + +// static +S32 LLDrawPoolBump::numBumpPasses() +{ + return 1; +} + + +//static +void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) +{ + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + if( cube_map && !LLPipeline::sReflectionProbesEnabled ) + { + if (shader ) + { + LLMatrix4 mat; + mat.initRows(LLVector4(gGLModelView+0), + LLVector4(gGLModelView+4), + LLVector4(gGLModelView+8), + LLVector4(gGLModelView+12)); + LLVector3 vec = LLVector3(gShinyOrigin) * mat; + LLVector4 vec4(vec, gShinyOrigin.mV[3]); + shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); + if (shader_level > 1) + { + cube_map->setMatrix(1); + // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for + // the cube map in the one pass shiny shaders + cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + cube_map->enableTexture(cube_channel); + diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } + else + { + cube_map->setMatrix(0); + cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + diffuse_channel = -1; + cube_map->enable(cube_channel); + } + gGL.getTexUnit(cube_channel)->bind(cube_map); + gGL.getTexUnit(0)->activate(); + } + else + { + cube_channel = 0; + diffuse_channel = -1; + gGL.getTexUnit(0)->disable(); + cube_map->enable(0); + cube_map->setMatrix(0); + gGL.getTexUnit(0)->bind(cube_map); + } + } +} + +//static +void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) +{ + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + if( cube_map && !LLPipeline::sReflectionProbesEnabled) + { + if (shader_level > 1) + { + shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + + if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) + { + if (diffuse_channel != 0) + { + shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } + } + } + // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0 + // MAINT-755 + cube_map->disable(); + cube_map->restoreMatrix(); + } +} + +void LLDrawPoolBump::beginFullbrightShiny() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + + sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; + + // Second pass: environment map + shader = &gDeferredFullbrightShinyProgram; + if (LLPipeline::sRenderingHUDs) + { + shader = &gHUDFullbrightShinyProgram; + } + + if (mRigged) + { + llassert(shader->mRiggedVariant); + shader = shader->mRiggedVariant; + } + + // bind exposure map so fullbright shader can cancel out exposure + S32 channel = shader->enableTexture(LLShaderMgr::EXPOSURE_MAP); + if (channel > -1) + { + gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap); + } + + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + + if (cube_map && !LLPipeline::sReflectionProbesEnabled) + { + // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for + // the cube map in the one pass shiny shaders + gGL.getTexUnit(1)->disable(); + cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + cube_map->enableTexture(cube_channel); + diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + + gGL.getTexUnit(cube_channel)->bind(cube_map); + gGL.getTexUnit(0)->activate(); + } + + { + LLMatrix4 mat; + mat.initRows(LLVector4(gGLModelView+0), + LLVector4(gGLModelView+4), + LLVector4(gGLModelView+8), + LLVector4(gGLModelView+12)); + shader->bind(); + + LLVector3 vec = LLVector3(gShinyOrigin) * mat; + LLVector4 vec4(vec, gShinyOrigin.mV[3]); + shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); + + if (LLPipeline::sReflectionProbesEnabled) + { + gPipeline.bindReflectionProbes(*shader); + } + else + { + gPipeline.setEnvMat(*shader); + } + } + + if (mShaderLevel > 1) + { //indexed texture rendering, channel 0 is always diffuse + diffuse_channel = 0; + } + + shiny = true; +} + +void LLDrawPoolBump::renderFullbrightShiny() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + + { + LLGLEnable blend_enable(GL_BLEND); + + if (mShaderLevel > 1) + { + if (mRigged) + { + LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, true, true); + } + else + { + LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, true, true); + } + } + else + { + if (mRigged) + { + LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED); + } + else + { + LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY); + } + } + } +} + +void LLDrawPoolBump::endFullbrightShiny() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; + if( cube_map && !LLPipeline::sReflectionProbesEnabled ) + { + cube_map->disable(); + if (shader->mFeatures.hasReflectionProbes) + { + gPipeline.unbindReflectionProbes(*shader); + } + shader->unbind(); + } + + diffuse_channel = -1; + cube_channel = 0; + shiny = false; +} + +void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, bool texture = true) +{ + LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; + + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + { + LLDrawInfo& params = **k; + + applyModelMatrix(params); + + params.mVertexBuffer->setBuffer(); + params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); + } +} + + +// static +bool LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) +{ + U8 bump_code = params.mBump; + + return bindBumpMap(bump_code, params.mTexture, channel); +} + +//static +bool LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel) +{ + const LLTextureEntry* te = face->getTextureEntry(); + if (te) + { + U8 bump_code = te->getBumpmap(); + return bindBumpMap(bump_code, face->getTexture(), channel); + } + + return false; +} + +//static +bool LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, S32 channel) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + //Note: texture atlas does not support bump texture now. + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ; + if(!tex) + { + //if the texture is not a fetched texture + return false; + } + + LLViewerTexture* bump = NULL; + + switch( bump_code ) + { + case BE_NO_BUMP: + break; + case BE_BRIGHTNESS: + case BE_DARKNESS: + bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code ); + break; + + default: + if( bump_code < LLStandardBumpmap::sStandardBumpmapCount ) + { + bump = gStandardBumpmapList[bump_code].mImage; + gBumpImageList.addTextureStats(bump_code, tex->getID(), tex->getMaxVirtualSize()); + } + break; + } + + if (bump) + { + if (channel == -2) + { + gGL.getTexUnit(1)->bindFast(bump); + gGL.getTexUnit(0)->bindFast(bump); + } + else + { + // NOTE: do not use bindFast here (see SL-16222) + gGL.getTexUnit(channel)->bind(bump); + } + + return true; + } + + return false; +} + +//static +void LLDrawPoolBump::beginBump() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); + sVertexMask = VERTEX_MASK_BUMP; + // Optional second pass: emboss bump map + stop_glerror(); + + shader = &gObjectBumpProgram; + + if (mRigged) + { + llassert(shader->mRiggedVariant); + shader = shader->mRiggedVariant; + } + + shader->bind(); + + gGL.setSceneBlendType(LLRender::BT_MULT_X2); + stop_glerror(); +} + +//static +void LLDrawPoolBump::renderBump(U32 pass) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL); + LLGLEnable blend(GL_BLEND); + gGL.diffuseColor4f(1,1,1,1); + /// Get rid of z-fighting with non-bump pass. + LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -1.0f); + pushBumpBatches(pass); +} + +//static +void LLDrawPoolBump::endBump(U32 pass) +{ + LLGLSLShader::unbind(); + + gGL.setSceneBlendType(LLRender::BT_ALPHA); +} + +S32 LLDrawPoolBump::getNumDeferredPasses() +{ + return 1; +} + +void LLDrawPoolBump::renderDeferred(S32 pass) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); + + shiny = true; + for (int i = 0; i < 2; ++i) + { + bool rigged = i == 1; + gDeferredBumpProgram.bind(rigged); + diffuse_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + bump_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::BUMP_MAP); + gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE); + + U32 type = rigged ? LLRenderPass::PASS_BUMP_RIGGED : LLRenderPass::PASS_BUMP; + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + + LLVOAvatar* avatar = nullptr; + U64 skin = 0; + + for (LLCullResult::drawinfo_iterator i = begin; i != end; ) + { + LLDrawInfo& params = **i; + + LLCullResult::increment_iterator(i, end); + + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff); + LLDrawPoolBump::bindBumpMap(params, bump_channel); + + if (rigged) + { + if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash) + { + uploadMatrixPalette(params); + avatar = params.mAvatar; + skin = params.mSkinInfo->mHash; + } + pushBumpBatch(params, true, false); + } + else + { + pushBumpBatch(params, true, false); + } + } + + LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::BUMP_MAP); + LLGLSLShader::sCurBoundShaderPtr->unbind(); + gGL.getTexUnit(0)->activate(); + } + + shiny = false; +} + + +void LLDrawPoolBump::renderPostDeferred(S32 pass) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + + S32 num_passes = LLPipeline::sRenderingHUDs ? 1 : 2; // skip rigged pass when rendering HUDs + + for (int i = 0; i < num_passes; ++i) + { // two passes -- static and rigged + mRigged = (i == 1); + + // render shiny + beginFullbrightShiny(); + renderFullbrightShiny(); + endFullbrightShiny(); + + //render bump + beginBump(); + renderBump(LLRenderPass::PASS_POST_BUMP); + endBump(); + } +} + + +//////////////////////////////////////////////////////////////// +// List of bump-maps created from other textures. + + +//const LLUUID TEST_BUMP_ID("3d33eaf2-459c-6f97-fd76-5fce3fc29447"); + +void LLBumpImageList::init() +{ + llassert( mBrightnessEntries.size() == 0 ); + llassert( mDarknessEntries.size() == 0 ); + + LLStandardBumpmap::restoreGL(); + sMainQueue = LL::WorkQueue::getInstance("mainloop"); + sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader. +} + +void LLBumpImageList::clear() +{ + LL_INFOS() << "Clearing dynamic bumpmaps." << LL_ENDL; + // these will be re-populated on-demand + mBrightnessEntries.clear(); + mDarknessEntries.clear(); + + sRenderTarget.release(); + + LLStandardBumpmap::clear(); +} + +void LLBumpImageList::shutdown() +{ + clear(); + LLStandardBumpmap::shutdown(); +} + +void LLBumpImageList::destroyGL() +{ + clear(); + LLStandardBumpmap::destroyGL(); +} + +void LLBumpImageList::restoreGL() +{ + if(!gTextureList.isInitialized()) + { + //safe to return here because bump images will be reloaded during initialization later. + return ; + } + + LLStandardBumpmap::restoreGL(); + // Images will be recreated as they are needed. +} + + +LLBumpImageList::~LLBumpImageList() +{ + // Shutdown should have already been called. + llassert( mBrightnessEntries.size() == 0 ); + llassert( mDarknessEntries.size() == 0 ); +} + + +// Note: Does nothing for entries in gStandardBumpmapList that are not actually standard bump images (e.g. none, brightness, and darkness) +void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32 virtual_size) +{ + bump &= TEM_BUMP_MASK; + LLViewerFetchedTexture* bump_image = gStandardBumpmapList[bump].mImage; + if( bump_image ) + { + bump_image->addTextureStats(virtual_size); + } +} + + +void LLBumpImageList::updateImages() +{ + for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); ) + { + bump_image_map_t::iterator curiter = iter++; + LLViewerTexture* image = curiter->second; + if( image ) + { + bool destroy = true; + if( image->hasGLTexture()) + { + if( image->getBoundRecently() ) + { + destroy = false; + } + else + { + image->destroyGLTexture(); + } + } + + if( destroy ) + { + //LL_INFOS() << "*** Destroying bright " << (void*)image << LL_ENDL; + mBrightnessEntries.erase(curiter); // deletes the image thanks to reference counting + } + } + } + + for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); ) + { + bump_image_map_t::iterator curiter = iter++; + LLViewerTexture* image = curiter->second; + if( image ) + { + bool destroy = true; + if( image->hasGLTexture()) + { + if( image->getBoundRecently() ) + { + destroy = false; + } + else + { + image->destroyGLTexture(); + } + } + + if( destroy ) + { + //LL_INFOS() << "*** Destroying dark " << (void*)image << LL_ENDL;; + mDarknessEntries.erase(curiter); // deletes the image thanks to reference counting + } + } + } +} + + +// Note: the caller SHOULD NOT keep the pointer that this function returns. It may be updated as more data arrives. +LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code ) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) ); + + LLViewerTexture* bump = NULL; + + bump_image_map_t* entries_list = NULL; + void (*callback_func)( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) = NULL; + + switch( bump_code ) + { + case BE_BRIGHTNESS: + entries_list = &mBrightnessEntries; + callback_func = LLBumpImageList::onSourceBrightnessLoaded; + break; + case BE_DARKNESS: + entries_list = &mDarknessEntries; + callback_func = LLBumpImageList::onSourceDarknessLoaded; + break; + default: + llassert(0); + return NULL; + } + + bump_image_map_t::iterator iter = entries_list->find(src_image->getID()); + if (iter != entries_list->end() && iter->second.notNull()) + { + bump = iter->second; + } + else + { + (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( true ); + bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image + } + + if (!src_image->hasCallbacks()) + { //if image has no callbacks but resolutions don't match, trigger raw image loaded callback again + if (src_image->getWidth() != bump->getWidth() || + src_image->getHeight() != bump->getHeight())// || + //(LLPipeline::sRenderDeferred && bump->getComponents() != 4)) + { + src_image->setBoostLevel(LLGLTexture::BOOST_BUMP) ; + src_image->setLoadedCallback( callback_func, 0, true, false, new LLUUID(src_image->getID()), NULL ); + src_image->forceToSaveRawImage(0) ; + } + } + + return bump; +} + + +// static +void LLBumpImageList::onSourceBrightnessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLUUID* source_asset_id = (LLUUID*)userdata; + LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS ); + if( final ) + { + delete source_asset_id; + } +} + +// static +void LLBumpImageList::onSourceDarknessLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata ) +{ + LLUUID* source_asset_id = (LLUUID*)userdata; + LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_DARKNESS ); + if( final ) + { + delete source_asset_id; + } +} + +void LLBumpImageList::onSourceStandardLoaded( bool success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) +{ + if (success && LLPipeline::sRenderDeferred) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLPointer nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4); + { + generateNormalMapFromAlpha(src, nrm_image); + } + src_vi->setExplicitFormat(GL_RGBA, GL_RGBA); + { + src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image); + } + } +} + +void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image) +{ + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(nrm_image); + + U8* nrm_data = nrm_image->getData(); + S32 resX = src->getWidth(); + S32 resY = src->getHeight(); + + const U8* src_data = src->getData(); + + S32 src_cmp = src->getComponents(); + + F32 norm_scale = gSavedSettings.getF32("RenderNormalMapScale"); + + U32 idx = 0; + //generate normal map from pseudo-heightfield + for (S32 j = 0; j < resY; ++j) + { + for (S32 i = 0; i < resX; ++i) + { + S32 rX = (i+1)%resX; + S32 rY = (j+1)%resY; + S32 lX = (i-1)%resX; + S32 lY = (j-1)%resY; + + if (lX < 0) + { + lX += resX; + } + if (lY < 0) + { + lY += resY; + } + + F32 cH = (F32) src_data[(j*resX+i)*src_cmp+src_cmp-1]; + + LLVector3 right = LLVector3(norm_scale, 0, (F32) src_data[(j*resX+rX)*src_cmp+src_cmp-1]-cH); + LLVector3 left = LLVector3(-norm_scale, 0, (F32) src_data[(j*resX+lX)*src_cmp+src_cmp-1]-cH); + LLVector3 up = LLVector3(0, -norm_scale, (F32) src_data[(lY*resX+i)*src_cmp+src_cmp-1]-cH); + LLVector3 down = LLVector3(0, norm_scale, (F32) src_data[(rY*resX+i)*src_cmp+src_cmp-1]-cH); + + LLVector3 norm = right%down + down%left + left%up + up%right; + + norm.normVec(); + + norm *= 0.5f; + norm += LLVector3(0.5f,0.5f,0.5f); + + idx = (j*resX+i)*4; + nrm_data[idx+0]= (U8) (norm.mV[0]*255); + nrm_data[idx+1]= (U8) (norm.mV[1]*255); + nrm_data[idx+2]= (U8) (norm.mV[2]*255); + nrm_data[idx+3]= src_data[(j*resX+i)*src_cmp+src_cmp-1]; + } + } +} + +// static +void LLBumpImageList::onSourceLoaded( bool success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) +{ + LL_PROFILE_ZONE_SCOPED; + + if( success ) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + + LLImageDataSharedLock lock(src); + + bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); + bump_image_map_t::iterator iter = entries_list.find(source_asset_id); + + { + if (iter == entries_list.end() || + iter->second.isNull() || + iter->second->getWidth() != src->getWidth() || + iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution + { //make sure an entry exists for this image + entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(true); + iter = entries_list.find(src_vi->getID()); + } + } + + if (iter->second->getWidth() != src->getWidth() || + iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution + { + LLPointer dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1); + U8* dst_data = dst_image->getData(); + S32 dst_data_size = dst_image->getDataSize(); + + const U8* src_data = src->getData(); + S32 src_data_size = src->getDataSize(); + + S32 src_components = src->getComponents(); + + // Convert to luminance and then scale and bias that to get ready for + // embossed bump mapping. (0-255 maps to 127-255) + + // Convert to fixed point so we don't have to worry about precision/clamping. + const S32 FIXED_PT = 8; + const S32 R_WEIGHT = S32(0.2995f * (1< maximum ) + { + maximum = dst_data[i]; + } + } + } + else + { + llassert(0); + dst_image->clear(); + } + } + break; + case 3: + case 4: + { + if( src_data_size == dst_data_size * src_components ) + { + for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) + { + // RGB to luminance + dst_data[i] = (R_WEIGHT * src_data[j] + G_WEIGHT * src_data[j+1] + B_WEIGHT * src_data[j+2]) >> FIXED_PT; + //llassert( dst_data[i] <= 255 );true because it's 8bit + if( dst_data[i] < minimum ) + { + minimum = dst_data[i]; + } + if( dst_data[i] > maximum ) + { + maximum = dst_data[i]; + } + } + } + else + { + llassert(0); + dst_image->clear(); + } + } + break; + default: + llassert(0); + dst_image->clear(); + break; + } + + if( maximum > minimum ) + { + U8 bias_and_scale_lut[256]; + F32 twice_one_over_range = 2.f / (maximum - minimum); + S32 i; + + const F32 ARTIFICIAL_SCALE = 2.f; // Advantage: exaggerates the effect in midrange. Disadvantage: clamps at the extremes. + if (BE_DARKNESS == bump_code) + { + for( i = minimum; i <= maximum; i++ ) + { + F32 minus_one_to_one = F32(maximum - i) * twice_one_over_range - 1.f; + bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); + } + } + else + { + for( i = minimum; i <= maximum; i++ ) + { + F32 minus_one_to_one = F32(i - minimum) * twice_one_over_range - 1.f; + bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); + } + } + + for( i = 0; i < dst_data_size; i++ ) + { + dst_data[i] = bias_and_scale_lut[dst_data[i]]; + } + } + + //--------------------------------------------------- + // immediately assign bump to a smart pointer in case some local smart pointer + // accidentally releases it. + LLPointer bump = iter->second; + + if (!LLPipeline::sRenderDeferred) + { + bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); + +#if LL_BUMPLIST_MULTITHREADED + auto tex_queue = LLImageGLThread::sEnabledTextures ? sTexUpdateQueue.lock() : nullptr; + + if (tex_queue) + { //dispatch creation to background thread + LLImageRaw* dst_ptr = dst_image; + LLViewerTexture* bump_ptr = bump; + dst_ptr->ref(); + bump_ptr->ref(); + tex_queue->post( + [=]() + { + LL_PROFILE_ZONE_NAMED("bil - create texture"); + bump_ptr->createGLTexture(0, dst_ptr); + bump_ptr->unref(); + dst_ptr->unref(); + }); + + } + else +#endif + { + bump->createGLTexture(0, dst_image); + } + } + else + { //convert to normal map + LL_PROFILE_ZONE_NAMED("bil - create normal map"); + LLImageGL* img = bump->getGLTexture(); + LLImageRaw* dst_ptr = dst_image.get(); + LLGLTexture* bump_ptr = bump.get(); + + dst_ptr->ref(); + img->ref(); + bump_ptr->ref(); + auto create_func = [=]() + { + img->setUseMipMaps(true); + // upload dst_image to GPU (greyscale in red channel) + img->setExplicitFormat(GL_RED, GL_RED); + + bump_ptr->createGLTexture(0, dst_ptr); + dst_ptr->unref(); + }; + + auto generate_func = [=]() + { + // Allocate an empty RGBA texture at "tex_name" the same size as bump + // Note: bump will still point at GPU copy of dst_image + bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA); + LLGLuint tex_name; + img->createGLTexture(0, nullptr, false, 0, true, &tex_name); + + // point render target at empty buffer + sRenderTarget.setColorAttachment(img, tex_name); + + // generate normal map in empty texture + { + sRenderTarget.bindTarget(); + + LLGLDepthTest depth(GL_FALSE); + LLGLDisable cull(GL_CULL_FACE); + LLGLDisable blend(GL_BLEND); + gGL.setColorMask(true, true); + + gNormalMapGenProgram.bind(); + + static LLStaticHashedString sNormScale("norm_scale"); + static LLStaticHashedString sStepX("stepX"); + static LLStaticHashedString sStepY("stepY"); + + gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); + gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); + gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight()); + + gGL.getTexUnit(0)->bind(bump_ptr); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(0, 0); + gGL.vertex2f(0, 0); + + gGL.texCoord2f(0, 1); + gGL.vertex2f(0, 1); + + gGL.texCoord2f(1, 0); + gGL.vertex2f(1, 0); + + gGL.texCoord2f(1, 1); + gGL.vertex2f(1, 1); + + gGL.end(); + + gGL.flush(); + + gNormalMapGenProgram.unbind(); + + sRenderTarget.flush(); + sRenderTarget.releaseColorAttachment(); + } + + // point bump at normal map and free gpu copy of dst_image + img->syncTexName(tex_name); + + // generate mipmap + gGL.getTexUnit(0)->bind(img); + glGenerateMipmap(GL_TEXTURE_2D); + gGL.getTexUnit(0)->disable(); + + bump_ptr->unref(); + img->unref(); + }; + +#if LL_BUMPLIST_MULTITHREADED + auto main_queue = LLImageGLThread::sEnabledTextures ? sMainQueue.lock() : nullptr; + + if (main_queue) + { //dispatch texture upload to background thread, issue GPU commands to generate normal map on main thread + main_queue->postTo( + sTexUpdateQueue, + create_func, + generate_func); + } + else +#endif + { // immediate upload texture and generate normal map + create_func(); + generate_func(); + } + + + } + + iter->second = bump; // derefs (and deletes) old image + //--------------------------------------------------- + } + } +} + +void LLDrawPoolBump::pushBumpBatches(U32 type) +{ + LLVOAvatar* avatar = nullptr; + U64 skin = 0; + + if (mRigged) + { // nudge type enum and include skinweights for rigged pass + type += 1; + } + + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + + for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) + { + LLDrawInfo& params = **i; + + if (LLDrawPoolBump::bindBumpMap(params)) + { + if (mRigged) + { + if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash) + { + if (uploadMatrixPalette(params)) + { + avatar = params.mAvatar; + skin = params.mSkinInfo->mHash; + } + else + { + continue; + } + } + } + pushBumpBatch(params, false); + } + } +} + +void LLRenderPass::pushBumpBatch(LLDrawInfo& params, bool texture, bool batch_textures) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + applyModelMatrix(params); + + bool tex_setup = false; + + if (batch_textures && params.mTextureList.size() > 1) + { + for (U32 i = 0; i < params.mTextureList.size(); ++i) + { + if (params.mTextureList[i].notNull()) + { + gGL.getTexUnit(i)->bindFast(params.mTextureList[i]); + } + } + } + else + { //not batching textures or batch has only 1 texture -- might need a texture matrix + if (params.mTextureMatrix) + { + if (shiny) + { + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); + } + else + { + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gPipeline.mTextureMatrixOps++; + } + + gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gPipeline.mTextureMatrixOps++; + + tex_setup = true; + } + + if (shiny && mShaderLevel > 1 && texture) + { + if (params.mTexture.notNull()) + { + gGL.getTexUnit(diffuse_channel)->bindFast(params.mTexture); + } + else + { + gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); + } + } + } + + params.mVertexBuffer->setBuffer(); + params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); + + if (tex_setup) + { + if (shiny) + { + gGL.getTexUnit(0)->activate(); + } + else + { + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); + } + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } +} + -- cgit v1.2.3