summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl17
-rwxr-xr-xindra/newview/llagent.cpp8
-rw-r--r--indra/newview/llagent.h2
-rw-r--r--indra/newview/llscenemonitor.cpp108
-rw-r--r--indra/newview/llscenemonitor.h13
-rw-r--r--indra/newview/llviewerobjectlist.cpp4
-rw-r--r--indra/newview/llviewerregion.cpp81
-rw-r--r--indra/newview/llviewerregion.h35
-rw-r--r--indra/newview/llviewershadermgr.cpp1
9 files changed, 218 insertions, 51 deletions
diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
index 050114b37e..6eeb2596b2 100644
--- a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -31,6 +31,10 @@ out vec4 frag_color;
uniform sampler2D tex0;
uniform sampler2D tex1;
+uniform sampler2D dither_tex;
+uniform float dither_scale;
+uniform float dither_scale_s;
+uniform float dither_scale_t;
VARYING vec2 vary_texcoord0;
VARYING vec2 vary_texcoord1;
@@ -38,4 +42,17 @@ VARYING vec2 vary_texcoord1;
void main()
{
frag_color = abs(texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy));
+
+ vec2 dither_coord;
+ dither_coord[0] = vary_texcoord0[0] * dither_scale_s;
+ dither_coord[1] = vary_texcoord0[1] * dither_scale_t;
+ vec4 dither_vec = texture(dither_tex, dither_coord.xy);
+
+ for(int i = 0; i < 3; i++)
+ {
+ if(frag_color[i] < dither_vec[i] * dither_scale)
+ {
+ frag_color[i] = 0.f;
+ }
+ }
}
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 14235bcee4..24c9da8e17 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1046,6 +1046,14 @@ const LLVector3d &LLAgent::getPositionGlobal() const
return mPositionGlobal;
}
+bool LLAgent::isPositionChanged() const
+{
+ LLVector3d diff;
+ diff = mPositionGlobal - mLastPositionGlobal;
+
+ return diff.lengthSquared() > 1.0;
+}
+
//-----------------------------------------------------------------------------
// getPositionAgent()
//-----------------------------------------------------------------------------
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 99904e118c..a1e899b45d 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -250,6 +250,8 @@ public:
const LLVector3d &getLastPositionGlobal() const { return mLastPositionGlobal; }
void setLastPositionGlobal(const LLVector3d &pos) { mLastPositionGlobal = pos; }
+
+ bool isPositionChanged() const;
private:
std::set<U64> mRegionsVisited; // Stat - what distinct regions has the avatar been to?
F64 mDistanceTraveled; // Stat - how far has the avatar moved?
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 189697dcf0..4eb44bcc00 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -37,6 +37,8 @@
#include "llwindow.h"
#include "llpointer.h"
#include "llspatialpartition.h"
+#include "llagent.h"
+#include "pipeline.h"
LLSceneMonitorView* gSceneMonitorView = NULL;
@@ -67,7 +69,10 @@ LLSceneMonitor::LLSceneMonitor() :
mDiffPixelRatio(0.5f)
{
mFrames[0] = NULL;
- mFrames[1] = NULL;
+ mFrames[1] = NULL;
+
+ mRecording = new LLTrace::ExtendableRecording();
+ mRecording->start();
}
LLSceneMonitor::~LLSceneMonitor()
@@ -78,6 +83,10 @@ LLSceneMonitor::~LLSceneMonitor()
void LLSceneMonitor::destroyClass()
{
reset();
+
+ delete mRecording;
+ mRecording = NULL;
+ mDitheringTexture = NULL;
}
void LLSceneMonitor::reset()
@@ -100,6 +109,67 @@ void LLSceneMonitor::reset()
}
}
+void LLSceneMonitor::generateDitheringTexture(S32 width, S32 height)
+{
+#if 1
+ //4 * 4 matrix
+ mDitherMatrixWidth = 4;
+ S32 dither_matrix[4][4] =
+ {
+ {1, 9, 3, 11},
+ {13, 5, 15, 7},
+ {4, 12, 2, 10},
+ {16, 8, 14, 6}
+ };
+
+ mDitherScale = 255.f / 17;
+#else
+ //8 * 8 matrix
+ mDitherMatrixWidth = 16;
+ S32 dither_matrix[16][16] =
+ {
+ {1, 49, 13, 61, 4, 52, 16, 64, 1, 49, 13, 61, 4, 52, 16, 64},
+ {33, 17, 45, 29, 36, 20, 48, 32, 33, 17, 45, 29, 36, 20, 48, 32},
+ {9, 57, 5, 53, 12, 60, 8, 56, 9, 57, 5, 53, 12, 60, 8, 56},
+ {41, 25, 37, 21, 44, 28, 40, 24, 41, 25, 37, 21, 44, 28, 40, 24},
+ {3, 51, 15, 63, 2, 50, 14, 62, 3, 51, 15, 63, 2, 50, 14, 62},
+ {35, 19, 47, 31, 34, 18, 46, 30, 35, 19, 47, 31, 34, 18, 46, 30},
+ {11, 59, 7, 55, 10, 58, 6, 54, 11, 59, 7, 55, 10, 58, 6, 54},
+ {43, 27, 39, 23, 42, 26, 38, 22, 43, 27, 39, 23, 42, 26, 38, 22},
+ {1, 49, 13, 61, 4, 52, 16, 64, 1, 49, 13, 61, 4, 52, 16, 64},
+ {33, 17, 45, 29, 36, 20, 48, 32, 33, 17, 45, 29, 36, 20, 48, 32},
+ {9, 57, 5, 53, 12, 60, 8, 56, 9, 57, 5, 53, 12, 60, 8, 56},
+ {41, 25, 37, 21, 44, 28, 40, 24, 41, 25, 37, 21, 44, 28, 40, 24},
+ {3, 51, 15, 63, 2, 50, 14, 62, 3, 51, 15, 63, 2, 50, 14, 62},
+ {35, 19, 47, 31, 34, 18, 46, 30, 35, 19, 47, 31, 34, 18, 46, 30},
+ {11, 59, 7, 55, 10, 58, 6, 54, 11, 59, 7, 55, 10, 58, 6, 54},
+ {43, 27, 39, 23, 42, 26, 38, 22, 43, 27, 39, 23, 42, 26, 38, 22}
+ };
+
+ mDitherScale = 255.f / 65;
+#endif
+
+ LLPointer<LLImageRaw> image_raw = new LLImageRaw(mDitherMatrixWidth, mDitherMatrixWidth, 3);
+ U8* data = image_raw->getData();
+ for (S32 i = 0; i < mDitherMatrixWidth; i++)
+ {
+ for (S32 j = 0; j < mDitherMatrixWidth; j++)
+ {
+ U8 val = dither_matrix[i][j];
+ *data++ = val;
+ *data++ = val;
+ *data++ = val;
+ }
+ }
+
+ mDitheringTexture = LLViewerTextureManager::getLocalTexture(image_raw.get(), FALSE) ;
+ mDitheringTexture->setAddressMode(LLTexUnit::TAM_WRAP);
+ mDitheringTexture->setFilteringOption(LLTexUnit::TFO_POINT);
+
+ mDitherScaleS = (F32)width / mDitherMatrixWidth;
+ mDitherScaleT = (F32)height / mDitherMatrixWidth;
+}
+
void LLSceneMonitor::setDebugViewerVisible(BOOL visible)
{
mDebugViewerVisible = visible;
@@ -137,6 +207,11 @@ bool LLSceneMonitor::preCapture()
return false;
}
+ if(gAgent.isPositionChanged())
+ {
+ mRecording->reset();
+ }
+
if(timer.getElapsedTimeF32() < mSamplingTime)
{
return false;
@@ -197,6 +272,9 @@ void LLSceneMonitor::freezeScene()
// freeze everything else
gSavedSettings.setBOOL("FreezeTime", TRUE);
+
+ gPipeline.clearRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::END_RENDER_TYPES);
}
void LLSceneMonitor::unfreezeScene()
@@ -206,6 +284,9 @@ void LLSceneMonitor::unfreezeScene()
// thaw everything else
gSavedSettings.setBOOL("FreezeTime", FALSE);
+
+ gPipeline.setRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::END_RENDER_TYPES);
}
void LLSceneMonitor::capture()
@@ -268,10 +349,13 @@ void LLSceneMonitor::compare()
{
mDiff = new LLRenderTarget();
mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true);
+
+ generateDitheringTexture(width, height);
}
else if(mDiff->getWidth() != width || mDiff->getHeight() != height)
{
mDiff->resize(width, height, GL_RGBA);
+ generateDitheringTexture(width, height);
}
mDiff->bindTarget();
@@ -279,6 +363,10 @@ void LLSceneMonitor::compare()
gTwoTextureCompareProgram.bind();
+ gTwoTextureCompareProgram.uniform1f("dither_scale", mDitherScale);
+ gTwoTextureCompareProgram.uniform1f("dither_scale_s", mDitherScaleS);
+ gTwoTextureCompareProgram.uniform1f("dither_scale_t", mDitherScaleT);
+
gGL.getTexUnit(0)->activate();
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(0)->bind(mFrames[0]);
@@ -289,6 +377,11 @@ void LLSceneMonitor::compare()
gGL.getTexUnit(1)->bind(mFrames[1]);
gGL.getTexUnit(1)->activate();
+ gGL.getTexUnit(2)->activate();
+ gGL.getTexUnit(2)->enable(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(2)->bind(mDitheringTexture);
+ gGL.getTexUnit(2)->activate();
+
gl_rect_2d_simple_tex(width, height);
mDiff->flush();
@@ -299,6 +392,8 @@ void LLSceneMonitor::compare()
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(1)->disable();
gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(2)->disable();
+ gGL.getTexUnit(2)->unbind(LLTexUnit::TT_TEXTURE);
mHasNewDiff = TRUE;
@@ -368,6 +463,7 @@ void LLSceneMonitor::calcDiffAggregate()
}
}
+static LLTrace::Measurement<> sFramePixelDiff("FramePixelDifference");
void LLSceneMonitor::fetchQueryResult()
{
if(!mHasNewQueryResult)
@@ -388,6 +484,11 @@ void LLSceneMonitor::fetchQueryResult()
mDiffResult = count * 0.5f / (mDiff->getWidth() * mDiff->getHeight() * mDiffPixelRatio * mDiffPixelRatio); //0.5 -> (front face + back face)
+ if(mDiffResult > 0.01f)
+ {
+ mRecording->extend();
+ sFramePixelDiff.sample(mDiffResult);
+ }
//llinfos << count << " : " << mDiffResult << llendl;
}
//-------------------------------------------------------------------------------------------------------------
@@ -454,6 +555,11 @@ void LLSceneMonitorView::draw()
num_str = llformat("Sampling time: %.3f seconds", LLSceneMonitor::getInstance()->getSamplingTime());
LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP);
+ lines++;
+
+ num_str = llformat("Scene Loading time: %.3f seconds", (F32)LLSceneMonitor::getInstance()->getRecording()->getAcceptedRecording().getDuration().value());
+ LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP);
+ lines++;
LLView::draw();
}
diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h
index 02e3d57d46..709650e206 100644
--- a/indra/newview/llscenemonitor.h
+++ b/indra/newview/llscenemonitor.h
@@ -31,9 +31,11 @@
#include "llmath.h"
#include "llfloater.h"
#include "llcharacter.h"
+#include "lltracerecording.h"
class LLCharacter;
class LLRenderTarget;
+class LLViewerTexture;
class LLSceneMonitor : public LLSingleton<LLSceneMonitor>
{
@@ -61,11 +63,14 @@ public:
bool isEnabled()const {return mEnabled;}
bool needsUpdate() const;
+ LLTrace::ExtendableRecording* getRecording() const {return mRecording;}
+
private:
void freezeScene();
void unfreezeScene();
void reset();
bool preCapture();
+ void generateDitheringTexture(S32 width, S32 height);
private:
BOOL mEnabled;
@@ -85,7 +90,15 @@ private:
F32 mSamplingTime; //time interval to capture frames, in seconds
F32 mDiffPixelRatio; //ratio of pixels used for comparison against the original mDiff size along one dimension
+ LLPointer<LLViewerTexture> mDitheringTexture;
+ S32 mDitherMatrixWidth;
+ F32 mDitherScale;
+ F32 mDitherScaleS;
+ F32 mDitherScaleT;
+
std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
+
+ LLTrace::ExtendableRecording* mRecording;
};
class LLSceneMonitorView : public LLFloater
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 0335cd769b..dce963c5c5 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -657,13 +657,15 @@ void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,
S32 msg_size = 0;
U32 id;
U32 crc;
+ U32 flags;
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i);
mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);
+ mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
msg_size += sizeof(U32) * 2;
// Lookup data packer and add this id to cache miss lists if necessary.
U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
- if(!regionp->probeCache(id, crc, cache_miss_type))
+ if(!regionp->probeCache(id, crc, flags, cache_miss_type))
{
// Cache Miss.
recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 570bf9264c..e5cb2a1b08 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1721,9 +1721,26 @@ LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id)
return NULL;
}
+//estimate weight of cache missed object
+F32 LLViewerRegion::calcObjectWeight(U32 flags)
+{
+ LLVector3 pos((F32)(flags & 0xff) + 0.5f, (F32)((flags >> 8) & 0xff) + 0.5f, (F32)((flags >> 16) & 0xff) * 16.f + 8.0f);
+ F32 rad = (F32)((flags >> 24) & 0xff);
+
+ pos += getOriginAgent();
+ pos -= LLViewerCamera::getInstance()->getOrigin();
+
+ return 100.f * rad * rad / pos.lengthSquared();
+}
+
+void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type, F32 weight)
+{
+ mCacheMissList.insert(CacheMissItem(id, miss_type, weight));
+}
+
// Get data packer for this object, if we have cached data
// AND the CRC matches. JC
-bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
+bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type)
{
//llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18
@@ -1749,15 +1766,14 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
else
{
// llinfos << "CRC miss for " << local_id << llendl;
- cache_miss_type = CACHE_MISS_TYPE_CRC;
- mCacheMissCRC.put(local_id);
+
+ addCacheMiss(local_id, CACHE_MISS_TYPE_CRC, calcObjectWeight(flags));
}
}
else
{
// llinfos << "Cache miss for " << local_id << llendl;
- cache_miss_type = CACHE_MISS_TYPE_FULL;
- mCacheMissFull.put(local_id);
+ addCacheMiss(local_id, CACHE_MISS_TYPE_FULL, calcObjectWeight(flags));
}
return false;
@@ -1765,49 +1781,22 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
void LLViewerRegion::addCacheMissFull(const U32 local_id)
{
- mCacheMissFull.put(local_id);
+ addCacheMiss(local_id, CACHE_MISS_TYPE_FULL, 100.f);
}
void LLViewerRegion::requestCacheMisses()
{
- S32 full_count = mCacheMissFull.count();
- S32 crc_count = mCacheMissCRC.count();
- if (full_count == 0 && crc_count == 0) return;
+ if (!mCacheMissList.size())
+ {
+ return;
+ }
LLMessageSystem* msg = gMessageSystem;
BOOL start_new_message = TRUE;
S32 blocks = 0;
- S32 i;
-
- // Send full cache miss updates. For these, we KNOW we don't
- // have a viewer object.
- for (i = 0; i < full_count; i++)
- {
- if (start_new_message)
- {
- msg->newMessageFast(_PREHASH_RequestMultipleObjects);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- start_new_message = FALSE;
- }
-
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_FULL);
- msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]);
- blocks++;
-
- if (blocks >= 255)
- {
- sendReliableMessage();
- start_new_message = TRUE;
- blocks = 0;
- }
- }
-
- // Send CRC miss updates. For these, we _might_ have a viewer object,
- // but probably not.
- for (i = 0; i < crc_count; i++)
+
+ //send requests for all cache-missed objects
+ for (CacheMissItem::cache_miss_list_t::iterator iter = mCacheMissList.begin(); iter != mCacheMissList.end(); ++iter)
{
if (start_new_message)
{
@@ -1819,8 +1808,8 @@ void LLViewerRegion::requestCacheMisses()
}
msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_CRC);
- msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]);
+ msg->addU8Fast(_PREHASH_CacheMissType, (*iter).mType);
+ msg->addU32Fast(_PREHASH_ID, (*iter).mID);
blocks++;
if (blocks >= 255)
@@ -1835,14 +1824,14 @@ void LLViewerRegion::requestCacheMisses()
if (!start_new_message)
{
sendReliableMessage();
- }
- mCacheMissFull.reset();
- mCacheMissCRC.reset();
+ }
mCacheDirty = TRUE ;
// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
- LLViewerStatsRecorder::instance().requestCacheMissesEvent(full_count + crc_count);
+ LLViewerStatsRecorder::instance().requestCacheMissesEvent(mCacheMissList.size());
LLViewerStatsRecorder::instance().log(0.2f);
+
+ mCacheMissList.clear();
}
void LLViewerRegion::dumpCache()
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 9252923aa3..de14c0fe27 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -169,6 +169,9 @@ public:
const LLVector3d &getOriginGlobal() const;
LLVector3 getOriginAgent() const;
+ //estimate weight of cache missed object
+ F32 calcObjectWeight(U32 flags);
+
// Center is at the height of the water table.
const LLVector3d &getCenterGlobal() const;
LLVector3 getCenterAgent() const;
@@ -316,7 +319,7 @@ public:
// handle a full update message
eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
LLVOCacheEntry* getCacheEntryForOctree(U32 local_id);
- bool probeCache(U32 local_id, U32 crc, U8 &cache_miss_type);
+ bool probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type);
void requestCacheMisses();
void addCacheMissFull(const U32 local_id);
@@ -356,6 +359,7 @@ private:
F32 createVisibleObjects(F32 max_time);
F32 updateVisibleEntries(F32 max_time); //update visible entries
+ void addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type, F32 weight);
public:
struct CompareDistance
{
@@ -441,8 +445,33 @@ private:
BOOL mReleaseNotesRequested;
BOOL mDead; //if true, this region is in the process of deleting.
- LLDynamicArray<U32> mCacheMissFull;
- LLDynamicArray<U32> mCacheMissCRC;
+ class CacheMissItem
+ {
+ public:
+ CacheMissItem(U32 id, LLViewerRegion::eCacheMissType miss_type, F32 weight) : mID(id), mType(miss_type), mWeight(weight){}
+
+ U32 mID; //local object id
+ LLViewerRegion::eCacheMissType mType; //cache miss type
+ F32 mWeight; //importance of this object to the current camera.
+
+ struct Compare
+ {
+ bool operator()(const CacheMissItem& lhs, const CacheMissItem& rhs)
+ {
+ if(lhs.mWeight == rhs.mWeight) //larger weight first
+ {
+ return &lhs < &rhs;
+ }
+ else
+ {
+ return lhs.mWeight > rhs.mWeight; //larger weight first
+ }
+ }
+ };
+
+ typedef std::set<CacheMissItem, Compare> cache_miss_list_t;
+ };
+ CacheMissItem::cache_miss_list_t mCacheMissList;
caps_received_signal_t mCapabilitiesReceivedSignal;
LLSD mSimulatorFeatures;
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 1aa36eafee..dd86ef4f34 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -2723,6 +2723,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
gTwoTextureCompareProgram.bind();
gTwoTextureCompareProgram.uniform1i("tex0", 0);
gTwoTextureCompareProgram.uniform1i("tex1", 1);
+ gTwoTextureCompareProgram.uniform1i("dither_tex", 2);
}
}