From 954c8fb1e3c47b3ebf219f97129e5c6e9bf911b8 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 10 Sep 2013 15:33:26 -0500
Subject: [PATCH] MAINT-3131 Add a GPU memory bandwidth benchmark.

---
 .../shaders/class1/interface/benchmarkF.glsl  |  39 +++++
 .../shaders/class1/interface/benchmarkV.glsl  |  38 +++++
 indra/newview/llglsandbox.cpp                 | 133 +++++++++++++++++-
 indra/newview/llviewermenu.cpp                |  12 ++
 indra/newview/llviewershadermgr.cpp           |  23 +++
 indra/newview/llviewershadermgr.h             |   1 +
 .../skins/default/xui/en/menu_viewer.xml      |   6 +
 7 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/benchmarkF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/benchmarkV.glsl

diff --git a/indra/newview/app_settings/shaders/class1/interface/benchmarkF.glsl b/indra/newview/app_settings/shaders/class1/interface/benchmarkF.glsl
new file mode 100644
index 00000000000..1936e0dcaa6
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/benchmarkF.glsl
@@ -0,0 +1,39 @@
+/** 
+ * @file benchmarkF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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 diffuseMap;
+
+VARYING vec2 tc0;
+
+void main() 
+{
+	frag_color = texture2D(diffuseMap, tc0);
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/benchmarkV.glsl b/indra/newview/app_settings/shaders/class1/interface/benchmarkV.glsl
new file mode 100644
index 00000000000..7beb20ede46
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/benchmarkV.glsl
@@ -0,0 +1,38 @@
+/** 
+ * @file benchmarkV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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;
+
+VARYING vec2 tc0;
+
+void main()
+{
+	gl_Position = vec4(position, 1.0); 
+	
+	tc0 = (position.xy*0.5+0.5);
+}
+
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 60fa53f491c..83cabf7d551 100755
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -62,6 +62,7 @@
 #include "llresmgr.h"
 #include "pipeline.h"
 #include "llspatialpartition.h"
+#include "llviewershadermgr.h"
 
 // Height of the yellow selection highlight posts for land
 const F32 PARCEL_POST_HEIGHT = 0.666f;
@@ -767,7 +768,6 @@ void draw_line_cube(F32 width, const LLVector3& center)
 	gGL.vertex3f(center.mV[VX] + width ,center.mV[VY] - width,center.mV[VZ] - width);
 }
 
-
 void LLViewerObjectList::renderObjectBeacons()
 {
 	if (mDebugBeacons.empty())
@@ -878,3 +878,134 @@ void LLViewerObjectList::renderObjectBeacons()
 }
 
 
+void gpu_benchmark()
+{
+	if (!LLGLSLShader::sNoFixedFunction)
+	{ //don't bother benchmarking the fixed function
+		return;
+	}
+
+	//measure memory bandwidth by:
+	// - allocating a batch of textures and render targets
+	// - rendering those textures to those render targets
+	// - recording time taken
+	// - taking the median time for a given number of samples
+	
+	//resolution of textures/render targets
+	const U32 res = 1024;
+	
+	//number of textures
+	const U32 count = 32;
+
+	//number of samples to take
+	const S32 samples = 64;
+
+	LLGLSLShader::initProfile();
+
+	LLRenderTarget dest[count];
+	U32 source[count];
+	LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGBA, count, source);
+	std::vector<F32> results;
+
+	//build a random texture
+	U8 pixels[res*res*4];
+
+	for (U32 i = 0; i < res*res*4; ++i)
+	{
+		pixels[i] = (U8) ll_rand(255);
+	}
+	
+
+	gGL.setColorMask(true, true);
+	LLGLDepthTest depth(GL_FALSE);
+
+	for (U32 i = 0; i < count; ++i)
+	{ //allocate render targets and textures
+		dest[i].allocate(res,res,GL_RGBA,false, false, LLTexUnit::TT_TEXTURE, true);
+		dest[i].bindTarget();
+		dest[i].clear();
+		dest[i].flush();
+
+		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, source[i]);
+		LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_RGBA, res,res,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+	}
+
+	//make a dummy triangle to draw with
+	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STATIC_DRAW_ARB);
+	buff->allocateBuffer(3, 0, true);
+
+	LLStrider<LLVector3> v;
+	LLStrider<LLVector2> tc;
+
+	buff->getVertexStrider(v);
+	
+	v[0].set(-1,1,0);
+	v[1].set(-1,-3,0);
+	v[2].set(3,1,0);
+	buff->flush();
+
+	gBenchmarkProgram.bind();
+	buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+	//wait for any previoius GL commands to finish
+	glFinish();
+	
+	for (S32 c = -1; c < samples; ++c)
+	{
+		LLTimer timer;
+		timer.start();
+
+		for (U32 i = 0; i < count; ++i)
+		{
+			dest[i].bindTarget();
+			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, source[i]);
+			buff->drawArrays(LLRender::TRIANGLES, 0, 3);
+			dest[i].flush();
+		}
+		
+		//wait for current batch of copies to finish
+		glFinish();
+
+		F32 time = timer.getElapsedTimeF32();
+
+		if (c >= 0) // <-- ignore the first sample as it tends to be artificially slow
+		{ 
+			//store result in gigabytes per second
+			F32 gb = (F32) ((F64) (res*res*8*count))/(1000000000);
+
+			F32 gbps = gb/time;
+
+			results.push_back(gbps);
+		}
+	}
+
+	gBenchmarkProgram.unbind();
+
+	LLGLSLShader::finishProfile();
+	
+	LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGBA, 0, count, source);
+
+
+	std::sort(results.begin(), results.end());
+
+	F32 gbps = results[results.size()/2];
+
+	llinfos << "Memory bandwidth is " << llformat("%.3f", gbps) << "GB/sec according to CPU timers" << llendl;
+	
+	F32 ms = gBenchmarkProgram.mTimeElapsed/1000000.f;
+	F32 seconds = ms/1000.f;
+
+	F64 samples_drawn = res*res*count*samples;
+	F32 samples_sec = (samples_drawn/1000000000.0)/seconds;
+	gbps = samples_sec*8;
+
+	if (gGLManager.mHasTimerQuery)
+	{
+		llinfos << "Memory bandwidth is " << llformat("%.3f", gbps) << "GB/sec according to ARB_timer_query" << llendl;
+	}
+	else
+	{
+		llinfos << "ARB_timer_query unavailable." << llendl;
+	}
+}
+
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ac2940fcfcc..3710522fddd 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7193,6 +7193,17 @@ class LLAdvancedClickRenderProfile: public view_listener_t
 	}
 };
 
+void gpu_benchmark();
+
+class LLAdvancedClickRenderBenchmark: public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		gpu_benchmark();
+		return true;
+	}
+};
+
 void menu_toggle_attached_lights(void* user_data)
 {
 	LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
@@ -8633,6 +8644,7 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption");
 	view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption");
 	view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
+	view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
 
 	#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
 	view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 553f6a2d599..e88b22b4617 100755
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -87,6 +87,8 @@ LLGLSLShader	gClipProgram;
 LLGLSLShader	gDownsampleDepthProgram;
 LLGLSLShader	gDownsampleDepthRectProgram;
 LLGLSLShader	gAlphaMaskProgram;
+LLGLSLShader	gBenchmarkProgram;
+
 
 //object shaders
 LLGLSLShader		gObjectSimpleProgram;
@@ -681,6 +683,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gClipProgram.unload();
 	gDownsampleDepthProgram.unload();
 	gDownsampleDepthRectProgram.unload();
+	gBenchmarkProgram.unload();
 	gAlphaMaskProgram.unload();
 	gUIProgram.unload();
 	gPathfindingProgram.unload();
@@ -3188,6 +3191,26 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		success = gDownsampleDepthProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gBenchmarkProgram.mName = "Benchmark Shader";
+		gBenchmarkProgram.mShaderFiles.clear();
+		gBenchmarkProgram.mShaderFiles.push_back(make_pair("interface/benchmarkV.glsl", GL_VERTEX_SHADER_ARB));
+		gBenchmarkProgram.mShaderFiles.push_back(make_pair("interface/benchmarkF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gBenchmarkProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gBenchmarkProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDownsampleDepthRectProgram.mName = "DownsampleDepthRect Shader";
+		gDownsampleDepthRectProgram.mShaderFiles.clear();
+		gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthV.glsl", GL_VERTEX_SHADER_ARB));
+		gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthRectF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDownsampleDepthRectProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gDownsampleDepthRectProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDownsampleDepthRectProgram.mName = "DownsampleDepthRect Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 3d89f8d20a5..53569ca7ab5 100755
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -183,6 +183,7 @@ extern LLGLSLShader			gDebugProgram;
 extern LLGLSLShader			gClipProgram;
 extern LLGLSLShader			gDownsampleDepthProgram;
 extern LLGLSLShader			gDownsampleDepthRectProgram;
+extern LLGLSLShader			gBenchmarkProgram;
 
 //output tex0[tc0] + tex1[tc1]
 extern LLGLSLShader			gTwoTextureAddProgram;
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 95a7839337b..8f9522c180a 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2397,6 +2397,12 @@
             <menu_item_call.on_click
              function="Advanced.ClickRenderProfile" />
           </menu_item_call>
+            <menu_item_call
+             label="Benchmark"
+             name="Benchmark">
+              <menu_item_call.on_click
+               function="Advanced.ClickRenderBenchmark" />
+          </menu_item_call>
         </menu>
       <menu
         create_jump_keys="true"
-- 
GitLab