• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Depth buffer performance tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3pDepthTests.hpp"
25 
26 #include "glsCalibration.hpp"
27 
28 #include "gluShaderProgram.hpp"
29 #include "gluObjectWrapper.hpp"
30 #include "gluPixelTransfer.hpp"
31 
32 #include "glwFunctions.hpp"
33 #include "glwEnums.hpp"
34 
35 #include "tcuTestLog.hpp"
36 #include "tcuStringTemplate.hpp"
37 #include "tcuCPUWarmup.hpp"
38 #include "tcuCommandLine.hpp"
39 #include "tcuResultCollector.hpp"
40 
41 #include "deClock.h"
42 #include "deString.h"
43 #include "deMath.h"
44 #include "deStringUtil.hpp"
45 #include "deRandom.hpp"
46 #include "deUniquePtr.hpp"
47 
48 #include <vector>
49 #include <algorithm>
50 
51 namespace deqp
52 {
53 namespace gles3
54 {
55 namespace Performance
56 {
57 namespace
58 {
59 using namespace glw;
60 using de::MovePtr;
61 using tcu::TestContext;
62 using tcu::TestLog;
63 using tcu::Vec4;
64 using tcu::Vec3;
65 using tcu::Vec2;
66 using glu::RenderContext;
67 using glu::ProgramSources;
68 using glu::ShaderSource;
69 using std::vector;
70 using std::string;
71 using std::map;
72 
73 struct Sample
74 {
75 	deInt64	nullTime;
76 	deInt64	baseTime;
77 	deInt64	testTime;
78 	int		order;
79 	int		workload;
80 };
81 
82 struct SampleParams
83 {
84 	int step;
85 	int measurement;
86 
SampleParamsdeqp::gles3::Performance::__anon3060813d0111::SampleParams87 	SampleParams(int step_, int measurement_) : step(step_), measurement(measurement_) {}
88 };
89 
90 typedef vector<float> Geometry;
91 
92 struct ObjectData
93 {
94 	ProgramSources	shader;
95 	Geometry		geometry;
96 
ObjectDatadeqp::gles3::Performance::__anon3060813d0111::ObjectData97 	ObjectData (const ProgramSources& shader_, const Geometry& geometry_) : shader(shader_), geometry(geometry_) {}
98 };
99 
100 class RenderData
101 {
102 public:
103 								RenderData		(const ObjectData& object, const glu::RenderContext& renderCtx, TestLog& log);
~RenderData(void)104 								~RenderData		(void) {};
105 
106 	const glu::ShaderProgram	m_program;
107 	const glu::VertexArray		m_vao;
108 	const glu::Buffer			m_vbo;
109 
110 	const int					m_numVertices;
111 };
112 
RenderData(const ObjectData & object,const glu::RenderContext & renderCtx,TestLog & log)113 RenderData::RenderData (const ObjectData& object, const  glu::RenderContext& renderCtx, TestLog& log)
114 	: m_program		(renderCtx, object.shader)
115 	, m_vao			(renderCtx.getFunctions())
116 	, m_vbo			(renderCtx.getFunctions())
117 	, m_numVertices	(int(object.geometry.size())/4)
118 {
119 	const glw::Functions& gl = renderCtx.getFunctions();
120 
121 	if (!m_program.isOk())
122 		log << m_program;
123 
124 	gl.bindBuffer(GL_ARRAY_BUFFER, *m_vbo);
125 	gl.bufferData(GL_ARRAY_BUFFER, object.geometry.size() * sizeof(float), &object.geometry[0], GL_STATIC_DRAW);
126 	gl.bindAttribLocation(m_program.getProgram(), 0, "a_position");
127 
128 	gl.bindVertexArray(*m_vao);
129 	gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
130 	gl.enableVertexAttribArray(0);
131 	gl.bindVertexArray(0);
132 }
133 
134 namespace Utils
135 {
getFullscreenQuad(float depth)136 	vector<float> getFullscreenQuad (float depth)
137 	{
138 		const float data[] =
139 		{
140 			+1.0f, +1.0f, depth, 0.0f, // .w is gl_VertexId%3 since Nexus 4&5 can't handle that on their own
141 			+1.0f, -1.0f, depth, 1.0f,
142 			-1.0f, -1.0f, depth, 2.0f,
143 			-1.0f, -1.0f, depth, 0.0f,
144 			-1.0f, +1.0f, depth, 1.0f,
145 			+1.0f, +1.0f, depth, 2.0f,
146 		};
147 
148 		return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
149 	}
150 
getFullscreenQuadWithGradient(float depth0,float depth1)151 	vector<float> getFullscreenQuadWithGradient (float depth0, float depth1)
152 	{
153 		const float data[] =
154 		{
155 			+1.0f, +1.0f, depth0, 0.0f,
156 			+1.0f, -1.0f, depth0, 1.0f,
157 			-1.0f, -1.0f, depth1, 2.0f,
158 			-1.0f, -1.0f, depth1, 0.0f,
159 			-1.0f, +1.0f, depth1, 1.0f,
160 			+1.0f, +1.0f, depth0, 2.0f,
161 		};
162 
163 		return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
164 	}
165 
getPartScreenQuad(float coverage,float depth)166 	vector<float> getPartScreenQuad (float coverage, float depth)
167 	{
168 		const float xMax	= -1.0f + 2.0f*coverage;
169 		const float data[]	=
170 		{
171 			 xMax, +1.0f, depth, 0.0f,
172 			 xMax, -1.0f, depth, 1.0f,
173 			-1.0f, -1.0f, depth, 2.0f,
174 			-1.0f, -1.0f, depth, 0.0f,
175 			-1.0f, +1.0f, depth, 1.0f,
176 			 xMax, +1.0f, depth, 2.0f,
177 		};
178 
179 		return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
180 	}
181 
182 	// Axis aligned grid. Depth of vertices is baseDepth +/- depthNoise
getFullScreenGrid(int resolution,deUint32 seed,float baseDepth,float depthNoise,float xyNoise)183 	vector<float> getFullScreenGrid (int resolution, deUint32 seed, float baseDepth, float depthNoise, float xyNoise)
184 	{
185 		const int		gridsize	= resolution+1;
186 		vector<Vec3>	vertices	(gridsize*gridsize);
187 		vector<float>	retval;
188 		de::Random		rng			(seed);
189 
190 		for (int y = 0; y < gridsize; y++)
191 		for (int x = 0; x < gridsize; x++)
192 		{
193 			const bool	isEdge	= x == 0 || y == 0 || x == resolution || y == resolution;
194 			const float x_		= float(x)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
195 			const float y_		= float(y)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
196 			const float z_		= baseDepth + rng.getFloat(-depthNoise, +depthNoise);
197 
198 			vertices[y*gridsize + x] = Vec3(x_, y_, z_);
199 		}
200 
201 		retval.reserve(resolution*resolution*6);
202 
203 		for (int y = 0; y < resolution; y++)
204 		for (int x = 0; x < resolution; x++)
205 		{
206 			const Vec3& p0 = vertices[(y+0)*gridsize + (x+0)];
207 			const Vec3& p1 = vertices[(y+0)*gridsize + (x+1)];
208 			const Vec3& p2 = vertices[(y+1)*gridsize + (x+0)];
209 			const Vec3& p3 = vertices[(y+1)*gridsize + (x+1)];
210 
211 			const float temp[6*4] =
212 			{
213 				p0.x(), p0.y(), p0.z(), 0.0f,
214 				p2.x(), p2.y(), p2.z(), 1.0f,
215 				p1.x(), p1.y(), p1.z(), 2.0f,
216 
217 				p3.x(), p3.y(), p3.z(), 0.0f,
218 				p1.x(), p1.y(), p1.z(), 1.0f,
219 				p2.x(), p2.y(), p2.z(), 2.0f,
220 			};
221 
222 			retval.insert(retval.end(), DE_ARRAY_BEGIN(temp), DE_ARRAY_END(temp));
223 		}
224 
225 		return retval;
226 	}
227 
228 	// Outputs barycentric coordinates as v_bcoords. Otherwise a passthrough shader
getBaseVertexShader(void)229 	string getBaseVertexShader (void)
230 	{
231 		return "#version 300 es\n"
232 				"in highp vec4 a_position;\n"
233 				"out mediump vec3 v_bcoords;\n"
234 				"void main()\n"
235 				"{\n"
236 				"	v_bcoords = vec3(0, 0, 0);\n"
237 				"	v_bcoords[int(a_position.w)] = 1.0;\n"
238 				"	gl_Position = vec4(a_position.xyz, 1.0);\n"
239 				"}\n";
240 	}
241 
242 	// Adds noise to coordinates based on InstanceID Outputs barycentric coordinates as v_bcoords
getInstanceNoiseVertexShader(void)243 	string getInstanceNoiseVertexShader (void)
244 	{
245 		return "#version 300 es\n"
246 				"in highp vec4 a_position;\n"
247 				"out mediump vec3 v_bcoords;\n"
248 				"void main()\n"
249 				"{\n"
250 				"	v_bcoords = vec3(0, 0, 0);\n"
251 				"	v_bcoords[int(a_position.w)] = 1.0;\n"
252 				"	vec3 noise = vec3(sin(float(gl_InstanceID)*1.05), sin(float(gl_InstanceID)*1.23), sin(float(gl_InstanceID)*1.71));\n"
253 				"	gl_Position = vec4(a_position.xyz + noise * 0.005, 1.0);\n"
254 				"}\n";
255 	}
256 
257 	// Renders green triangles with edges highlighted. Exact shade depends on depth.
getDepthAsGreenFragmentShader(void)258 	string getDepthAsGreenFragmentShader (void)
259 	{
260 		return	"#version 300 es\n"
261 				"in mediump vec3 v_bcoords;\n"
262 				"out mediump vec4 fragColor;\n"
263 				"void main()\n"
264 				"{\n"
265 				"	mediump float d = gl_FragCoord.z;\n"
266 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
267 				"		fragColor = vec4(d,1,d,1);\n"
268 				"	else\n"
269 				"		fragColor = vec4(0,d,0,1);\n"
270 				"}\n";
271 	}
272 
273 	// Renders green triangles with edges highlighted. Exact shade depends on depth.
getDepthAsRedFragmentShader(void)274 	string getDepthAsRedFragmentShader (void)
275 	{
276 		return	"#version 300 es\n"
277 				"in mediump vec3 v_bcoords;\n"
278 				"out mediump vec4 fragColor;\n"
279 				"void main()\n"
280 				"{\n"
281 				"	mediump float d = gl_FragCoord.z;\n"
282 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
283 				"		fragColor = vec4(1,d,d,1);\n"
284 				"	else\n"
285 				"		fragColor = vec4(d,0,0,1);\n"
286 				"}\n";
287 	}
288 
289 	// Basic time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
getArithmeticWorkloadFragmentShader(void)290 	string getArithmeticWorkloadFragmentShader (void)
291 	{
292 
293 		return	"#version 300 es\n"
294 				"in mediump vec3 v_bcoords;\n"
295 				"out mediump vec4 fragColor;\n"
296 				"uniform mediump int u_iterations;\n"
297 				"void main()\n"
298 				"{\n"
299 				"	mediump float d = gl_FragCoord.z;\n"
300 				"	for (int i = 0; i<u_iterations; i++)\n"
301 				// cos(a)^2 + sin(a)^2 == 1. since d is in range [0,1] this will lose a few ULP's of precision per iteration but should not significantly change the value of d without extreme iteration counts
302 				"		d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
303 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
304 				"		fragColor = vec4(1,d,d,1);\n"
305 				"	else\n"
306 				"		fragColor = vec4(d,0,0,1);\n"
307 				"}\n";
308 	}
309 
310 	// Arithmetic workload shader but contains discard
getArithmeticWorkloadDiscardFragmentShader(void)311 	string getArithmeticWorkloadDiscardFragmentShader (void)
312 	{
313 		return	"#version 300 es\n"
314 				"in mediump vec3 v_bcoords;\n"
315 				"out mediump vec4 fragColor;\n"
316 				"uniform mediump int u_iterations;\n"
317 				"void main()\n"
318 				"{\n"
319 				"	mediump float d = gl_FragCoord.z;\n"
320 				"	for (int i = 0; i<u_iterations; i++)\n"
321 				"		d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
322 				"	if (d < 0.5) discard;\n"
323 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
324 				"		fragColor = vec4(1,d,d,1);\n"
325 				"	else\n"
326 				"		fragColor = vec4(d,0,0,1);\n"
327 				"}\n";
328 	}
329 
330 	// Texture fetch based time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
getTextureWorkloadFragmentShader(void)331 	string getTextureWorkloadFragmentShader (void)
332 	{
333 		return  "#version 300 es\n"
334 				"in mediump vec3 v_bcoords;\n"
335 				"out mediump vec4 fragColor;\n"
336 				"uniform mediump int u_iterations;\n"
337 				"uniform sampler2D u_texture;\n"
338 				"void main()\n"
339 				"{\n"
340 				"	mediump float d = gl_FragCoord.z;\n"
341 				"	for (int i = 0; i<u_iterations; i++)\n"
342 				"		d *= texture(u_texture, (gl_FragCoord.xy+vec2(i))/512.0).r;\n" // Texture is expected to be fully white
343 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
344 				"		fragColor = vec4(1,1,1,1);\n"
345 				"	else\n"
346 				"		fragColor = vec4(d,0,0,1);\n"
347 				"}\n";
348 	}
349 
350 	// Discard fragments in a grid pattern
getGridDiscardFragmentShader(int gridsize)351 	string getGridDiscardFragmentShader (int gridsize)
352 	{
353 		const string		fragSrc = "#version 300 es\n"
354 									  "in mediump vec3 v_bcoords;\n"
355 									  "out mediump vec4 fragColor;\n"
356 									  "void main()\n"
357 									  "{\n"
358 									  "	mediump float d = gl_FragCoord.z;\n"
359 									  "	if ((int(gl_FragCoord.x)/${GRIDRENDER_SIZE} + int(gl_FragCoord.y)/${GRIDRENDER_SIZE})%2 == 0)\n"
360 									  "		discard;\n"
361 									  "	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
362 									  "		fragColor = vec4(d,1,d,1);\n"
363 									  "	else\n"
364 									  "		fragColor = vec4(0,d,0,1);\n"
365 									  "}\n";
366 		map<string, string>	params;
367 
368 		params["GRIDRENDER_SIZE"] = de::toString(gridsize);
369 
370 		return tcu::StringTemplate(fragSrc).specialize(params);
371 	}
372 
373 	// A static increment to frag depth
getStaticFragDepthFragmentShader(void)374 	string getStaticFragDepthFragmentShader (void)
375 	{
376 		return	"#version 300 es\n"
377 				"in mediump vec3 v_bcoords;\n"
378 				"out mediump vec4 fragColor;\n"
379 				"void main()\n"
380 				"{\n"
381 				"	mediump float d = gl_FragCoord.z;\n"
382 				"	gl_FragDepth = gl_FragCoord.z + 0.1;\n"
383 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
384 				"		fragColor = vec4(d,1,d,1);\n"
385 				"	else\n"
386 				"		fragColor = vec4(0,d,0,1);\n"
387 				"}\n";
388 	}
389 
390 	// A trivial dynamic change to frag depth
getDynamicFragDepthFragmentShader(void)391 	string getDynamicFragDepthFragmentShader (void)
392 	{
393 		return	"#version 300 es\n"
394 				"in mediump vec3 v_bcoords;\n"
395 				"out mediump vec4 fragColor;\n"
396 				"void main()\n"
397 				"{\n"
398 				"	mediump float d = gl_FragCoord.z;\n"
399 				"	gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1
400 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
401 				"		fragColor = vec4(d,1,d,1);\n"
402 				"	else\n"
403 				"		fragColor = vec4(0,d,0,1);\n"
404 				"}\n";
405 	}
406 
407 	// A static increment to frag depth
getStaticFragDepthArithmeticWorkloadFragmentShader(void)408 	string getStaticFragDepthArithmeticWorkloadFragmentShader (void)
409 	{
410 		return	"#version 300 es\n"
411 				"in mediump vec3 v_bcoords;\n"
412 				"out mediump vec4 fragColor;\n"
413 				"uniform mediump int u_iterations;\n"
414 				"void main()\n"
415 				"{\n"
416 				"	mediump float d = gl_FragCoord.z;\n"
417 				"	gl_FragDepth = gl_FragCoord.z + 0.1;\n"
418 				"	for (int i = 0; i<u_iterations; i++)\n"
419 				"		d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
420 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
421 				"		fragColor = vec4(1,d,d,1);\n"
422 				"	else\n"
423 				"		fragColor = vec4(d,0,0,1);\n"
424 				"}\n";
425 	}
426 
427 	// A trivial dynamic change to frag depth
getDynamicFragDepthArithmeticWorkloadFragmentShader(void)428 	string getDynamicFragDepthArithmeticWorkloadFragmentShader (void)
429 	{
430 		return	"#version 300 es\n"
431 				"in mediump vec3 v_bcoords;\n"
432 				"out mediump vec4 fragColor;\n"
433 				"uniform mediump int u_iterations;\n"
434 				"void main()\n"
435 				"{\n"
436 				"	mediump float d = gl_FragCoord.z;\n"
437 				"	gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1
438 				"	for (int i = 0; i<u_iterations; i++)\n"
439 				"		d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
440 				"	if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
441 				"		fragColor = vec4(1,d,d,1);\n"
442 				"	else\n"
443 				"		fragColor = vec4(d,0,0,1);\n"
444 				"}\n";
445 	}
446 
getBaseShader(void)447 	glu::ProgramSources getBaseShader (void)
448 	{
449 		return glu::makeVtxFragSources(getBaseVertexShader(), getDepthAsGreenFragmentShader());
450 	}
451 
getArithmeticWorkloadShader(void)452 	glu::ProgramSources getArithmeticWorkloadShader (void)
453 	{
454 		return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadFragmentShader());
455 	}
456 
getArithmeticWorkloadDiscardShader(void)457 	glu::ProgramSources getArithmeticWorkloadDiscardShader (void)
458 	{
459 		return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadDiscardFragmentShader());
460 	}
461 
getTextureWorkloadShader(void)462 	glu::ProgramSources getTextureWorkloadShader (void)
463 	{
464 		return glu::makeVtxFragSources(getBaseVertexShader(), getTextureWorkloadFragmentShader());
465 	}
466 
getGridDiscardShader(int gridsize)467 	glu::ProgramSources getGridDiscardShader (int gridsize)
468 	{
469 		return glu::makeVtxFragSources(getBaseVertexShader(), getGridDiscardFragmentShader(gridsize));
470 	}
471 
quadWith(const glu::ProgramSources & shader,float depth)472 	inline ObjectData quadWith (const glu::ProgramSources& shader, float depth)
473 	{
474 		return ObjectData(shader, getFullscreenQuad(depth));
475 	}
476 
quadWith(const string & fragShader,float depth)477 	inline ObjectData quadWith (const string& fragShader, float depth)
478 	{
479 		return ObjectData(glu::makeVtxFragSources(getBaseVertexShader(), fragShader), getFullscreenQuad(depth));
480 	}
481 
variableQuad(float depth)482 	inline ObjectData variableQuad (float depth)
483 	{
484 		return ObjectData(glu::makeVtxFragSources(getInstanceNoiseVertexShader(), getDepthAsRedFragmentShader()), getFullscreenQuad(depth));
485 	}
486 
fastQuad(float depth)487 	inline ObjectData fastQuad (float depth)
488 	{
489 		return ObjectData(getBaseShader(), getFullscreenQuad(depth));
490 	}
491 
slowQuad(float depth)492 	inline ObjectData slowQuad (float depth)
493 	{
494 		return ObjectData(getArithmeticWorkloadShader(), getFullscreenQuad(depth));
495 	}
496 
fastQuadWithGradient(float depth0,float depth1)497 	inline ObjectData fastQuadWithGradient (float depth0, float depth1)
498 	{
499 		return ObjectData(getBaseShader(), getFullscreenQuadWithGradient(depth0, depth1));
500 	}
501 } // Utils
502 
503 // Shared base
504 class BaseCase : public tcu::TestCase
505 {
506 public:
507 	enum {RENDER_SIZE = 512};
508 
509 							BaseCase			(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
~BaseCase(void)510 	virtual					~BaseCase			(void) {}
511 
512 	virtual IterateResult	iterate				(void);
513 
514 protected:
515 	void					logSamples			(const vector<Sample>& samples, const string& name, const string& desc);
516 	void					logGeometry			(const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg);
517 	virtual void			logAnalysis			(const vector<Sample>& samples) = 0;
518 	virtual void			logDescription		(void) = 0;
519 
520 	virtual ObjectData		genOccluderGeometry	(void) const = 0;
521 	virtual ObjectData		genOccludedGeometry	(void) const = 0;
522 
523 	virtual int				calibrate			(void) const = 0;
524 	virtual Sample			renderSample		(const RenderData& occluder, const RenderData& occluded, int workload) const = 0;
525 
526 	void					render				(const RenderData& data) const;
527 	void					render				(const RenderData& data, int instances) const;
528 
529 	const RenderContext&	m_renderCtx;
530 	tcu::ResultCollector	m_results;
531 
532 	enum {ITERATION_STEPS = 10, ITERATION_SAMPLES = 16};
533 };
534 
BaseCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)535 BaseCase::BaseCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
536 	: TestCase		(testCtx, tcu::NODETYPE_PERFORMANCE, name, desc)
537 	, m_renderCtx	(renderCtx)
538 {
539 }
540 
iterate(void)541 BaseCase::IterateResult BaseCase::iterate (void)
542 {
543 	typedef de::MovePtr<RenderData> RenderDataP;
544 
545 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
546 	TestLog&				log					= m_testCtx.getLog();
547 
548 	const glu::Framebuffer	framebuffer			(gl);
549 	const glu::Renderbuffer	renderbuffer		(gl);
550 	const glu::Renderbuffer	depthbuffer			(gl);
551 
552 	vector<Sample>			results;
553 	vector<int>				params;
554 	RenderDataP				occluderData;
555 	RenderDataP				occludedData;
556 	tcu::TextureLevel		resultTex			(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), RENDER_SIZE, RENDER_SIZE);
557 	int						maxWorkload			= 0;
558 	de::Random				rng					(deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed());
559 
560 	logDescription();
561 
562 	gl.bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer);
563 	gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE);
564 	gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuffer);
565 	gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, RENDER_SIZE, RENDER_SIZE);
566 
567 	gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
568 	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *renderbuffer);
569 	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *depthbuffer);
570 	gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
571 	gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
572 
573 	maxWorkload = calibrate();
574 
575 	// Setup data
576 	occluderData = RenderDataP(new RenderData (genOccluderGeometry(), m_renderCtx, log));
577 	occludedData = RenderDataP(new RenderData (genOccludedGeometry(), m_renderCtx, log));
578 
579 	TCU_CHECK(occluderData->m_program.isOk());
580 	TCU_CHECK(occludedData->m_program.isOk());
581 
582 	// Force initialization of GPU resources
583 	gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
584 	gl.enable(GL_DEPTH_TEST);
585 
586 	render(*occluderData);
587 	render(*occludedData);
588 	glu::readPixels(m_renderCtx, 0, 0, resultTex.getAccess());
589 
590 	logGeometry(resultTex.getAccess(), occluderData->m_program, occludedData->m_program);
591 
592 	params.reserve(ITERATION_STEPS*ITERATION_SAMPLES);
593 
594 	// Setup parameters
595 	for (int step = 0; step < ITERATION_STEPS; step++)
596 	{
597 		const int workload = maxWorkload*step/ITERATION_STEPS;
598 
599 		for (int count = 0; count < ITERATION_SAMPLES; count++)
600 			params.push_back(workload);
601 	}
602 
603 	rng.shuffle(params.begin(), params.end());
604 
605 	// Render samples
606 	for (size_t ndx = 0; ndx < params.size(); ndx++)
607 	{
608 		const int	workload	= params[ndx];
609 		Sample		sample		= renderSample(*occluderData, *occludedData, workload);
610 
611 		sample.workload = workload;
612 		sample.order = int(ndx);
613 
614 		results.push_back(sample);
615 	}
616 
617 	logSamples(results, "Samples", "Samples");
618 	logAnalysis(results);
619 
620 	m_results.setTestContextResult(m_testCtx);
621 
622 	return STOP;
623 }
624 
logSamples(const vector<Sample> & samples,const string & name,const string & desc)625 void BaseCase::logSamples (const vector<Sample>& samples, const string& name, const string& desc)
626 {
627 	TestLog& log = m_testCtx.getLog();
628 
629 	bool testOnly = true;
630 
631 	for (size_t ndx = 0; ndx < samples.size(); ndx++)
632 	{
633 		if (samples[ndx].baseTime != 0 || samples[ndx].nullTime != 0)
634 		{
635 			testOnly = false;
636 			break;
637 		}
638 	}
639 
640 	log << TestLog::SampleList(name, desc);
641 
642 	if (testOnly)
643 	{
644 		log << TestLog::SampleInfo
645 			<< TestLog::ValueInfo("Workload",	"Workload",			"",				QP_SAMPLE_VALUE_TAG_PREDICTOR)
646 			<< TestLog::ValueInfo("Order",		"Order of sample",	"",				QP_SAMPLE_VALUE_TAG_PREDICTOR)
647 			<< TestLog::ValueInfo("TestTime",	"Test render time",	"us",			QP_SAMPLE_VALUE_TAG_RESPONSE)
648 			<< TestLog::EndSampleInfo;
649 
650 		for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
651 		{
652 			const Sample& sample = samples[sampleNdx];
653 
654 			log << TestLog::Sample << sample.workload << sample.order << sample.testTime << TestLog::EndSample;
655 		}
656 	}
657 	else
658 	{
659 		log << TestLog::SampleInfo
660 			<< TestLog::ValueInfo("Workload",	"Workload",			"",				QP_SAMPLE_VALUE_TAG_PREDICTOR)
661 			<< TestLog::ValueInfo("Order",		"Order of sample",	"",				QP_SAMPLE_VALUE_TAG_PREDICTOR)
662 			<< TestLog::ValueInfo("TestTime",	"Test render time",	"us",			QP_SAMPLE_VALUE_TAG_RESPONSE)
663 			<< TestLog::ValueInfo("NullTime",	"Read pixels time",	"us",			QP_SAMPLE_VALUE_TAG_RESPONSE)
664 			<< TestLog::ValueInfo("BaseTime",	"Base render time",	"us",			QP_SAMPLE_VALUE_TAG_RESPONSE)
665 			<< TestLog::EndSampleInfo;
666 
667 		for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
668 		{
669 			const Sample& sample = samples[sampleNdx];
670 
671 			log << TestLog::Sample << sample.workload << sample.order << sample.testTime << sample.nullTime << sample.baseTime << TestLog::EndSample;
672 		}
673 	}
674 
675 	log << TestLog::EndSampleList;
676 }
677 
logGeometry(const tcu::ConstPixelBufferAccess & sample,const glu::ShaderProgram & occluderProg,const glu::ShaderProgram & occludedProg)678 void BaseCase::logGeometry (const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg)
679 {
680 	TestLog& log = m_testCtx.getLog();
681 
682 	log << TestLog::Section("Geometry", "Geometry");
683 	log << TestLog::Message << "Occluding geometry is green with shade dependent on depth (rgb == 0, depth, 0)" << TestLog::EndMessage;
684 	log << TestLog::Message << "Occluded geometry is red with shade dependent on depth (rgb == depth, 0, 0)" << TestLog::EndMessage;
685 	log << TestLog::Message << "Primitive edges are a lighter shade of red/green" << TestLog::EndMessage;
686 
687 	log << TestLog::Image("Test Geometry", "Test Geometry",  sample);
688 	log << TestLog::EndSection;
689 
690 	log << TestLog::Section("Occluder", "Occluder");
691 	log << occluderProg;
692 	log << TestLog::EndSection;
693 
694 	log << TestLog::Section("Occluded", "Occluded");
695 	log << occludedProg;
696 	log << TestLog::EndSection;
697 }
698 
render(const RenderData & data) const699 void BaseCase::render (const RenderData& data) const
700 {
701 	const glw::Functions& gl = m_renderCtx.getFunctions();
702 
703 	gl.useProgram(data.m_program.getProgram());
704 
705 	gl.bindVertexArray(*data.m_vao);
706 	gl.drawArrays(GL_TRIANGLES, 0, data.m_numVertices);
707 	gl.bindVertexArray(0);
708 }
709 
render(const RenderData & data,int instances) const710 void BaseCase::render (const RenderData& data, int instances) const
711 {
712 	const glw::Functions& gl = m_renderCtx.getFunctions();
713 
714 	gl.useProgram(data.m_program.getProgram());
715 
716 	gl.bindVertexArray(*data.m_vao);
717 	gl.drawArraysInstanced(GL_TRIANGLES, 0, data.m_numVertices, instances);
718 	gl.bindVertexArray(0);
719 }
720 
721 // Render occluder once, then repeatedly render occluded geometry. Sample with multiple repetition counts & establish time per call with linear regression
722 class RenderCountCase : public BaseCase
723 {
724 public:
725 					RenderCountCase		(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
~RenderCountCase(void)726 					~RenderCountCase	(void) {}
727 
728 protected:
729 	virtual void	logAnalysis			(const vector<Sample>& samples);
730 
731 private:
732 	virtual int		calibrate			(void) const;
733 	virtual Sample	renderSample		(const RenderData& occluder, const RenderData& occluded, int callcount) const;
734 };
735 
RenderCountCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)736 RenderCountCase::RenderCountCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
737 	: BaseCase	(testCtx, renderCtx, name, desc)
738 {
739 }
740 
logAnalysis(const vector<Sample> & samples)741 void RenderCountCase::logAnalysis (const vector<Sample>& samples)
742 {
743 	using namespace gls;
744 
745 	TestLog&		log			= m_testCtx.getLog();
746 	int				maxWorkload	= 0;
747 	vector<Vec2>	testSamples	(samples.size());
748 
749 	for (size_t ndx = 0; ndx < samples.size(); ndx++)
750 	{
751 		const Sample& sample = samples[ndx];
752 
753 		testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
754 
755 		maxWorkload = de::max(maxWorkload, sample.workload);
756 	}
757 
758 	{
759 		const float							confidence	= 0.60f;
760 		const LineParametersWithConfidence	testParam	= theilSenSiegelLinearRegression(testSamples, confidence);
761 		const float							usPerCall	= testParam.coefficient;
762 		const float							pxPerCall	= RENDER_SIZE*RENDER_SIZE;
763 		const float							pxPerUs		= pxPerCall/usPerCall;
764 		const float							mpxPerS		= pxPerUs;
765 
766 		log << TestLog::Section("Linear Regression", "Linear Regression");
767 		log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage;
768 		log << TestLog::Message << "Render time for scene with depth test was\n\t"
769 			<< "[" << testParam.offsetConfidenceLower << ", " << testParam.offset <<  ", " << testParam.offsetConfidenceUpper << "]us +"
770 			<< "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]"
771 			<< "us/workload" << TestLog::EndMessage;
772 		log << TestLog::EndSection;
773 
774 		log << TestLog::Section("Result", "Result");
775 
776 		if (testParam.coefficientConfidenceLower < 0.0f)
777 		{
778 			log << TestLog::Message << "Coefficient confidence bounds include values below 0.0, the operation likely has neglible per-pixel cost" << TestLog::EndMessage;
779 			m_results.addResult(QP_TEST_RESULT_PASS, "Pass");
780 		}
781 		else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25)
782 		{
783 			log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage;
784 			m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
785 		}
786 		else
787 		{
788 			log << TestLog::Message << "Culled hidden pixels @ " << mpxPerS << "Mpx/s" << TestLog::EndMessage;
789 			m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(mpxPerS, 2));
790 		}
791 
792 		log << TestLog::EndSection;
793 	}
794 }
795 
renderSample(const RenderData & occluder,const RenderData & occluded,int callcount) const796 Sample RenderCountCase::renderSample (const RenderData& occluder, const RenderData& occluded, int callcount) const
797 {
798 	const glw::Functions&	gl		= m_renderCtx.getFunctions();
799 	Sample					sample;
800 	deUint64				now		= 0;
801 	deUint64				prev	= 0;
802 	deUint8					buffer[4];
803 
804 	// Stabilize
805 	{
806 		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
807 		gl.enable(GL_DEPTH_TEST);
808 		gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
809 	}
810 
811 	prev = deGetMicroseconds();
812 
813 	gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
814 	gl.enable(GL_DEPTH_TEST);
815 
816 	render(occluder);
817 	render(occluded, callcount);
818 
819 	gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
820 
821 	now = deGetMicroseconds();
822 
823 	sample.testTime = now - prev;
824 	sample.baseTime = 0;
825 	sample.nullTime = 0;
826 	sample.workload = callcount;
827 
828 	return sample;
829 }
830 
calibrate(void) const831 int RenderCountCase::calibrate (void) const
832 {
833 	using namespace gls;
834 
835 	const glw::Functions&	gl					= m_renderCtx.getFunctions();
836 	TestLog&				log					= m_testCtx.getLog();
837 
838 	const RenderData		occluderGeometry	(genOccluderGeometry(), m_renderCtx, log);
839 	const RenderData		occludedGeometry	(genOccludedGeometry(), m_renderCtx, log);
840 
841 	TheilSenCalibrator		calibrator			(CalibratorParameters(20, // Initial workload
842 																	  10, // Max iteration frames
843 																	  20.0f, // Iteration shortcut threshold ms
844 																	  20, // Max iterations
845 																	  33.0f, // Target frame time
846 																	  40.0f, // Frame time cap
847 																	  1000.0f // Target measurement duration
848 																	  ));
849 
850 	while (true)
851 	{
852 		switch(calibrator.getState())
853 		{
854 			case TheilSenCalibrator::STATE_FINISHED:
855 				logCalibrationInfo(m_testCtx.getLog(), calibrator);
856 				return calibrator.getCallCount();
857 
858 			case TheilSenCalibrator::STATE_MEASURE:
859 			{
860 				deUint8	buffer[4];
861 				deInt64 now;
862 				deInt64 prev;
863 
864 				prev = deGetMicroseconds();
865 
866 				gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
867 				gl.disable(GL_DEPTH_TEST);
868 
869 				render(occluderGeometry);
870 				render(occludedGeometry, calibrator.getCallCount());
871 
872 				gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
873 
874 				now = deGetMicroseconds();
875 
876 				calibrator.recordIteration(now - prev);
877 				break;
878 			}
879 
880 			case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
881 				calibrator.recomputeParameters();
882 				break;
883 			default:
884 				DE_ASSERT(false);
885 				return 1;
886 		}
887 	}
888 }
889 
890 // Compares time/workload gradients of same geometry with and without depth testing
891 class RelativeChangeCase : public BaseCase
892 {
893 public:
894 					RelativeChangeCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
~RelativeChangeCase(void)895 	virtual			~RelativeChangeCase	(void) {}
896 
897 protected:
898 	Sample			renderSample		(const RenderData& occluder, const RenderData& occluded, int workload) const;
899 
900 	virtual void	logAnalysis			(const vector<Sample>& samples);
901 
902 private:
903 	int				calibrate			(void) const;
904 };
905 
RelativeChangeCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)906 RelativeChangeCase::RelativeChangeCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
907 	: BaseCase		(testCtx, renderCtx, name, desc)
908 {
909 }
910 
calibrate(void) const911 int RelativeChangeCase::calibrate (void) const
912 {
913 	using namespace gls;
914 
915 	const glw::Functions&	gl		= m_renderCtx.getFunctions();
916 	TestLog&				log		= m_testCtx.getLog();
917 
918 	const RenderData		geom	(genOccludedGeometry(), m_renderCtx, log);
919 
920 	TheilSenCalibrator calibrator(CalibratorParameters( 20, // Initial workload
921 														10, // Max iteration frames
922 														20.0f, // Iteration shortcut threshold ms
923 														20, // Max iterations
924 														33.0f, // Target frame time
925 														40.0f, // Frame time cap
926 														1000.0f // Target measurement duration
927 														));
928 
929 	while (true)
930 	{
931 		switch(calibrator.getState())
932 		{
933 			case TheilSenCalibrator::STATE_FINISHED:
934 				logCalibrationInfo(m_testCtx.getLog(), calibrator);
935 				return calibrator.getCallCount();
936 
937 			case TheilSenCalibrator::STATE_MEASURE:
938 			{
939 				deUint8			buffer[4];
940 				const GLuint	program	= geom.m_program.getProgram();
941 
942 				gl.useProgram(program);
943 				gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), calibrator.getCallCount());
944 
945 				const deInt64 prev = deGetMicroseconds();
946 
947 				gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
948 				gl.disable(GL_DEPTH_TEST);
949 
950 				render(geom);
951 
952 				gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
953 
954 				const deInt64 now = deGetMicroseconds();
955 
956 				calibrator.recordIteration(now - prev);
957 				break;
958 			}
959 
960 			case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
961 				calibrator.recomputeParameters();
962 				break;
963 			default:
964 				DE_ASSERT(false);
965 				return 1;
966 		}
967 	}
968 }
969 
renderSample(const RenderData & occluder,const RenderData & occluded,int workload) const970 Sample RelativeChangeCase::renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const
971 {
972 	const glw::Functions&	gl		= m_renderCtx.getFunctions();
973 	const GLuint			program	= occluded.m_program.getProgram();
974 	Sample					sample;
975 	deUint64				now		= 0;
976 	deUint64				prev	= 0;
977 	deUint8					buffer[4];
978 
979 	gl.useProgram(program);
980 	gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
981 
982 	// Warmup (this workload seems to reduce variation in following workloads)
983 	{
984 		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
985 		gl.disable(GL_DEPTH_TEST);
986 
987 		gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
988 	}
989 
990 	// Null time
991 	{
992 		prev = deGetMicroseconds();
993 
994 		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
995 		gl.disable(GL_DEPTH_TEST);
996 
997 		gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
998 
999 		now = deGetMicroseconds();
1000 
1001 		sample.nullTime = now - prev;
1002 	}
1003 
1004 	// Test time
1005 	{
1006 		prev = deGetMicroseconds();
1007 
1008 		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1009 		gl.enable(GL_DEPTH_TEST);
1010 
1011 		render(occluder);
1012 		render(occluded);
1013 
1014 		gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1015 
1016 		now = deGetMicroseconds();
1017 
1018 		sample.testTime = now - prev;
1019 	}
1020 
1021 	// Base time
1022 	{
1023 		prev = deGetMicroseconds();
1024 
1025 		gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1026 		gl.disable(GL_DEPTH_TEST);
1027 
1028 		render(occluder);
1029 		render(occluded);
1030 
1031 		gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1032 
1033 		now = deGetMicroseconds();
1034 
1035 		sample.baseTime = now - prev;
1036 	}
1037 
1038 	sample.workload = 0;
1039 
1040 	return sample;
1041 }
1042 
logAnalysis(const vector<Sample> & samples)1043 void RelativeChangeCase::logAnalysis (const vector<Sample>& samples)
1044 {
1045 	using namespace gls;
1046 
1047 	TestLog&		log			= m_testCtx.getLog();
1048 
1049 	int				maxWorkload	= 0;
1050 
1051 	vector<Vec2>	nullSamples	(samples.size());
1052 	vector<Vec2>	baseSamples	(samples.size());
1053 	vector<Vec2>	testSamples	(samples.size());
1054 
1055 	for (size_t ndx = 0; ndx < samples.size(); ndx++)
1056 	{
1057 		const Sample& sample = samples[ndx];
1058 
1059 		nullSamples[ndx] = Vec2((float)sample.workload, (float)sample.nullTime);
1060 		baseSamples[ndx] = Vec2((float)sample.workload, (float)sample.baseTime);
1061 		testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
1062 
1063 		maxWorkload = de::max(maxWorkload, sample.workload);
1064 	}
1065 
1066 	{
1067 		const float							confidence	= 0.60f;
1068 
1069 		const LineParametersWithConfidence	nullParam	= theilSenSiegelLinearRegression(nullSamples, confidence);
1070 		const LineParametersWithConfidence	baseParam	= theilSenSiegelLinearRegression(baseSamples, confidence);
1071 		const LineParametersWithConfidence	testParam	= theilSenSiegelLinearRegression(testSamples, confidence);
1072 
1073 		if (!de::inRange(0.0f, nullParam.coefficientConfidenceLower, nullParam.coefficientConfidenceUpper))
1074 		{
1075 			m_results.addResult(QP_TEST_RESULT_FAIL, "Constant operation sequence duration not constant");
1076 			log << TestLog::Message << "Constant operation sequence timing may vary as a function of workload. Result quality extremely low" << TestLog::EndMessage;
1077 		}
1078 
1079 		if (de::inRange(0.0f, baseParam.coefficientConfidenceLower, baseParam.coefficientConfidenceUpper))
1080 		{
1081 			m_results.addResult(QP_TEST_RESULT_FAIL, "Workload has no effect on duration");
1082 			log << TestLog::Message << "Workload factor has no effect on duration of sample (smart optimizer?)" << TestLog::EndMessage;
1083 		}
1084 
1085 		log << TestLog::Section("Linear Regression", "Linear Regression");
1086 		log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage;
1087 
1088 		log << TestLog::Message << "Render time for empty scene was\n\t"
1089 			<< "[" << nullParam.offsetConfidenceLower << ", " << nullParam.offset <<  ", " << nullParam.offsetConfidenceUpper << "]us +"
1090 			<< "[" << nullParam.coefficientConfidenceLower << ", " << nullParam.coefficient << ", " << nullParam.coefficientConfidenceUpper << "]"
1091 			<< "us/workload" << TestLog::EndMessage;
1092 
1093 		log << TestLog::Message << "Render time for scene without depth test was\n\t"
1094 			<< "[" << baseParam.offsetConfidenceLower << ", " << baseParam.offset <<  ", " << baseParam.offsetConfidenceUpper << "]us +"
1095 			<< "[" << baseParam.coefficientConfidenceLower << ", " << baseParam.coefficient << ", " << baseParam.coefficientConfidenceUpper << "]"
1096 			<< "us/workload" << TestLog::EndMessage;
1097 
1098 		log << TestLog::Message << "Render time for scene with depth test was\n\t"
1099 			<< "[" << testParam.offsetConfidenceLower << ", " << testParam.offset <<  ", " << testParam.offsetConfidenceUpper << "]us +"
1100 			<< "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]"
1101 			<< "us/workload" << TestLog::EndMessage;
1102 
1103 		log << TestLog::EndSection;
1104 
1105 		if (de::inRange(0.0f, testParam.coefficientConfidenceLower, testParam.coefficientConfidenceUpper))
1106 		{
1107 			log << TestLog::Message << "Test duration not dependent on culled workload" << TestLog::EndMessage;
1108 			m_results.addResult(QP_TEST_RESULT_PASS, "0.0");
1109 		}
1110 		else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25)
1111 		{
1112 			log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage;
1113 			m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
1114 		}
1115 		else if (baseParam.coefficientConfidenceLower < baseParam.coefficientConfidenceUpper*0.25)
1116 		{
1117 			log << TestLog::Message << "Coefficient confidence range for base render time is extremely large, cannot give reliable result" << TestLog::EndMessage;
1118 			m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
1119 		}
1120 		else
1121 		{
1122 			log << TestLog::Message << "Test duration is dependent on culled workload" << TestLog::EndMessage;
1123 			m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(de::abs(testParam.coefficient)/de::abs(baseParam.coefficient), 2));
1124 		}
1125 	}
1126 }
1127 
1128 // Speed of trivial culling
1129 class BaseCostCase : public RenderCountCase
1130 {
1131 public:
BaseCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1132 						BaseCostCase		(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1133 							: RenderCountCase (testCtx, renderCtx, name, desc) {}
1134 
~BaseCostCase(void)1135 						~BaseCostCase		(void) {}
1136 
1137 private:
genOccluderGeometry(void) const1138 	virtual ObjectData	genOccluderGeometry	(void) const { return Utils::fastQuad(0.2f); }
genOccludedGeometry(void) const1139 	virtual ObjectData	genOccludedGeometry	(void) const { return Utils::variableQuad(0.8f); }
1140 
logDescription(void)1141 	virtual void		logDescription		(void)
1142 	{
1143 		TestLog& log = m_testCtx.getLog();
1144 
1145 		log << TestLog::Section("Description", "Test description");
1146 		log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1147 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1148 		log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"  << TestLog::EndMessage;
1149 		log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
1150 		log << TestLog::EndSection;
1151 	}
1152 };
1153 
1154 // Gradient
1155 class GradientCostCase : public RenderCountCase
1156 {
1157 public:
GradientCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,float gradientDistance)1158 						GradientCostCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float gradientDistance)
1159 							: RenderCountCase		(testCtx, renderCtx, name, desc)
1160 							, m_gradientDistance	(gradientDistance)
1161 						{
1162 						}
1163 
~GradientCostCase(void)1164 						~GradientCostCase	(void) {}
1165 
1166 private:
genOccluderGeometry(void) const1167 	virtual ObjectData	genOccluderGeometry	(void) const { return Utils::fastQuadWithGradient(0.0f, 1.0f - m_gradientDistance); }
genOccludedGeometry(void) const1168 	virtual ObjectData	genOccludedGeometry	(void) const
1169 	{
1170 		return ObjectData(glu::makeVtxFragSources(Utils::getInstanceNoiseVertexShader(), Utils::getDepthAsRedFragmentShader()), Utils::getFullscreenQuadWithGradient(m_gradientDistance, 1.0f));
1171 	}
1172 
logDescription(void)1173 	virtual void		logDescription		(void)
1174 	{
1175 		TestLog& log = m_testCtx.getLog();
1176 
1177 		log << TestLog::Section("Description", "Test description");
1178 		log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1179 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1180 		log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1181 		log << TestLog::Message << "The quads are tilted so that the left edge of the occluded quad has a depth of 1.0 and the right edge of the occluding quad has a depth of 0.0." << TestLog::EndMessage;
1182 		log << TestLog::Message << "The quads are spaced to have a depth difference of " << m_gradientDistance << " at all points." << TestLog::EndMessage;
1183 		log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
1184 		log << TestLog::EndSection;
1185 	}
1186 
1187 	const float			m_gradientDistance;
1188 };
1189 
1190 // Constant offset to frag depth in occluder
1191 class OccluderStaticFragDepthCostCase : public RenderCountCase
1192 {
1193 public:
OccluderStaticFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1194 						OccluderStaticFragDepthCostCase		(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1195 							: RenderCountCase(testCtx, renderCtx, name, desc)
1196 						{
1197 						}
1198 
~OccluderStaticFragDepthCostCase(void)1199 						~OccluderStaticFragDepthCostCase	(void) {}
1200 
1201 private:
genOccluderGeometry(void) const1202 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
genOccludedGeometry(void) const1203 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::fastQuad(0.8f); }
1204 
logDescription(void)1205 	virtual void		logDescription						(void)
1206 	{
1207 		TestLog& log = m_testCtx.getLog();
1208 
1209 		log << TestLog::Section("Description", "Test description");
1210 		log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1211 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1212 		log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1213 		log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1214 		log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
1215 		log << TestLog::EndSection;
1216 	}
1217 };
1218 
1219 // Dynamic offset to frag depth in occluder
1220 class OccluderDynamicFragDepthCostCase : public RenderCountCase
1221 {
1222 public:
OccluderDynamicFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1223 						OccluderDynamicFragDepthCostCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1224 							: RenderCountCase(testCtx, renderCtx, name, desc)
1225 						{
1226 						}
1227 
~OccluderDynamicFragDepthCostCase(void)1228 						~OccluderDynamicFragDepthCostCase	(void) {}
1229 
1230 private:
genOccluderGeometry(void) const1231 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
genOccludedGeometry(void) const1232 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::fastQuad(0.8f); }
1233 
logDescription(void)1234 	virtual void		logDescription						(void)
1235 	{
1236 		TestLog& log = m_testCtx.getLog();
1237 
1238 		log << TestLog::Section("Description", "Test description");
1239 		log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1240 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1241 		log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1242 		log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1243 		log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
1244 		log << TestLog::EndSection;
1245 	}
1246 };
1247 
1248 // Constant offset to frag depth in occluder
1249 class OccludedStaticFragDepthCostCase : public RenderCountCase
1250 {
1251 public:
OccludedStaticFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1252 						OccludedStaticFragDepthCostCase		(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1253 							: RenderCountCase(testCtx, renderCtx, name, desc)
1254 						{
1255 						}
1256 
~OccludedStaticFragDepthCostCase(void)1257 						~OccludedStaticFragDepthCostCase	(void) {}
1258 
1259 private:
genOccluderGeometry(void) const1260 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::fastQuad(0.2f); }
genOccludedGeometry(void) const1261 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
1262 
logDescription(void)1263 	virtual void		logDescription						(void)
1264 	{
1265 		TestLog& log = m_testCtx.getLog();
1266 
1267 		log << TestLog::Section("Description", "Test description");
1268 		log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1269 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1270 		log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1271 		log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1272 		log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
1273 		log << TestLog::EndSection;
1274 	}
1275 };
1276 
1277 // Dynamic offset to frag depth in occluder
1278 class OccludedDynamicFragDepthCostCase : public RenderCountCase
1279 {
1280 public:
OccludedDynamicFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1281 						OccludedDynamicFragDepthCostCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1282 							: RenderCountCase(testCtx, renderCtx, name, desc)
1283 						{
1284 						}
1285 
~OccludedDynamicFragDepthCostCase(void)1286 						~OccludedDynamicFragDepthCostCase	(void) {}
1287 
1288 private:
genOccluderGeometry(void) const1289 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::fastQuad(0.2f); }
genOccludedGeometry(void) const1290 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
1291 
logDescription(void)1292 	virtual void		logDescription						(void)
1293 	{
1294 		TestLog& log = m_testCtx.getLog();
1295 
1296 		log << TestLog::Section("Description", "Test description");
1297 		log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1298 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1299 		log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1300 		log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1301 		log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
1302 		log << TestLog::EndSection;
1303 	}
1304 };
1305 
1306 // Culling speed with slightly less trivial geometry
1307 class OccludingGeometryComplexityCostCase : public RenderCountCase
1308 {
1309 public:
OccludingGeometryComplexityCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,int resolution,float xyNoise,float zNoise)1310 						OccludingGeometryComplexityCostCase		(TestContext&			testCtx,
1311 																 const RenderContext&	renderCtx,
1312 																 const char*			name,
1313 																 const char*			desc,
1314 																 int					resolution,
1315 																 float					xyNoise,
1316 																 float					zNoise)
1317 							: RenderCountCase	(testCtx, renderCtx, name, desc)
1318 							, m_resolution		(resolution)
1319 							, m_xyNoise			(xyNoise)
1320 							, m_zNoise			(zNoise)
1321 						{
1322 						}
1323 
~OccludingGeometryComplexityCostCase(void)1324 						~OccludingGeometryComplexityCostCase	(void) {}
1325 
1326 private:
genOccluderGeometry(void) const1327 	virtual ObjectData	genOccluderGeometry						(void) const
1328 	{
1329 		return ObjectData(Utils::getBaseShader(),
1330 						  Utils::getFullScreenGrid(m_resolution,
1331 						  deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed(),
1332 						  0.2f,
1333 						  m_zNoise,
1334 						  m_xyNoise));
1335 	}
1336 
genOccludedGeometry(void) const1337 	virtual ObjectData	genOccludedGeometry						(void) const { return Utils::variableQuad(0.8f); }
1338 
logDescription(void)1339 	virtual void		logDescription		(void)
1340 	{
1341 		TestLog& log = m_testCtx.getLog();
1342 
1343 		log << TestLog::Section("Description", "Test description");
1344 		log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1345 		log << TestLog::Message << "Geometry consists of an occluding grid and an occluded fullsceen quad. The occluding geometry is rendered once, the occluded one is rendered repeatedly" << TestLog::EndMessage;
1346 		log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"  << TestLog::EndMessage;
1347 		log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload"  << TestLog::EndMessage;
1348 		log << TestLog::EndSection;
1349 	}
1350 
1351 	const int			m_resolution;
1352 	const float			m_xyNoise;
1353 	const float			m_zNoise;
1354 };
1355 
1356 
1357 // Cases with varying workloads in the fragment shader
1358 class FragmentWorkloadCullCase : public RelativeChangeCase
1359 {
1360 public:
1361 						FragmentWorkloadCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
~FragmentWorkloadCullCase(void)1362 	virtual				~FragmentWorkloadCullCase	(void) {}
1363 
1364 private:
genOccluderGeometry(void) const1365 	virtual ObjectData	genOccluderGeometry			(void) const { return Utils::fastQuad(0.2f); }
1366 
1367 	virtual void		logDescription				(void);
1368 };
1369 
FragmentWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1370 FragmentWorkloadCullCase::FragmentWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1371 	: RelativeChangeCase	(testCtx, renderCtx, name, desc)
1372 {
1373 }
1374 
logDescription(void)1375 void FragmentWorkloadCullCase::logDescription (void)
1376 {
1377 	TestLog& log = m_testCtx.getLog();
1378 
1379 	log << TestLog::Section("Description", "Test description");
1380 	log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
1381 	log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
1382 		"the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1383 	log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1384 	log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1385 	log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
1386 	log << TestLog::EndSection;
1387 }
1388 
1389 // Additional workload consists of texture lookups
1390 class FragmentTextureWorkloadCullCase : public FragmentWorkloadCullCase
1391 {
1392 public:
1393 						FragmentTextureWorkloadCullCase		(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
~FragmentTextureWorkloadCullCase(void)1394 	virtual				~FragmentTextureWorkloadCullCase	(void) {}
1395 
1396 	virtual void		init								(void);
1397 	virtual void		deinit								(void);
1398 
1399 private:
1400 	typedef MovePtr<glu::Texture> TexPtr;
1401 
genOccludedGeometry(void) const1402 	virtual ObjectData	genOccludedGeometry					(void) const
1403 	{
1404 		return ObjectData(Utils::getTextureWorkloadShader(), Utils::getFullscreenQuad(0.8f));
1405 	}
1406 
1407 	TexPtr				m_texture;
1408 };
1409 
FragmentTextureWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1410 FragmentTextureWorkloadCullCase::FragmentTextureWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1411 	: FragmentWorkloadCullCase	(testCtx, renderCtx, name, desc)
1412 {
1413 }
1414 
init(void)1415 void FragmentTextureWorkloadCullCase::init (void)
1416 {
1417 	const glw::Functions&	gl		= m_renderCtx.getFunctions();
1418 	const int				size	= 128;
1419 	const vector<deUint8>	data	(size*size*4, 255);
1420 
1421 	m_texture = MovePtr<glu::Texture>(new glu::Texture(gl));
1422 
1423 	gl.bindTexture(GL_TEXTURE_2D, m_texture);
1424 	gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
1425 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1426 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1427 }
1428 
deinit(void)1429 void FragmentTextureWorkloadCullCase::deinit (void)
1430 {
1431 	m_texture.clear();
1432 }
1433 
1434 // Additional workload consists of arithmetic
1435 class FragmentArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
1436 {
1437 public:
FragmentArithmeticWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1438 						FragmentArithmeticWorkloadCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1439 						: FragmentWorkloadCullCase	(testCtx, renderCtx, name, desc)
1440 					{
1441 					}
~FragmentArithmeticWorkloadCullCase(void)1442 	virtual				~FragmentArithmeticWorkloadCullCase	(void) {}
1443 
1444 private:
genOccludedGeometry(void) const1445 	virtual ObjectData	genOccludedGeometry					(void) const
1446 	{
1447 		return ObjectData(Utils::getArithmeticWorkloadShader(), Utils::getFullscreenQuad(0.8f));
1448 	}
1449 };
1450 
1451 // Contains dynamicly unused discard after a series of calculations
1452 class FragmentDiscardArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
1453 {
1454 public:
FragmentDiscardArithmeticWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1455 						FragmentDiscardArithmeticWorkloadCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1456 						: FragmentWorkloadCullCase	(testCtx, renderCtx, name, desc)
1457 					{
1458 					}
1459 
~FragmentDiscardArithmeticWorkloadCullCase(void)1460 	virtual				~FragmentDiscardArithmeticWorkloadCullCase	(void) {}
1461 
1462 private:
genOccludedGeometry(void) const1463 	virtual ObjectData	genOccludedGeometry							(void) const
1464 	{
1465 		return ObjectData(Utils::getArithmeticWorkloadDiscardShader(), Utils::getFullscreenQuad(0.8f));
1466 	}
1467 
logDescription(void)1468 	virtual void		logDescription								(void)
1469 	{
1470 		TestLog& log = m_testCtx.getLog();
1471 
1472 		log << TestLog::Section("Description", "Test description");
1473 		log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
1474 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
1475 			"the second (occluded) contains significant fragment shader work and a discard that is never triggers but has a dynamic condition" << TestLog::EndMessage;
1476 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1477 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1478 		log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
1479 		log << TestLog::EndSection;
1480 	}
1481 };
1482 
1483 // Discards fragments from the occluder in a grid pattern
1484 class PartialOccluderDiscardCullCase : public RelativeChangeCase
1485 {
1486 public:
PartialOccluderDiscardCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,int gridsize)1487 						PartialOccluderDiscardCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, int gridsize)
1488 							: RelativeChangeCase		(testCtx, renderCtx, name, desc)
1489 							, m_gridsize	(gridsize)
1490 						{
1491 						}
~PartialOccluderDiscardCullCase(void)1492 	virtual				~PartialOccluderDiscardCullCase	(void) {}
1493 
1494 private:
genOccluderGeometry(void) const1495 	virtual ObjectData	genOccluderGeometry				(void) const { return Utils::quadWith(Utils::getGridDiscardShader(m_gridsize), 0.2f); }
genOccludedGeometry(void) const1496 	virtual ObjectData	genOccludedGeometry				(void) const { return Utils::slowQuad(0.8f); }
1497 
logDescription(void)1498 	virtual void		logDescription					(void)
1499 	{
1500 		TestLog& log = m_testCtx.getLog();
1501 
1502 		log << TestLog::Section("Description", "Test description");
1503 		log << TestLog::Message << "Testing effects of partially discarded occluder on rendering time" << TestLog::EndMessage;
1504 		log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad discards half the "
1505 			"fragments in a grid pattern, the second (partially occluded) contains significant fragment shader work" << TestLog::EndMessage;
1506 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1507 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1508 		log << TestLog::Message << "Successfull early Z-testing should result in depth testing halving the render time"  << TestLog::EndMessage;
1509 		log << TestLog::EndSection;
1510 	}
1511 
1512 	const int			m_gridsize;
1513 };
1514 
1515 // Trivial occluder covering part of screen
1516 class PartialOccluderCullCase : public RelativeChangeCase
1517 {
1518 public:
PartialOccluderCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,float coverage)1519 						PartialOccluderCullCase		(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float coverage)
1520 							: RelativeChangeCase		(testCtx, renderCtx, name, desc)
1521 							, m_coverage	(coverage)
1522 						{
1523 						}
~PartialOccluderCullCase(void)1524 						~PartialOccluderCullCase	(void) {}
1525 
1526 private:
genOccluderGeometry(void) const1527 	virtual ObjectData	genOccluderGeometry			(void) const { return ObjectData(Utils::getBaseShader(), Utils::getPartScreenQuad(m_coverage, 0.2f)); }
genOccludedGeometry(void) const1528 	virtual ObjectData	genOccludedGeometry			(void) const {return Utils::slowQuad(0.8f); }
1529 
logDescription(void)1530 	virtual void		logDescription				(void)
1531 	{
1532 		TestLog& log = m_testCtx.getLog();
1533 
1534 		log << TestLog::Section("Description", "Test description");
1535 		log << TestLog::Message << "Testing effects of partial occluder on rendering time" << TestLog::EndMessage;
1536 		log << TestLog::Message << "Geometry consists of two quads. The first (occluding) quad covers " << m_coverage*100.0f
1537 			<< "% of the screen, while the second (partially occluded, fullscreen) contains significant fragment shader work" << TestLog::EndMessage;
1538 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1539 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1540 		log << TestLog::Message << "Successfull early Z-testing should result in render time increasing proportionally with unoccluded area"  << TestLog::EndMessage;
1541 		log << TestLog::EndSection;
1542 	}
1543 
1544 	const float			m_coverage;
1545 };
1546 
1547 // Constant offset to frag depth in occluder
1548 class StaticOccluderFragDepthCullCase : public RelativeChangeCase
1549 {
1550 public:
StaticOccluderFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1551 						StaticOccluderFragDepthCullCase		(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1552 							: RelativeChangeCase(testCtx, renderCtx, name, desc)
1553 						{
1554 						}
1555 
~StaticOccluderFragDepthCullCase(void)1556 						~StaticOccluderFragDepthCullCase	(void) {}
1557 
1558 private:
genOccluderGeometry(void) const1559 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
genOccludedGeometry(void) const1560 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::slowQuad(0.8f); }
1561 
logDescription(void)1562 	virtual void		logDescription						(void)
1563 	{
1564 		TestLog& log = m_testCtx.getLog();
1565 
1566 		log << TestLog::Section("Description", "Test description");
1567 		log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage;
1568 		log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1569 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1570 		log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1571 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1572 		log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
1573 		log << TestLog::EndSection;
1574 	}
1575 };
1576 
1577 // Dynamic offset to frag depth in occluder
1578 class DynamicOccluderFragDepthCullCase : public RelativeChangeCase
1579 {
1580 public:
DynamicOccluderFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1581 						DynamicOccluderFragDepthCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1582 							: RelativeChangeCase(testCtx, renderCtx, name, desc)
1583 						{
1584 						}
1585 
~DynamicOccluderFragDepthCullCase(void)1586 						~DynamicOccluderFragDepthCullCase	(void) {}
1587 
1588 private:
genOccluderGeometry(void) const1589 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
genOccludedGeometry(void) const1590 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::slowQuad(0.8f); }
1591 
logDescription(void)1592 	virtual void		logDescription						(void)
1593 	{
1594 		TestLog& log = m_testCtx.getLog();
1595 
1596 		log << TestLog::Section("Description", "Test description");
1597 		log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage;
1598 		log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1599 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1600 		log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1601 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1602 		log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
1603 		log << TestLog::EndSection;
1604 	}
1605 };
1606 
1607 // Constant offset to frag depth in occluded
1608 class StaticOccludedFragDepthCullCase : public RelativeChangeCase
1609 {
1610 public:
StaticOccludedFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1611 						StaticOccludedFragDepthCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1612 							: RelativeChangeCase(testCtx, renderCtx, name, desc)
1613 						{
1614 						}
1615 
~StaticOccludedFragDepthCullCase(void)1616 						~StaticOccludedFragDepthCullCase	(void) {}
1617 
1618 private:
genOccluderGeometry(void) const1619 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::fastQuad(0.2f); }
genOccludedGeometry(void) const1620 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::quadWith(Utils::getStaticFragDepthArithmeticWorkloadFragmentShader(), 0.2f); }
1621 
logDescription(void)1622 	virtual void		logDescription						(void)
1623 	{
1624 		TestLog& log = m_testCtx.getLog();
1625 
1626 		log << TestLog::Section("Description", "Test description");
1627 		log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
1628 		log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1629 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1630 		log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1631 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1632 		log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
1633 		log << TestLog::EndSection;
1634 	}
1635 };
1636 
1637 // Dynamic offset to frag depth in occluded
1638 class DynamicOccludedFragDepthCullCase : public RelativeChangeCase
1639 {
1640 public:
DynamicOccludedFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1641 						DynamicOccludedFragDepthCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1642 							: RelativeChangeCase(testCtx, renderCtx, name, desc)
1643 						{
1644 						}
1645 
~DynamicOccludedFragDepthCullCase(void)1646 						~DynamicOccludedFragDepthCullCase	(void) {}
1647 
1648 private:
genOccluderGeometry(void) const1649 	virtual ObjectData	genOccluderGeometry					(void) const { return Utils::fastQuad(0.2f); }
genOccludedGeometry(void) const1650 	virtual ObjectData	genOccludedGeometry					(void) const { return Utils::quadWith(Utils::getDynamicFragDepthArithmeticWorkloadFragmentShader(), 0.2f); }
1651 
logDescription(void)1652 	virtual void		logDescription						(void)
1653 	{
1654 		TestLog& log = m_testCtx.getLog();
1655 
1656 		log << TestLog::Section("Description", "Test description");
1657 		log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
1658 		log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1659 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1660 		log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1661 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1662 		log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
1663 		log << TestLog::EndSection;
1664 	}
1665 };
1666 
1667 // Dynamic offset to frag depth in occluded
1668 class ReversedDepthOrderCullCase : public RelativeChangeCase
1669 {
1670 public:
ReversedDepthOrderCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1671 						ReversedDepthOrderCullCase	(TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1672 							: RelativeChangeCase(testCtx, renderCtx, name, desc)
1673 						{
1674 						}
1675 
~ReversedDepthOrderCullCase(void)1676 						~ReversedDepthOrderCullCase	(void) {}
1677 
1678 private:
genOccluderGeometry(void) const1679 	virtual ObjectData	genOccluderGeometry			(void) const { return Utils::fastQuad(0.2f); }
genOccludedGeometry(void) const1680 	virtual ObjectData	genOccludedGeometry			(void) const { return Utils::slowQuad(0.8f); }
1681 
logDescription(void)1682 	virtual void		logDescription				(void)
1683 	{
1684 		TestLog& log = m_testCtx.getLog();
1685 
1686 		log << TestLog::Section("Description", "Test description");
1687 		log << TestLog::Message << "Testing effects of of back first rendering order on culling efficiency" << TestLog::EndMessage;
1688 		log << TestLog::Message << "Geometry consists of two fullscreen quads. The second (occluding) quad is trivial, while the first (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1689 		log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader"  << TestLog::EndMessage;
1690 		log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"  << TestLog::EndMessage;
1691 		log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time"  << TestLog::EndMessage;
1692 		log << TestLog::EndSection;
1693 	}
1694 
1695 	// Rendering order of occluder & occluded is reversed, otherwise identical to parent version
renderSample(const RenderData & occluder,const RenderData & occluded,int workload) const1696 	Sample				renderSample				(const RenderData& occluder, const RenderData& occluded, int workload) const
1697 	{
1698 		const glw::Functions&	gl		= m_renderCtx.getFunctions();
1699 		const GLuint			program	= occluded.m_program.getProgram();
1700 		Sample					sample;
1701 		deUint64				now		= 0;
1702 		deUint64				prev	= 0;
1703 		deUint8					buffer[4];
1704 
1705 		gl.useProgram(program);
1706 		gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
1707 
1708 		// Warmup (this workload seems to reduce variation in following workloads)
1709 		{
1710 			gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1711 			gl.disable(GL_DEPTH_TEST);
1712 
1713 			gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1714 		}
1715 
1716 		// Null time
1717 		{
1718 			prev = deGetMicroseconds();
1719 
1720 			gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1721 			gl.disable(GL_DEPTH_TEST);
1722 
1723 			gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1724 
1725 			now = deGetMicroseconds();
1726 
1727 			sample.nullTime = now - prev;
1728 		}
1729 
1730 		// Test time
1731 		{
1732 			prev = deGetMicroseconds();
1733 
1734 			gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1735 			gl.enable(GL_DEPTH_TEST);
1736 
1737 			render(occluded);
1738 			render(occluder);
1739 
1740 			gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1741 
1742 			now = deGetMicroseconds();
1743 
1744 			sample.testTime = now - prev;
1745 		}
1746 
1747 		// Base time
1748 		{
1749 			prev = deGetMicroseconds();
1750 
1751 			gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1752 			gl.disable(GL_DEPTH_TEST);
1753 
1754 			render(occluded);
1755 			render(occluder);
1756 
1757 			gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1758 
1759 			now = deGetMicroseconds();
1760 
1761 			sample.baseTime = now - prev;
1762 		}
1763 
1764 		sample.workload = 0;
1765 
1766 		return sample;
1767 	}
1768 };
1769 
1770 } // Anonymous
1771 
DepthTests(Context & context)1772 DepthTests::DepthTests (Context& context)
1773 	: TestCaseGroup (context, "depth", "Depth culling performance")
1774 {
1775 }
1776 
init(void)1777 void DepthTests::init (void)
1778 {
1779 	TestContext&			testCtx		= m_context.getTestContext();
1780 	const RenderContext&	renderCtx	= m_context.getRenderContext();
1781 
1782 	{
1783 		tcu::TestCaseGroup* const cullEfficiencyGroup = new tcu::TestCaseGroup(m_testCtx, "cull_efficiency", "Fragment cull efficiency");
1784 
1785 		addChild(cullEfficiencyGroup);
1786 
1787 		{
1788 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "workload", "Workload");
1789 
1790 			cullEfficiencyGroup->addChild(group);
1791 
1792 			group->addChild(new FragmentTextureWorkloadCullCase(			testCtx, renderCtx, "workload_texture",				"Fragment shader with texture lookup workload"));
1793 			group->addChild(new FragmentArithmeticWorkloadCullCase(			testCtx, renderCtx, "workload_arithmetic",			"Fragment shader with arithmetic workload"));
1794 			group->addChild(new FragmentDiscardArithmeticWorkloadCullCase(	testCtx, renderCtx, "workload_arithmetic_discard",	"Fragment shader that may discard with arithmetic workload"));
1795 		}
1796 
1797 		{
1798 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_discard", "Discard");
1799 
1800 			cullEfficiencyGroup->addChild(group);
1801 
1802 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_256",	"Parts of occluder geometry discarded", 256));
1803 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_128",	"Parts of occluder geometry discarded", 128));
1804 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_64",	"Parts of occluder geometry discarded", 64));
1805 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_32",	"Parts of occluder geometry discarded", 32));
1806 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_16",	"Parts of occluder geometry discarded", 16));
1807 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_8",	"Parts of occluder geometry discarded", 8));
1808 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_4",	"Parts of occluder geometry discarded", 4));
1809 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_2",	"Parts of occluder geometry discarded", 2));
1810 			group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_1",	"Parts of occluder geometry discarded", 1));
1811 		}
1812 
1813 		{
1814 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "partial_coverage", "Partial Coverage");
1815 
1816 			cullEfficiencyGroup->addChild(group);
1817 
1818 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "100", "Occluder covering only part of occluded geometry", 1.00f));
1819 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "099", "Occluder covering only part of occluded geometry", 0.99f));
1820 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "095", "Occluder covering only part of occluded geometry", 0.95f));
1821 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "090", "Occluder covering only part of occluded geometry", 0.90f));
1822 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "080", "Occluder covering only part of occluded geometry", 0.80f));
1823 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "070", "Occluder covering only part of occluded geometry", 0.70f));
1824 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "050", "Occluder covering only part of occluded geometry", 0.50f));
1825 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "025", "Occluder covering only part of occluded geometry", 0.25f));
1826 			group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "010", "Occluder covering only part of occluded geometry", 0.10f));
1827 		}
1828 
1829 		{
1830 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Partial Coverage");
1831 
1832 			cullEfficiencyGroup->addChild(group);
1833 
1834 			group->addChild(new StaticOccluderFragDepthCullCase( testCtx, renderCtx, "occluder_static", ""));
1835 			group->addChild(new DynamicOccluderFragDepthCullCase(testCtx, renderCtx, "occluder_dynamic", ""));
1836 			group->addChild(new StaticOccludedFragDepthCullCase( testCtx, renderCtx, "occluded_static", ""));
1837 			group->addChild(new DynamicOccludedFragDepthCullCase(testCtx, renderCtx, "occluded_dynamic", ""));
1838 		}
1839 
1840 		{
1841 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "order", "Rendering order");
1842 
1843 			cullEfficiencyGroup->addChild(group);
1844 
1845 			group->addChild(new ReversedDepthOrderCullCase(testCtx, renderCtx, "reversed", "Back to front rendering order"));
1846 		}
1847 	}
1848 
1849 	{
1850 		tcu::TestCaseGroup* const testCostGroup = new tcu::TestCaseGroup(m_testCtx, "culled_pixel_cost", "Fragment cull efficiency");
1851 
1852 		addChild(testCostGroup);
1853 
1854 		{
1855 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "gradient", "Gradients with small depth differences");
1856 
1857 			testCostGroup->addChild(group);
1858 
1859 			group->addChild(new BaseCostCase(testCtx, renderCtx, "flat", ""));
1860 			group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_050", "", 0.50f));
1861 			group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_010", "", 0.10f));
1862 			group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_005", "", 0.05f));
1863 			group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_002", "", 0.02f));
1864 			group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_001", "", 0.01f));
1865 		}
1866 
1867 		{
1868 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_geometry", "Occluders with varying geometry complexity");
1869 
1870 			testCostGroup->addChild(group);
1871 
1872 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_5",   "", 5,   0.0f, 0.0f));
1873 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_15",  "", 15,  0.0f, 0.0f));
1874 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_25",  "", 25,  0.0f, 0.0f));
1875 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_50",  "", 50,  0.0f, 0.0f));
1876 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_100", "", 100, 0.0f, 0.0f));
1877 
1878 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_5",   "", 5,   1.0f/5.0f,   0.0f));
1879 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_15",  "", 15,  1.0f/15.0f,  0.0f));
1880 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_25",  "", 25,  1.0f/25.0f,  0.0f));
1881 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_50",  "", 50,  1.0f/50.0f,  0.0f));
1882 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_100", "", 100, 1.0f/100.0f, 0.0f));
1883 
1884 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_5",   "", 5,   0.0f, 0.2f));
1885 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_15",  "", 15,  0.0f, 0.2f));
1886 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_25",  "", 25,  0.0f, 0.2f));
1887 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_50",  "", 50,  0.0f, 0.2f));
1888 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_100", "", 100, 0.0f, 0.2f));
1889 
1890 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_5",   "", 5,   1.0f/5.0f,   0.2f));
1891 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_15",  "", 15,  1.0f/15.0f,  0.2f));
1892 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_25",  "", 25,  1.0f/25.0f,  0.2f));
1893 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_50",  "", 50,  1.0f/50.0f,  0.2f));
1894 			group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_100", "", 100, 1.0f/100.0f, 0.2f));
1895 		}
1896 
1897 		{
1898 			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Modifying gl_FragDepth");
1899 
1900 			testCostGroup->addChild(group);
1901 
1902 			group->addChild(new OccluderStaticFragDepthCostCase( testCtx, renderCtx, "occluder_static", ""));
1903 			group->addChild(new OccluderDynamicFragDepthCostCase(testCtx, renderCtx, "occluder_dynamic", ""));
1904 			group->addChild(new OccludedStaticFragDepthCostCase( testCtx, renderCtx, "occluded_static", ""));
1905 			group->addChild(new OccludedDynamicFragDepthCostCase(testCtx, renderCtx, "occluded_dynamic", ""));
1906 		}
1907 	}
1908 }
1909 
1910 } // Performance
1911 } // gles3
1912 } // deqp
1913