From 21409a3aaaef71102195d65fc35cebdb5d941a26 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Fri, 30 Nov 2012 22:50:06 -0700
Subject: [PATCH] for SH-3350 and SH-3353: Report frame-to-frame visual deltas
 as an LLStat

---
 .../class1/interface/onetexturefilterF.glsl   |  49 +++++
 .../class1/interface/onetexturefilterV.glsl   |  38 ++++
 .../class1/interface/twotexturecompareF.glsl  |  16 +-
 indra/newview/llscenemonitor.cpp              | 188 ++++++++++++------
 indra/newview/llscenemonitor.h                |  17 +-
 indra/newview/llspatialpartition.cpp          |  22 +-
 indra/newview/llspatialpartition.h            |   2 +
 indra/newview/llviewershadermgr.cpp           |  17 ++
 indra/newview/llviewershadermgr.h             |   4 +-
 indra/newview/pipeline.cpp                    |   5 +-
 10 files changed, 271 insertions(+), 87 deletions(-)
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl

diff --git a/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl
new file mode 100644
index 0000000000..f1400c9b44
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl
@@ -0,0 +1,49 @@
+/** 
+ * @file onetexturefilterF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2D tex0;
+uniform float tolerance;
+
+VARYING vec2 vary_texcoord0;
+
+void main() 
+{
+	frag_color = texture2D(tex0, vary_texcoord0.xy);
+	
+	if(frag_color[0] + frag_color[1] + frag_color[2] < tolerance)
+	{
+		discard;
+	}
+	else
+	{		
+		frag_color[3] = 0.95f;	
+	}	
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl
new file mode 100644
index 0000000000..a33ef7e92c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl
@@ -0,0 +1,38 @@
+/** 
+ * @file onetexturefilterV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+ 
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec2 vary_texcoord0;
+
+void main()
+{
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+	vary_texcoord0 = texcoord0;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
index 336ca21b96..050114b37e 100644
--- a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -37,19 +37,5 @@ VARYING vec2 vary_texcoord1;
 
 void main() 
 {
-	frag_color = texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy);
-	
-	if(frag_color[0] < 0.f)
-	{
-		frag_color[0] = -frag_color[0];
-	}
-	if(frag_color[1] < 0.f)
-	{
-		frag_color[1] = -frag_color[1];
-	}
-	if(frag_color[2] < 0.f)
-	{
-		frag_color[2] = -frag_color[2];
-	}
-	frag_color[3] = 0.95f;
+	frag_color = abs(texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy));
 }
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 0730281d85..adeada04ca 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -36,18 +36,24 @@
 #include "llappviewer.h"
 #include "llwindow.h"
 #include "llpointer.h"
+#include "llspatialpartition.h"
 
 LLSceneMonitorView* gSceneMonitorView = NULL;
 
 LLSceneMonitor::LLSceneMonitor() : 
 	mEnabled(FALSE), 
-	mDiff(NULL), 
+	mDiff(NULL),
+	mDiffResult(0.f),
+	mDiffTolerance(0.1f),
 	mCurTarget(NULL), 
-	mNeedsUpdateDiff(FALSE), 
-	mDebugViewerVisible(FALSE)
+	mNeedsUpdateDiff(FALSE),
+	mHasNewDiff(FALSE),
+	mHasNewQueryResult(FALSE),
+	mDebugViewerVisible(FALSE),
+	mQueryObject(0)
 {
 	mFrames[0] = NULL;
-	mFrames[1] = NULL;
+	mFrames[1] = NULL;	
 }
 
 LLSceneMonitor::~LLSceneMonitor()
@@ -69,6 +75,15 @@ void LLSceneMonitor::reset()
 	mFrames[0] = NULL;
 	mFrames[1] = NULL;
 	mDiff = NULL;
+	mCurTarget = NULL;
+
+	unfreezeScene();
+
+	if(mQueryObject > 0)
+	{
+		release_occlusion_query_object_name(mQueryObject);
+		mQueryObject = 0;
+	}
 }
 
 void LLSceneMonitor::setDebugViewerVisible(BOOL visible) 
@@ -108,28 +123,6 @@ bool LLSceneMonitor::preCapture()
 		return false;
 	}
 
-	if (LLStartUp::getStartupState() < STATE_STARTED)
-	{
-		return false;
-	}
-
-	if(LLAppViewer::instance()->logoutRequestSent())
-	{
-		return false;
-	}
-
-	if(gWindowResized || gHeadlessClient || gTeleportDisplay || gRestoreGL || gDisconnected)
-	{
-		return false;
-	}
-
-	if (   !gViewerWindow->getActive()
-		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
-	{
-		return false;
-	}
-
 	if(timer.getElapsedTimeF32() < 1.0f)
 	{
 		return false;
@@ -174,12 +167,6 @@ bool LLSceneMonitor::preCapture()
 	return true;
 }
 
-void LLSceneMonitor::postCapture()
-{
-	mCurTarget = NULL;
-	mNeedsUpdateDiff = TRUE;
-}
-
 void LLSceneMonitor::freezeAvatar(LLCharacter* avatarp)
 {
 	mAvatarPauseHandles.push_back(avatarp->requestPause());
@@ -207,19 +194,14 @@ void LLSceneMonitor::unfreezeScene()
 	gSavedSettings.setBOOL("FreezeTime", FALSE);
 }
 
-LLRenderTarget* LLSceneMonitor::getDiffTarget() const 
-{
-	return mDiff;
-}
-
 void LLSceneMonitor::capture()
 {
-	static U32 count = 0;
-	if(count == gFrameCount)
+	static U32 last_capture_time = 0;
+	if(last_capture_time == gFrameCount)
 	{
 		return;
 	}
-	count = gFrameCount;
+	last_capture_time = gFrameCount;
 
 	preCapture();
 
@@ -239,7 +221,8 @@ void LLSceneMonitor::capture()
 	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);		
 	glBindFramebuffer(GL_FRAMEBUFFER, old_FBO);
 
-	postCapture();
+	mCurTarget = NULL;
+	mNeedsUpdateDiff = TRUE;
 }
 
 void LLSceneMonitor::compare()
@@ -248,6 +231,7 @@ void LLSceneMonitor::compare()
 	{
 		return;
 	}
+	mNeedsUpdateDiff = FALSE;
 
 	if(!mFrames[0] || !mFrames[1])
 	{
@@ -258,11 +242,6 @@ void LLSceneMonitor::compare()
 		return; //size does not match
 	}
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		return;
-	}
-
 	S32 width = gViewerWindow->getWindowWidthRaw();
 	S32 height = gViewerWindow->getWindowHeightRaw();
 	if(!mDiff)
@@ -274,9 +253,10 @@ void LLSceneMonitor::compare()
 	{
 		mDiff->resize(width, height, GL_RGBA);
 	}
+
 	mDiff->bindTarget();
 	mDiff->clear();
-
+	
 	gTwoTextureCompareProgram.bind();
 	
 	gGL.getTexUnit(0)->activate();
@@ -288,21 +268,108 @@ void LLSceneMonitor::compare()
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->bind(mFrames[1]);
 	gGL.getTexUnit(1)->activate();	
-			
+	
 	gl_rect_2d_simple_tex(width, height);
 	
-	mDiff->flush();
+	mDiff->flush();	
 
 	gTwoTextureCompareProgram.unbind();
-	
+
 	gGL.getTexUnit(0)->disable();
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->disable();
 	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
 
-	mNeedsUpdateDiff = FALSE;
+	mHasNewDiff = TRUE;
+	
+	//send out the query request.
+	queryDiff();
+}
+
+void LLSceneMonitor::queryDiff()
+{
+	if(mDebugViewerVisible)
+	{
+		return;
+	}
+
+	calcDiffAggregate();
+}
+
+//calculate Diff aggregate information in GPU, and enable gl occlusion query to capture it.
+void LLSceneMonitor::calcDiffAggregate()
+{
+	if(!mHasNewDiff && !mDebugViewerVisible)
+	{
+		return;
+	}	
+
+	if(!mQueryObject)
+	{
+		mQueryObject = get_new_occlusion_query_object_name();
+	}
+
+	LLGLDepthTest depth(true, false, GL_ALWAYS);
+	if(!mDebugViewerVisible)
+	{
+		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	}
+
+	LLGLSLShader* cur_shader = NULL;
+	
+	cur_shader = LLGLSLShader::sCurBoundShaderPtr;
+	gOneTextureFilterProgram.bind();
+	gOneTextureFilterProgram.uniform1f("tolerance", mDiffTolerance);
+
+	if(mHasNewDiff)
+	{
+		glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mQueryObject);
+	}
+
+	gl_draw_scaled_target(0, 0, mDiff->getWidth() * 0.5f, mDiff->getHeight() * 0.5f, mDiff);
+
+	if(mHasNewDiff)
+	{
+		glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+		mHasNewDiff = FALSE;	
+		mHasNewQueryResult = TRUE;
+	}
+		
+	gOneTextureFilterProgram.unbind();
+	
+	if(cur_shader != NULL)
+	{
+		cur_shader->bind();
+	}
+	
+	if(!mDebugViewerVisible)
+	{
+		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	}	
 }
 
+void LLSceneMonitor::fetchQueryResult()
+{
+	if(!mHasNewQueryResult)
+	{
+		return;
+	}
+	mHasNewQueryResult = FALSE;
+
+	GLuint available = 0;
+	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+	if(!available)
+	{
+		return;
+	}
+
+	GLuint count = 0;
+	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_ARB, &count);
+	
+	mDiffResult = count * 0.5f / (mDiff->getWidth() * mDiff->getHeight() * 0.25f);
+
+	//llinfos << count << " : " << mDiffResult << llendl;
+}
 //-------------------------------------------------------------------------------------------------------------
 //definition of class LLSceneMonitorView
 //-------------------------------------------------------------------------------------------------------------
@@ -330,27 +397,26 @@ void LLSceneMonitorView::setVisible(BOOL visible)
 
 void LLSceneMonitorView::draw()
 {
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		return;
-	}
-	LLRenderTarget* target = LLSceneMonitor::getInstance()->getDiffTarget();
+	const LLRenderTarget* target = LLSceneMonitor::getInstance()->getDiffTarget();
 	if(!target)
 	{
 		return;
 	}
 
-	S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f);
-	S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f);
+	S32 height = target->getHeight() * 0.5f;
+	S32 width = target->getWidth() * 0.5f;
+	//S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f);
+	//S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f);
 	
 	LLRect new_rect;
 	new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
 	setRect(new_rect);
 
-	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	//gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
+	//draw background
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
 	
-	gl_draw_scaled_target(0, 0, getRect().getWidth(), getRect().getHeight(), target);
+	LLSceneMonitor::getInstance()->calcDiffAggregate();
 
 	LLView::draw();
 }
diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h
index 648429f97b..db5ac3eeef 100644
--- a/indra/newview/llscenemonitor.h
+++ b/indra/newview/llscenemonitor.h
@@ -48,8 +48,14 @@ public:
 
 	void capture(); //capture the main frame buffer
 	void compare(); //compare the stored two buffers.	
+	void queryDiff();	
+	void fetchQueryResult();
+	void calcDiffAggregate();
+	void setDiffTolerance(F32 tol) {mDiffTolerance = tol;}
 
-	LLRenderTarget* getDiffTarget() const;
+	const LLRenderTarget* getDiffTarget() const {return mDiff;}
+	F32  getDiffTolerance() const {return mDiffTolerance;}
+	F32  getDiffResult() const { return mDiffResult;}
 	bool isEnabled()const {return mEnabled;}
 	
 private:
@@ -57,17 +63,22 @@ private:
 	void unfreezeScene();
 	void reset();
 	bool preCapture();
-	void postCapture();
-	
+
 private:
 	BOOL mEnabled;
 	BOOL mNeedsUpdateDiff;
+	BOOL mHasNewDiff;
+	BOOL mHasNewQueryResult;
 	BOOL mDebugViewerVisible;
 
 	LLRenderTarget* mFrames[2];
 	LLRenderTarget* mDiff;
 	LLRenderTarget* mCurTarget;
 
+	GLuint  mQueryObject; //used for glQuery
+	F32     mDiffResult;  //aggregate results of mDiff.
+	F32     mDiffTolerance; //pixels are filtered out when R+G+B < mDiffTolerance
+
 	std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
 };
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index e9ece331d1..b7694074a5 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -126,6 +126,16 @@ protected:
 
 static LLOcclusionQueryPool sQueryPool;
 
+GLuint get_new_occlusion_query_object_name()
+{
+	return sQueryPool.allocate();
+}
+
+void release_occlusion_query_object_name(GLuint name)
+{
+	sQueryPool.release(name);
+}
+
 //static counter for frame to switch LOD on
 
 void sg_assert(BOOL expr)
@@ -283,7 +293,7 @@ LLSpatialGroup::~LLSpatialGroup()
 		{
 			if (mOcclusionQuery[i])
 			{
-				sQueryPool.release(mOcclusionQuery[i]);
+				release_occlusion_query_object_name(mOcclusionQuery[i]);
 			}
 		}
 	}
@@ -879,7 +889,7 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
 
 				if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
 				{
-					sQueryPool.release(mOcclusionQuery[i]);
+					release_occlusion_query_object_name(mOcclusionQuery[i]);
 					mOcclusionQuery[i] = 0;
 				}
 			}
@@ -890,7 +900,7 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
 		mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
 		if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
 		{
-			sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+			release_occlusion_query_object_name(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 			mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
 		}
 	}
@@ -1237,7 +1247,7 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)
 		{
 			if (mOcclusionQuery[i])
 			{
-				sQueryPool.release(mOcclusionQuery[i]);
+				release_occlusion_query_object_name(mOcclusionQuery[i]);
 				mOcclusionQuery[i] = 0;
 			}
 		}
@@ -1318,7 +1328,7 @@ void LLSpatialGroup::checkOcclusion()
 				}
 				else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
 				{ //delete the query to avoid holding onto hundreds of pending queries
-					sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+					release_occlusion_query_object_name(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 					mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
 				}
 				
@@ -1390,7 +1400,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 					{
 						LLFastTimer t(FTM_OCCLUSION_ALLOCATE);
-						mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
+						mOcclusionQuery[LLViewerCamera::sCurCameraID] = get_new_occlusion_query_object_name();
 					}
 
 					// Depth clamp all water to avoid it being culled as a result of being
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 079c0f58f0..57e986fb80 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -58,6 +58,8 @@ void pushVerts(LLFace* face, U32 mask);
 // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
 U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center);
 U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center);
+GLuint get_new_occlusion_query_object_name();
+void release_occlusion_query_object_name(GLuint name);
 
 class LLDrawInfo : public LLRefCount 
 {
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 5295573709..1aa36eafee 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -79,6 +79,7 @@ LLGLSLShader	gSplatTextureRectProgram;
 LLGLSLShader	gGlowCombineFXAAProgram;
 LLGLSLShader	gTwoTextureAddProgram;
 LLGLSLShader	gTwoTextureCompareProgram;
+LLGLSLShader	gOneTextureFilterProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
 LLGLSLShader	gClipProgram;
@@ -674,6 +675,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gGlowCombineFXAAProgram.unload();
 	gTwoTextureAddProgram.unload();
 	gTwoTextureCompareProgram.unload();
+	gOneTextureFilterProgram.unload();
 	gOneTextureNoColorProgram.unload();
 	gSolidColorProgram.unload();
 
@@ -2724,6 +2726,21 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		}
 	}
 
+	if (success)
+	{
+		gOneTextureFilterProgram.mName = "One Texture Filter Shader";
+		gOneTextureFilterProgram.mShaderFiles.clear();
+		gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterV.glsl", GL_VERTEX_SHADER_ARB));
+		gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gOneTextureFilterProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gOneTextureFilterProgram.createShader(NULL, NULL);
+		if (success)
+		{
+			gOneTextureFilterProgram.bind();
+			gOneTextureFilterProgram.uniform1i("tex0", 0);
+		}
+	}
+
 	if (success)
 	{
 		gOneTextureNoColorProgram.mName = "One Texture No Color Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 8a706daa8f..3e7c615f23 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -235,7 +235,9 @@ extern LLGLSLShader			gAlphaMaskProgram;
 extern LLGLSLShader			gTwoTextureAddProgram;
 //output tex0[tc0] - tex1[tc1]
 extern LLGLSLShader			gTwoTextureCompareProgram;
-						
+//discard some fragments based on user-set color tolerance
+extern LLGLSLShader			gOneTextureFilterProgram;
+
 extern LLGLSLShader			gOneTextureNoColorProgram;
 
 //object shaders
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 850714f676..d8af7a5cfb 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -112,6 +112,7 @@
 #include "llfloaterpathfindingconsole.h"
 #include "llfloaterpathfindingcharacters.h"
 #include "llpathfindingpathtool.h"
+#include "llscenemonitor.h"
 
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
@@ -3161,7 +3162,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 		}
 	}
 		
-	postSort(camera);	
+	postSort(camera);
+
+	LLSceneMonitor::getInstance()->fetchQueryResult();
 }
 
 void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
-- 
GitLab