xref: /aosp_15_r20/external/deqp/modules/gles3/performance/es3pDepthTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 glu::ProgramSources;
62 using glu::RenderContext;
63 using glu::ShaderSource;
64 using std::map;
65 using std::string;
66 using std::vector;
67 using tcu::TestContext;
68 using tcu::TestLog;
69 using tcu::Vec2;
70 using tcu::Vec3;
71 using tcu::Vec4;
72 
73 struct Sample
74 {
75     int64_t nullTime;
76     int64_t baseTime;
77     int64_t testTime;
78     int order;
79     int workload;
80 };
81 
82 struct SampleParams
83 {
84     int step;
85     int measurement;
86 
SampleParamsdeqp::gles3::Performance::__anon5a4bff6a0111::SampleParams87     SampleParams(int step_, int measurement_) : step(step_), measurement(measurement_)
88     {
89     }
90 };
91 
92 typedef vector<float> Geometry;
93 
94 struct ObjectData
95 {
96     ProgramSources shader;
97     Geometry geometry;
98 
ObjectDatadeqp::gles3::Performance::__anon5a4bff6a0111::ObjectData99     ObjectData(const ProgramSources &shader_, const Geometry &geometry_) : shader(shader_), geometry(geometry_)
100     {
101     }
102 };
103 
104 class RenderData
105 {
106 public:
107     RenderData(const ObjectData &object, const glu::RenderContext &renderCtx, TestLog &log);
~RenderData(void)108     ~RenderData(void)
109     {
110     }
111 
112     const glu::ShaderProgram m_program;
113     const glu::VertexArray m_vao;
114     const glu::Buffer m_vbo;
115 
116     const int m_numVertices;
117 };
118 
RenderData(const ObjectData & object,const glu::RenderContext & renderCtx,TestLog & log)119 RenderData::RenderData(const ObjectData &object, const glu::RenderContext &renderCtx, TestLog &log)
120     : m_program(renderCtx, object.shader)
121     , m_vao(renderCtx.getFunctions())
122     , m_vbo(renderCtx.getFunctions())
123     , m_numVertices(int(object.geometry.size()) / 4)
124 {
125     const glw::Functions &gl = renderCtx.getFunctions();
126 
127     if (!m_program.isOk())
128         log << m_program;
129 
130     gl.bindBuffer(GL_ARRAY_BUFFER, *m_vbo);
131     gl.bufferData(GL_ARRAY_BUFFER, object.geometry.size() * sizeof(float), &object.geometry[0], GL_STATIC_DRAW);
132     gl.bindAttribLocation(m_program.getProgram(), 0, "a_position");
133 
134     gl.bindVertexArray(*m_vao);
135     gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
136     gl.enableVertexAttribArray(0);
137     gl.bindVertexArray(0);
138 }
139 
140 namespace Utils
141 {
getFullscreenQuad(float depth)142 vector<float> getFullscreenQuad(float depth)
143 {
144     const float data[] = {
145         +1.0f, +1.0f, depth, 0.0f, // .w is gl_VertexId%3 since Nexus 4&5 can't handle that on their own
146         +1.0f, -1.0f, depth, 1.0f,  -1.0f, -1.0f, depth, 2.0f,  -1.0f, -1.0f,
147         depth, 0.0f,  -1.0f, +1.0f, depth, 1.0f,  +1.0f, +1.0f, depth, 2.0f,
148     };
149 
150     return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
151 }
152 
getFullscreenQuadWithGradient(float depth0,float depth1)153 vector<float> getFullscreenQuadWithGradient(float depth0, float depth1)
154 {
155     const float data[] = {
156         +1.0f, +1.0f, depth0, 0.0f, +1.0f, -1.0f, depth0, 1.0f, -1.0f, -1.0f, depth1, 2.0f,
157         -1.0f, -1.0f, depth1, 0.0f, -1.0f, +1.0f, depth1, 1.0f, +1.0f, +1.0f, depth0, 2.0f,
158     };
159 
160     return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
161 }
162 
getPartScreenQuad(float coverage,float depth)163 vector<float> getPartScreenQuad(float coverage, float depth)
164 {
165     const float xMax   = -1.0f + 2.0f * coverage;
166     const float data[] = {
167         xMax,  +1.0f, depth, 0.0f, xMax,  -1.0f, depth, 1.0f, -1.0f, -1.0f, depth, 2.0f,
168         -1.0f, -1.0f, depth, 0.0f, -1.0f, +1.0f, depth, 1.0f, xMax,  +1.0f, depth, 2.0f,
169     };
170 
171     return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
172 }
173 
174 // Axis aligned grid. Depth of vertices is baseDepth +/- depthNoise
getFullScreenGrid(int resolution,uint32_t seed,float baseDepth,float depthNoise,float xyNoise)175 vector<float> getFullScreenGrid(int resolution, uint32_t seed, float baseDepth, float depthNoise, float xyNoise)
176 {
177     const int gridsize = resolution + 1;
178     vector<Vec3> vertices(gridsize * gridsize);
179     vector<float> retval;
180     de::Random rng(seed);
181 
182     for (int y = 0; y < gridsize; y++)
183         for (int x = 0; x < gridsize; x++)
184         {
185             const bool isEdge = x == 0 || y == 0 || x == resolution || y == resolution;
186             const float x_ =
187                 float(x) / float(resolution) * 2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
188             const float y_ =
189                 float(y) / float(resolution) * 2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
190             const float z_ = baseDepth + rng.getFloat(-depthNoise, +depthNoise);
191 
192             vertices[y * gridsize + x] = Vec3(x_, y_, z_);
193         }
194 
195     retval.reserve(resolution * resolution * 6);
196 
197     for (int y = 0; y < resolution; y++)
198         for (int x = 0; x < resolution; x++)
199         {
200             const Vec3 &p0 = vertices[(y + 0) * gridsize + (x + 0)];
201             const Vec3 &p1 = vertices[(y + 0) * gridsize + (x + 1)];
202             const Vec3 &p2 = vertices[(y + 1) * gridsize + (x + 0)];
203             const Vec3 &p3 = vertices[(y + 1) * gridsize + (x + 1)];
204 
205             const float temp[6 * 4] = {
206                 p0.x(), p0.y(), p0.z(), 0.0f, p2.x(), p2.y(), p2.z(), 1.0f, p1.x(), p1.y(), p1.z(), 2.0f,
207 
208                 p3.x(), p3.y(), p3.z(), 0.0f, p1.x(), p1.y(), p1.z(), 1.0f, p2.x(), p2.y(), p2.z(), 2.0f,
209             };
210 
211             retval.insert(retval.end(), DE_ARRAY_BEGIN(temp), DE_ARRAY_END(temp));
212         }
213 
214     return retval;
215 }
216 
217 // Outputs barycentric coordinates as v_bcoords. Otherwise a passthrough shader
getBaseVertexShader(void)218 string getBaseVertexShader(void)
219 {
220     return "#version 300 es\n"
221            "in highp vec4 a_position;\n"
222            "out mediump vec3 v_bcoords;\n"
223            "void main()\n"
224            "{\n"
225            "    v_bcoords = vec3(0, 0, 0);\n"
226            "    v_bcoords[int(a_position.w)] = 1.0;\n"
227            "    gl_Position = vec4(a_position.xyz, 1.0);\n"
228            "}\n";
229 }
230 
231 // Adds noise to coordinates based on InstanceID Outputs barycentric coordinates as v_bcoords
getInstanceNoiseVertexShader(void)232 string getInstanceNoiseVertexShader(void)
233 {
234     return "#version 300 es\n"
235            "in highp vec4 a_position;\n"
236            "out mediump vec3 v_bcoords;\n"
237            "void main()\n"
238            "{\n"
239            "    v_bcoords = vec3(0, 0, 0);\n"
240            "    v_bcoords[int(a_position.w)] = 1.0;\n"
241            "    vec3 noise = vec3(sin(float(gl_InstanceID)*1.05), sin(float(gl_InstanceID)*1.23), "
242            "sin(float(gl_InstanceID)*1.71));\n"
243            "    gl_Position = vec4(a_position.xyz + noise * 0.005, 1.0);\n"
244            "}\n";
245 }
246 
247 // Renders green triangles with edges highlighted. Exact shade depends on depth.
getDepthAsGreenFragmentShader(void)248 string getDepthAsGreenFragmentShader(void)
249 {
250     return "#version 300 es\n"
251            "in mediump vec3 v_bcoords;\n"
252            "out mediump vec4 fragColor;\n"
253            "void main()\n"
254            "{\n"
255            "    mediump float d = gl_FragCoord.z;\n"
256            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
257            "        fragColor = vec4(d,1,d,1);\n"
258            "    else\n"
259            "        fragColor = vec4(0,d,0,1);\n"
260            "}\n";
261 }
262 
263 // Renders green triangles with edges highlighted. Exact shade depends on depth.
getDepthAsRedFragmentShader(void)264 string getDepthAsRedFragmentShader(void)
265 {
266     return "#version 300 es\n"
267            "in mediump vec3 v_bcoords;\n"
268            "out mediump vec4 fragColor;\n"
269            "void main()\n"
270            "{\n"
271            "    mediump float d = gl_FragCoord.z;\n"
272            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
273            "        fragColor = vec4(1,d,d,1);\n"
274            "    else\n"
275            "        fragColor = vec4(d,0,0,1);\n"
276            "}\n";
277 }
278 
279 // Basic time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
getArithmeticWorkloadFragmentShader(void)280 string getArithmeticWorkloadFragmentShader(void)
281 {
282 
283     return "#version 300 es\n"
284            "in mediump vec3 v_bcoords;\n"
285            "out mediump vec4 fragColor;\n"
286            "uniform mediump int u_iterations;\n"
287            "void main()\n"
288            "{\n"
289            "    mediump float d = gl_FragCoord.z;\n"
290            "    for (int i = 0; i<u_iterations; i++)\n"
291            // 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
292            "        d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
293            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
294            "        fragColor = vec4(1,d,d,1);\n"
295            "    else\n"
296            "        fragColor = vec4(d,0,0,1);\n"
297            "}\n";
298 }
299 
300 // Arithmetic workload shader but contains discard
getArithmeticWorkloadDiscardFragmentShader(void)301 string getArithmeticWorkloadDiscardFragmentShader(void)
302 {
303     return "#version 300 es\n"
304            "in mediump vec3 v_bcoords;\n"
305            "out mediump vec4 fragColor;\n"
306            "uniform mediump int u_iterations;\n"
307            "void main()\n"
308            "{\n"
309            "    mediump float d = gl_FragCoord.z;\n"
310            "    for (int i = 0; i<u_iterations; i++)\n"
311            "        d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
312            "    if (d < 0.5) discard;\n"
313            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
314            "        fragColor = vec4(1,d,d,1);\n"
315            "    else\n"
316            "        fragColor = vec4(d,0,0,1);\n"
317            "}\n";
318 }
319 
320 // Texture fetch based time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
getTextureWorkloadFragmentShader(void)321 string getTextureWorkloadFragmentShader(void)
322 {
323     return "#version 300 es\n"
324            "in mediump vec3 v_bcoords;\n"
325            "out mediump vec4 fragColor;\n"
326            "uniform mediump int u_iterations;\n"
327            "uniform sampler2D u_texture;\n"
328            "void main()\n"
329            "{\n"
330            "    mediump float d = gl_FragCoord.z;\n"
331            "    for (int i = 0; i<u_iterations; i++)\n"
332            "        d *= texture(u_texture, (gl_FragCoord.xy+vec2(i))/512.0).r;\n" // Texture is expected to be fully white
333            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
334            "        fragColor = vec4(1,1,1,1);\n"
335            "    else\n"
336            "        fragColor = vec4(d,0,0,1);\n"
337            "}\n";
338 }
339 
340 // Discard fragments in a grid pattern
getGridDiscardFragmentShader(int gridsize)341 string getGridDiscardFragmentShader(int gridsize)
342 {
343     const string fragSrc =
344         "#version 300 es\n"
345         "in mediump vec3 v_bcoords;\n"
346         "out mediump vec4 fragColor;\n"
347         "void main()\n"
348         "{\n"
349         "    mediump float d = gl_FragCoord.z;\n"
350         "    if ((int(gl_FragCoord.x)/${GRIDRENDER_SIZE} + int(gl_FragCoord.y)/${GRIDRENDER_SIZE})%2 == 0)\n"
351         "        discard;\n"
352         "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
353         "        fragColor = vec4(d,1,d,1);\n"
354         "    else\n"
355         "        fragColor = vec4(0,d,0,1);\n"
356         "}\n";
357     map<string, string> params;
358 
359     params["GRIDRENDER_SIZE"] = de::toString(gridsize);
360 
361     return tcu::StringTemplate(fragSrc).specialize(params);
362 }
363 
364 // A static increment to frag depth
getStaticFragDepthFragmentShader(void)365 string getStaticFragDepthFragmentShader(void)
366 {
367     return "#version 300 es\n"
368            "in mediump vec3 v_bcoords;\n"
369            "out mediump vec4 fragColor;\n"
370            "void main()\n"
371            "{\n"
372            "    mediump float d = gl_FragCoord.z;\n"
373            "    gl_FragDepth = gl_FragCoord.z + 0.1;\n"
374            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
375            "        fragColor = vec4(d,1,d,1);\n"
376            "    else\n"
377            "        fragColor = vec4(0,d,0,1);\n"
378            "}\n";
379 }
380 
381 // A trivial dynamic change to frag depth
getDynamicFragDepthFragmentShader(void)382 string getDynamicFragDepthFragmentShader(void)
383 {
384     return "#version 300 es\n"
385            "in mediump vec3 v_bcoords;\n"
386            "out mediump vec4 fragColor;\n"
387            "void main()\n"
388            "{\n"
389            "    mediump float d = gl_FragCoord.z;\n"
390            "    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
391            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
392            "        fragColor = vec4(d,1,d,1);\n"
393            "    else\n"
394            "        fragColor = vec4(0,d,0,1);\n"
395            "}\n";
396 }
397 
398 // A static increment to frag depth
getStaticFragDepthArithmeticWorkloadFragmentShader(void)399 string getStaticFragDepthArithmeticWorkloadFragmentShader(void)
400 {
401     return "#version 300 es\n"
402            "in mediump vec3 v_bcoords;\n"
403            "out mediump vec4 fragColor;\n"
404            "uniform mediump int u_iterations;\n"
405            "void main()\n"
406            "{\n"
407            "    mediump float d = gl_FragCoord.z;\n"
408            "    gl_FragDepth = gl_FragCoord.z + 0.1;\n"
409            "    for (int i = 0; i<u_iterations; i++)\n"
410            "        d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
411            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
412            "        fragColor = vec4(1,d,d,1);\n"
413            "    else\n"
414            "        fragColor = vec4(d,0,0,1);\n"
415            "}\n";
416 }
417 
418 // A trivial dynamic change to frag depth
getDynamicFragDepthArithmeticWorkloadFragmentShader(void)419 string getDynamicFragDepthArithmeticWorkloadFragmentShader(void)
420 {
421     return "#version 300 es\n"
422            "in mediump vec3 v_bcoords;\n"
423            "out mediump vec4 fragColor;\n"
424            "uniform mediump int u_iterations;\n"
425            "void main()\n"
426            "{\n"
427            "    mediump float d = gl_FragCoord.z;\n"
428            "    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
429            "    for (int i = 0; i<u_iterations; i++)\n"
430            "        d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
431            "    if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
432            "        fragColor = vec4(1,d,d,1);\n"
433            "    else\n"
434            "        fragColor = vec4(d,0,0,1);\n"
435            "}\n";
436 }
437 
getBaseShader(void)438 glu::ProgramSources getBaseShader(void)
439 {
440     return glu::makeVtxFragSources(getBaseVertexShader(), getDepthAsGreenFragmentShader());
441 }
442 
getArithmeticWorkloadShader(void)443 glu::ProgramSources getArithmeticWorkloadShader(void)
444 {
445     return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadFragmentShader());
446 }
447 
getArithmeticWorkloadDiscardShader(void)448 glu::ProgramSources getArithmeticWorkloadDiscardShader(void)
449 {
450     return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadDiscardFragmentShader());
451 }
452 
getTextureWorkloadShader(void)453 glu::ProgramSources getTextureWorkloadShader(void)
454 {
455     return glu::makeVtxFragSources(getBaseVertexShader(), getTextureWorkloadFragmentShader());
456 }
457 
getGridDiscardShader(int gridsize)458 glu::ProgramSources getGridDiscardShader(int gridsize)
459 {
460     return glu::makeVtxFragSources(getBaseVertexShader(), getGridDiscardFragmentShader(gridsize));
461 }
462 
quadWith(const glu::ProgramSources & shader,float depth)463 inline ObjectData quadWith(const glu::ProgramSources &shader, float depth)
464 {
465     return ObjectData(shader, getFullscreenQuad(depth));
466 }
467 
quadWith(const string & fragShader,float depth)468 inline ObjectData quadWith(const string &fragShader, float depth)
469 {
470     return ObjectData(glu::makeVtxFragSources(getBaseVertexShader(), fragShader), getFullscreenQuad(depth));
471 }
472 
variableQuad(float depth)473 inline ObjectData variableQuad(float depth)
474 {
475     return ObjectData(glu::makeVtxFragSources(getInstanceNoiseVertexShader(), getDepthAsRedFragmentShader()),
476                       getFullscreenQuad(depth));
477 }
478 
fastQuad(float depth)479 inline ObjectData fastQuad(float depth)
480 {
481     return ObjectData(getBaseShader(), getFullscreenQuad(depth));
482 }
483 
slowQuad(float depth)484 inline ObjectData slowQuad(float depth)
485 {
486     return ObjectData(getArithmeticWorkloadShader(), getFullscreenQuad(depth));
487 }
488 
fastQuadWithGradient(float depth0,float depth1)489 inline ObjectData fastQuadWithGradient(float depth0, float depth1)
490 {
491     return ObjectData(getBaseShader(), getFullscreenQuadWithGradient(depth0, depth1));
492 }
493 } // namespace Utils
494 
495 // Shared base
496 class BaseCase : public tcu::TestCase
497 {
498 public:
499     enum
500     {
501         RENDER_SIZE = 512
502     };
503 
504     BaseCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc);
~BaseCase(void)505     virtual ~BaseCase(void)
506     {
507     }
508 
509     virtual IterateResult iterate(void);
510 
511 protected:
512     void logSamples(const vector<Sample> &samples, const string &name, const string &desc);
513     void logGeometry(const tcu::ConstPixelBufferAccess &sample, const glu::ShaderProgram &occluderProg,
514                      const glu::ShaderProgram &occludedProg);
515     virtual void logAnalysis(const vector<Sample> &samples) = 0;
516     virtual void logDescription(void)                       = 0;
517 
518     virtual ObjectData genOccluderGeometry(void) const = 0;
519     virtual ObjectData genOccludedGeometry(void) const = 0;
520 
521     virtual int calibrate(void) const                                                                       = 0;
522     virtual Sample renderSample(const RenderData &occluder, const RenderData &occluded, int workload) const = 0;
523 
524     void render(const RenderData &data) const;
525     void render(const RenderData &data, int instances) const;
526 
527     const RenderContext &m_renderCtx;
528     tcu::ResultCollector m_results;
529 
530     enum
531     {
532         ITERATION_STEPS   = 10,
533         ITERATION_SAMPLES = 16
534     };
535 };
536 
BaseCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)537 BaseCase::BaseCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc)
538     : TestCase(testCtx, tcu::NODETYPE_PERFORMANCE, name, desc)
539     , m_renderCtx(renderCtx)
540 {
541 }
542 
iterate(void)543 BaseCase::IterateResult BaseCase::iterate(void)
544 {
545     typedef de::MovePtr<RenderData> RenderDataP;
546 
547     const glw::Functions &gl = m_renderCtx.getFunctions();
548     TestLog &log             = m_testCtx.getLog();
549 
550     const glu::Framebuffer framebuffer(gl);
551     const glu::Renderbuffer renderbuffer(gl);
552     const glu::Renderbuffer depthbuffer(gl);
553 
554     vector<Sample> results;
555     vector<int> params;
556     RenderDataP occluderData;
557     RenderDataP occludedData;
558     tcu::TextureLevel resultTex(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
559                                 RENDER_SIZE, RENDER_SIZE);
560     int maxWorkload = 0;
561     de::Random rng(deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed());
562 
563     logDescription();
564 
565     gl.bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer);
566     gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE);
567     gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuffer);
568     gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, RENDER_SIZE, RENDER_SIZE);
569 
570     gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
571     gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *renderbuffer);
572     gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *depthbuffer);
573     gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
574     gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
575 
576     maxWorkload = calibrate();
577 
578     // Setup data
579     occluderData = RenderDataP(new RenderData(genOccluderGeometry(), m_renderCtx, log));
580     occludedData = RenderDataP(new RenderData(genOccludedGeometry(), m_renderCtx, log));
581 
582     TCU_CHECK(occluderData->m_program.isOk());
583     TCU_CHECK(occludedData->m_program.isOk());
584 
585     // Force initialization of GPU resources
586     gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
587     gl.enable(GL_DEPTH_TEST);
588 
589     render(*occluderData);
590     render(*occludedData);
591     glu::readPixels(m_renderCtx, 0, 0, resultTex.getAccess());
592 
593     logGeometry(resultTex.getAccess(), occluderData->m_program, occludedData->m_program);
594 
595     params.reserve(ITERATION_STEPS * ITERATION_SAMPLES);
596 
597     // Setup parameters
598     for (int step = 0; step < ITERATION_STEPS; step++)
599     {
600         const int workload = maxWorkload * step / ITERATION_STEPS;
601 
602         for (int count = 0; count < ITERATION_SAMPLES; count++)
603             params.push_back(workload);
604     }
605 
606     rng.shuffle(params.begin(), params.end());
607 
608     // Render samples
609     for (size_t ndx = 0; ndx < params.size(); ndx++)
610     {
611         const int workload = params[ndx];
612         Sample sample      = renderSample(*occluderData, *occludedData, workload);
613 
614         sample.workload = workload;
615         sample.order    = int(ndx);
616 
617         results.push_back(sample);
618     }
619 
620     logSamples(results, "Samples", "Samples");
621     logAnalysis(results);
622 
623     m_results.setTestContextResult(m_testCtx);
624 
625     return STOP;
626 }
627 
logSamples(const vector<Sample> & samples,const string & name,const string & desc)628 void BaseCase::logSamples(const vector<Sample> &samples, const string &name, const string &desc)
629 {
630     TestLog &log = m_testCtx.getLog();
631 
632     bool testOnly = true;
633 
634     for (size_t ndx = 0; ndx < samples.size(); ndx++)
635     {
636         if (samples[ndx].baseTime != 0 || samples[ndx].nullTime != 0)
637         {
638             testOnly = false;
639             break;
640         }
641     }
642 
643     log << TestLog::SampleList(name, desc);
644 
645     if (testOnly)
646     {
647         log << TestLog::SampleInfo << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
648             << TestLog::ValueInfo("Order", "Order of sample", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
649             << TestLog::ValueInfo("TestTime", "Test render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
650             << TestLog::EndSampleInfo;
651 
652         for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
653         {
654             const Sample &sample = samples[sampleNdx];
655 
656             log << TestLog::Sample << sample.workload << sample.order << sample.testTime << TestLog::EndSample;
657         }
658     }
659     else
660     {
661         log << TestLog::SampleInfo << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
662             << TestLog::ValueInfo("Order", "Order of sample", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
663             << TestLog::ValueInfo("TestTime", "Test render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
664             << TestLog::ValueInfo("NullTime", "Read pixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
665             << TestLog::ValueInfo("BaseTime", "Base render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
666             << TestLog::EndSampleInfo;
667 
668         for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
669         {
670             const Sample &sample = samples[sampleNdx];
671 
672             log << TestLog::Sample << sample.workload << sample.order << sample.testTime << sample.nullTime
673                 << sample.baseTime << TestLog::EndSample;
674         }
675     }
676 
677     log << TestLog::EndSampleList;
678 }
679 
logGeometry(const tcu::ConstPixelBufferAccess & sample,const glu::ShaderProgram & occluderProg,const glu::ShaderProgram & occludedProg)680 void BaseCase::logGeometry(const tcu::ConstPixelBufferAccess &sample, const glu::ShaderProgram &occluderProg,
681                            const glu::ShaderProgram &occludedProg)
682 {
683     TestLog &log = m_testCtx.getLog();
684 
685     log << TestLog::Section("Geometry", "Geometry");
686     log << TestLog::Message << "Occluding geometry is green with shade dependent on depth (rgb == 0, depth, 0)"
687         << TestLog::EndMessage;
688     log << TestLog::Message << "Occluded geometry is red with shade dependent on depth (rgb == depth, 0, 0)"
689         << TestLog::EndMessage;
690     log << TestLog::Message << "Primitive edges are a lighter shade of red/green" << TestLog::EndMessage;
691 
692     log << TestLog::Image("Test Geometry", "Test Geometry", sample);
693     log << TestLog::EndSection;
694 
695     log << TestLog::Section("Occluder", "Occluder");
696     log << occluderProg;
697     log << TestLog::EndSection;
698 
699     log << TestLog::Section("Occluded", "Occluded");
700     log << occludedProg;
701     log << TestLog::EndSection;
702 }
703 
render(const RenderData & data) const704 void BaseCase::render(const RenderData &data) const
705 {
706     const glw::Functions &gl = m_renderCtx.getFunctions();
707 
708     gl.useProgram(data.m_program.getProgram());
709 
710     gl.bindVertexArray(*data.m_vao);
711     gl.drawArrays(GL_TRIANGLES, 0, data.m_numVertices);
712     gl.bindVertexArray(0);
713 }
714 
render(const RenderData & data,int instances) const715 void BaseCase::render(const RenderData &data, int instances) const
716 {
717     const glw::Functions &gl = m_renderCtx.getFunctions();
718 
719     gl.useProgram(data.m_program.getProgram());
720 
721     gl.bindVertexArray(*data.m_vao);
722     gl.drawArraysInstanced(GL_TRIANGLES, 0, data.m_numVertices, instances);
723     gl.bindVertexArray(0);
724 }
725 
726 // Render occluder once, then repeatedly render occluded geometry. Sample with multiple repetition counts & establish time per call with linear regression
727 class RenderCountCase : public BaseCase
728 {
729 public:
730     RenderCountCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc);
~RenderCountCase(void)731     ~RenderCountCase(void)
732     {
733     }
734 
735 protected:
736     virtual void logAnalysis(const vector<Sample> &samples);
737 
738 private:
739     virtual int calibrate(void) const;
740     virtual Sample renderSample(const RenderData &occluder, const RenderData &occluded, int callcount) const;
741 };
742 
RenderCountCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)743 RenderCountCase::RenderCountCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
744                                  const char *desc)
745     : BaseCase(testCtx, renderCtx, name, desc)
746 {
747 }
748 
logAnalysis(const vector<Sample> & samples)749 void RenderCountCase::logAnalysis(const vector<Sample> &samples)
750 {
751     using namespace gls;
752 
753     TestLog &log    = m_testCtx.getLog();
754     int maxWorkload = 0;
755     vector<Vec2> testSamples(samples.size());
756 
757     for (size_t ndx = 0; ndx < samples.size(); ndx++)
758     {
759         const Sample &sample = samples[ndx];
760 
761         testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
762 
763         maxWorkload = de::max(maxWorkload, sample.workload);
764     }
765 
766     {
767         const float confidence                       = 0.60f;
768         const LineParametersWithConfidence testParam = theilSenSiegelLinearRegression(testSamples, confidence);
769         const float usPerCall                        = testParam.coefficient;
770         const float pxPerCall                        = RENDER_SIZE * RENDER_SIZE;
771         const float pxPerUs                          = pxPerCall / usPerCall;
772         const float mpxPerS                          = pxPerUs;
773 
774         log << TestLog::Section("Linear Regression", "Linear Regression");
775         log << TestLog::Message
776             << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. "
777                "Reported confidence interval for this test is "
778             << confidence << TestLog::EndMessage;
779         log << TestLog::Message << "Render time for scene with depth test was\n\t"
780             << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset << ", "
781             << testParam.offsetConfidenceUpper << "]us +"
782             << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", "
783             << testParam.coefficientConfidenceUpper << "]"
784             << "us/workload" << TestLog::EndMessage;
785         log << TestLog::EndSection;
786 
787         log << TestLog::Section("Result", "Result");
788 
789         if (testParam.coefficientConfidenceLower < 0.0f)
790         {
791             log << TestLog::Message
792                 << "Coefficient confidence bounds include values below 0.0, the operation likely has neglible "
793                    "per-pixel cost"
794                 << TestLog::EndMessage;
795             m_results.addResult(QP_TEST_RESULT_PASS, "Pass");
796         }
797         else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper * 0.25)
798         {
799             log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result"
800                 << TestLog::EndMessage;
801             m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
802         }
803         else
804         {
805             log << TestLog::Message << "Culled hidden pixels @ " << mpxPerS << "Mpx/s" << TestLog::EndMessage;
806             m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(mpxPerS, 2));
807         }
808 
809         log << TestLog::EndSection;
810     }
811 }
812 
renderSample(const RenderData & occluder,const RenderData & occluded,int callcount) const813 Sample RenderCountCase::renderSample(const RenderData &occluder, const RenderData &occluded, int callcount) const
814 {
815     const glw::Functions &gl = m_renderCtx.getFunctions();
816     Sample sample;
817     uint64_t now  = 0;
818     uint64_t prev = 0;
819     uint8_t buffer[4];
820 
821     // Stabilize
822     {
823         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
824         gl.enable(GL_DEPTH_TEST);
825         gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
826     }
827 
828     prev = deGetMicroseconds();
829 
830     gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
831     gl.enable(GL_DEPTH_TEST);
832 
833     render(occluder);
834     render(occluded, callcount);
835 
836     gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
837 
838     now = deGetMicroseconds();
839 
840     sample.testTime = now - prev;
841     sample.baseTime = 0;
842     sample.nullTime = 0;
843     sample.workload = callcount;
844 
845     return sample;
846 }
847 
calibrate(void) const848 int RenderCountCase::calibrate(void) const
849 {
850     using namespace gls;
851 
852     const glw::Functions &gl = m_renderCtx.getFunctions();
853     TestLog &log             = m_testCtx.getLog();
854 
855     const RenderData occluderGeometry(genOccluderGeometry(), m_renderCtx, log);
856     const RenderData occludedGeometry(genOccludedGeometry(), m_renderCtx, log);
857 
858     TheilSenCalibrator calibrator(CalibratorParameters(20,     // Initial workload
859                                                        10,     // Max iteration frames
860                                                        20.0f,  // Iteration shortcut threshold ms
861                                                        20,     // Max iterations
862                                                        33.0f,  // Target frame time
863                                                        40.0f,  // Frame time cap
864                                                        1000.0f // Target measurement duration
865                                                        ));
866 
867     while (true)
868     {
869         switch (calibrator.getState())
870         {
871         case TheilSenCalibrator::STATE_FINISHED:
872             logCalibrationInfo(m_testCtx.getLog(), calibrator);
873             return calibrator.getCallCount();
874 
875         case TheilSenCalibrator::STATE_MEASURE:
876         {
877             uint8_t buffer[4];
878             int64_t now;
879             int64_t prev;
880 
881             prev = deGetMicroseconds();
882 
883             gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
884             gl.disable(GL_DEPTH_TEST);
885 
886             render(occluderGeometry);
887             render(occludedGeometry, calibrator.getCallCount());
888 
889             gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
890 
891             now = deGetMicroseconds();
892 
893             calibrator.recordIteration(now - prev);
894             break;
895         }
896 
897         case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
898             calibrator.recomputeParameters();
899             break;
900         default:
901             DE_ASSERT(false);
902             return 1;
903         }
904     }
905 }
906 
907 // Compares time/workload gradients of same geometry with and without depth testing
908 class RelativeChangeCase : public BaseCase
909 {
910 public:
911     RelativeChangeCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc);
~RelativeChangeCase(void)912     virtual ~RelativeChangeCase(void)
913     {
914     }
915 
916 protected:
917     Sample renderSample(const RenderData &occluder, const RenderData &occluded, int workload) const;
918 
919     virtual void logAnalysis(const vector<Sample> &samples);
920 
921 private:
922     int calibrate(void) const;
923 };
924 
RelativeChangeCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)925 RelativeChangeCase::RelativeChangeCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
926                                        const char *desc)
927     : BaseCase(testCtx, renderCtx, name, desc)
928 {
929 }
930 
calibrate(void) const931 int RelativeChangeCase::calibrate(void) const
932 {
933     using namespace gls;
934 
935     const glw::Functions &gl = m_renderCtx.getFunctions();
936     TestLog &log             = m_testCtx.getLog();
937 
938     const RenderData geom(genOccludedGeometry(), m_renderCtx, log);
939 
940     TheilSenCalibrator calibrator(CalibratorParameters(20,     // Initial workload
941                                                        10,     // Max iteration frames
942                                                        20.0f,  // Iteration shortcut threshold ms
943                                                        20,     // Max iterations
944                                                        33.0f,  // Target frame time
945                                                        40.0f,  // Frame time cap
946                                                        1000.0f // Target measurement duration
947                                                        ));
948 
949     while (true)
950     {
951         switch (calibrator.getState())
952         {
953         case TheilSenCalibrator::STATE_FINISHED:
954             logCalibrationInfo(m_testCtx.getLog(), calibrator);
955             return calibrator.getCallCount();
956 
957         case TheilSenCalibrator::STATE_MEASURE:
958         {
959             uint8_t buffer[4];
960             const GLuint program = geom.m_program.getProgram();
961 
962             gl.useProgram(program);
963             gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), calibrator.getCallCount());
964 
965             const int64_t prev = deGetMicroseconds();
966 
967             gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
968             gl.disable(GL_DEPTH_TEST);
969 
970             render(geom);
971 
972             gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
973 
974             const int64_t now = deGetMicroseconds();
975 
976             calibrator.recordIteration(now - prev);
977             break;
978         }
979 
980         case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
981             calibrator.recomputeParameters();
982             break;
983         default:
984             DE_ASSERT(false);
985             return 1;
986         }
987     }
988 }
989 
renderSample(const RenderData & occluder,const RenderData & occluded,int workload) const990 Sample RelativeChangeCase::renderSample(const RenderData &occluder, const RenderData &occluded, int workload) const
991 {
992     const glw::Functions &gl = m_renderCtx.getFunctions();
993     const GLuint program     = occluded.m_program.getProgram();
994     Sample sample;
995     uint64_t now  = 0;
996     uint64_t prev = 0;
997     uint8_t buffer[4];
998 
999     gl.useProgram(program);
1000     gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
1001 
1002     // Warmup (this workload seems to reduce variation in following workloads)
1003     {
1004         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1005         gl.disable(GL_DEPTH_TEST);
1006 
1007         gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1008     }
1009 
1010     // Null time
1011     {
1012         prev = deGetMicroseconds();
1013 
1014         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1015         gl.disable(GL_DEPTH_TEST);
1016 
1017         gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1018 
1019         now = deGetMicroseconds();
1020 
1021         sample.nullTime = now - prev;
1022     }
1023 
1024     // Test time
1025     {
1026         prev = deGetMicroseconds();
1027 
1028         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1029         gl.enable(GL_DEPTH_TEST);
1030 
1031         render(occluder);
1032         render(occluded);
1033 
1034         gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1035 
1036         now = deGetMicroseconds();
1037 
1038         sample.testTime = now - prev;
1039     }
1040 
1041     // Base time
1042     {
1043         prev = deGetMicroseconds();
1044 
1045         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1046         gl.disable(GL_DEPTH_TEST);
1047 
1048         render(occluder);
1049         render(occluded);
1050 
1051         gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1052 
1053         now = deGetMicroseconds();
1054 
1055         sample.baseTime = now - prev;
1056     }
1057 
1058     sample.workload = 0;
1059 
1060     return sample;
1061 }
1062 
logAnalysis(const vector<Sample> & samples)1063 void RelativeChangeCase::logAnalysis(const vector<Sample> &samples)
1064 {
1065     using namespace gls;
1066 
1067     TestLog &log = m_testCtx.getLog();
1068 
1069     int maxWorkload = 0;
1070 
1071     vector<Vec2> nullSamples(samples.size());
1072     vector<Vec2> baseSamples(samples.size());
1073     vector<Vec2> testSamples(samples.size());
1074 
1075     for (size_t ndx = 0; ndx < samples.size(); ndx++)
1076     {
1077         const Sample &sample = samples[ndx];
1078 
1079         nullSamples[ndx] = Vec2((float)sample.workload, (float)sample.nullTime);
1080         baseSamples[ndx] = Vec2((float)sample.workload, (float)sample.baseTime);
1081         testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
1082 
1083         maxWorkload = de::max(maxWorkload, sample.workload);
1084     }
1085 
1086     {
1087         const float confidence = 0.60f;
1088 
1089         const LineParametersWithConfidence nullParam = theilSenSiegelLinearRegression(nullSamples, confidence);
1090         const LineParametersWithConfidence baseParam = theilSenSiegelLinearRegression(baseSamples, confidence);
1091         const LineParametersWithConfidence testParam = theilSenSiegelLinearRegression(testSamples, confidence);
1092 
1093         if (!de::inRange(0.0f, nullParam.coefficientConfidenceLower, nullParam.coefficientConfidenceUpper))
1094         {
1095             m_results.addResult(QP_TEST_RESULT_FAIL, "Constant operation sequence duration not constant");
1096             log << TestLog::Message
1097                 << "Constant operation sequence timing may vary as a function of workload. Result quality extremely low"
1098                 << TestLog::EndMessage;
1099         }
1100 
1101         if (de::inRange(0.0f, baseParam.coefficientConfidenceLower, baseParam.coefficientConfidenceUpper))
1102         {
1103             m_results.addResult(QP_TEST_RESULT_FAIL, "Workload has no effect on duration");
1104             log << TestLog::Message << "Workload factor has no effect on duration of sample (smart optimizer?)"
1105                 << TestLog::EndMessage;
1106         }
1107 
1108         log << TestLog::Section("Linear Regression", "Linear Regression");
1109         log << TestLog::Message
1110             << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. "
1111                "Reported confidence interval for this test is "
1112             << confidence << TestLog::EndMessage;
1113 
1114         log << TestLog::Message << "Render time for empty scene was\n\t"
1115             << "[" << nullParam.offsetConfidenceLower << ", " << nullParam.offset << ", "
1116             << nullParam.offsetConfidenceUpper << "]us +"
1117             << "[" << nullParam.coefficientConfidenceLower << ", " << nullParam.coefficient << ", "
1118             << nullParam.coefficientConfidenceUpper << "]"
1119             << "us/workload" << TestLog::EndMessage;
1120 
1121         log << TestLog::Message << "Render time for scene without depth test was\n\t"
1122             << "[" << baseParam.offsetConfidenceLower << ", " << baseParam.offset << ", "
1123             << baseParam.offsetConfidenceUpper << "]us +"
1124             << "[" << baseParam.coefficientConfidenceLower << ", " << baseParam.coefficient << ", "
1125             << baseParam.coefficientConfidenceUpper << "]"
1126             << "us/workload" << TestLog::EndMessage;
1127 
1128         log << TestLog::Message << "Render time for scene with depth test was\n\t"
1129             << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset << ", "
1130             << testParam.offsetConfidenceUpper << "]us +"
1131             << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", "
1132             << testParam.coefficientConfidenceUpper << "]"
1133             << "us/workload" << TestLog::EndMessage;
1134 
1135         log << TestLog::EndSection;
1136 
1137         if (de::inRange(0.0f, testParam.coefficientConfidenceLower, testParam.coefficientConfidenceUpper))
1138         {
1139             log << TestLog::Message << "Test duration not dependent on culled workload" << TestLog::EndMessage;
1140             m_results.addResult(QP_TEST_RESULT_PASS, "0.0");
1141         }
1142         else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper * 0.25)
1143         {
1144             log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result"
1145                 << TestLog::EndMessage;
1146             m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
1147         }
1148         else if (baseParam.coefficientConfidenceLower < baseParam.coefficientConfidenceUpper * 0.25)
1149         {
1150             log << TestLog::Message
1151                 << "Coefficient confidence range for base render time is extremely large, cannot give reliable result"
1152                 << TestLog::EndMessage;
1153             m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
1154         }
1155         else
1156         {
1157             log << TestLog::Message << "Test duration is dependent on culled workload" << TestLog::EndMessage;
1158             m_results.addResult(QP_TEST_RESULT_PASS,
1159                                 de::floatToString(de::abs(testParam.coefficient) / de::abs(baseParam.coefficient), 2));
1160         }
1161     }
1162 }
1163 
1164 // Speed of trivial culling
1165 class BaseCostCase : public RenderCountCase
1166 {
1167 public:
BaseCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1168     BaseCostCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc)
1169         : RenderCountCase(testCtx, renderCtx, name, desc)
1170     {
1171     }
1172 
~BaseCostCase(void)1173     ~BaseCostCase(void)
1174     {
1175     }
1176 
1177 private:
genOccluderGeometry(void) const1178     virtual ObjectData genOccluderGeometry(void) const
1179     {
1180         return Utils::fastQuad(0.2f);
1181     }
genOccludedGeometry(void) const1182     virtual ObjectData genOccludedGeometry(void) const
1183     {
1184         return Utils::variableQuad(0.8f);
1185     }
1186 
logDescription(void)1187     virtual void logDescription(void)
1188     {
1189         TestLog &log = m_testCtx.getLog();
1190 
1191         log << TestLog::Section("Description", "Test description");
1192         log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1193         log << TestLog::Message
1194             << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second "
1195                "(occluded) is rendered repeatedly"
1196             << TestLog::EndMessage;
1197         log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"
1198             << TestLog::EndMessage;
1199         log << TestLog::Message
1200             << "The time per culled pixel is estimated from the rate of change of rendering time as a function of "
1201                "workload"
1202             << TestLog::EndMessage;
1203         log << TestLog::EndSection;
1204     }
1205 };
1206 
1207 // Gradient
1208 class GradientCostCase : public RenderCountCase
1209 {
1210 public:
GradientCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,float gradientDistance)1211     GradientCostCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc,
1212                      float gradientDistance)
1213         : RenderCountCase(testCtx, renderCtx, name, desc)
1214         , m_gradientDistance(gradientDistance)
1215     {
1216     }
1217 
~GradientCostCase(void)1218     ~GradientCostCase(void)
1219     {
1220     }
1221 
1222 private:
genOccluderGeometry(void) const1223     virtual ObjectData genOccluderGeometry(void) const
1224     {
1225         return Utils::fastQuadWithGradient(0.0f, 1.0f - m_gradientDistance);
1226     }
genOccludedGeometry(void) const1227     virtual ObjectData genOccludedGeometry(void) const
1228     {
1229         return ObjectData(
1230             glu::makeVtxFragSources(Utils::getInstanceNoiseVertexShader(), Utils::getDepthAsRedFragmentShader()),
1231             Utils::getFullscreenQuadWithGradient(m_gradientDistance, 1.0f));
1232     }
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
1241             << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second "
1242                "(occluded) is rendered repeatedly"
1243             << TestLog::EndMessage;
1244         log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"
1245             << TestLog::EndMessage;
1246         log << TestLog::Message
1247             << "The quads are tilted so that the left edge of the occluded quad has a depth of 1.0 and the right edge "
1248                "of the occluding quad has a depth of 0.0."
1249             << TestLog::EndMessage;
1250         log << TestLog::Message << "The quads are spaced to have a depth difference of " << m_gradientDistance
1251             << " at all points." << TestLog::EndMessage;
1252         log << TestLog::Message
1253             << "The time per culled pixel is estimated from the rate of change of rendering time as a function of "
1254                "workload"
1255             << TestLog::EndMessage;
1256         log << TestLog::EndSection;
1257     }
1258 
1259     const float m_gradientDistance;
1260 };
1261 
1262 // Constant offset to frag depth in occluder
1263 class OccluderStaticFragDepthCostCase : public RenderCountCase
1264 {
1265 public:
OccluderStaticFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1266     OccluderStaticFragDepthCostCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1267                                     const char *desc)
1268         : RenderCountCase(testCtx, renderCtx, name, desc)
1269     {
1270     }
1271 
~OccluderStaticFragDepthCostCase(void)1272     ~OccluderStaticFragDepthCostCase(void)
1273     {
1274     }
1275 
1276 private:
genOccluderGeometry(void) const1277     virtual ObjectData genOccluderGeometry(void) const
1278     {
1279         return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f);
1280     }
genOccludedGeometry(void) const1281     virtual ObjectData genOccludedGeometry(void) const
1282     {
1283         return Utils::fastQuad(0.8f);
1284     }
1285 
logDescription(void)1286     virtual void logDescription(void)
1287     {
1288         TestLog &log = m_testCtx.getLog();
1289 
1290         log << TestLog::Section("Description", "Test description");
1291         log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1292         log << TestLog::Message
1293             << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second "
1294                "(occluded) is rendered repeatedly"
1295             << TestLog::EndMessage;
1296         log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"
1297             << TestLog::EndMessage;
1298         log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth"
1299             << TestLog::EndMessage;
1300         log << TestLog::Message
1301             << "The time per culled pixel is estimated from the rate of change of rendering time as a function of "
1302                "workload"
1303             << TestLog::EndMessage;
1304         log << TestLog::EndSection;
1305     }
1306 };
1307 
1308 // Dynamic offset to frag depth in occluder
1309 class OccluderDynamicFragDepthCostCase : public RenderCountCase
1310 {
1311 public:
OccluderDynamicFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1312     OccluderDynamicFragDepthCostCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1313                                      const char *desc)
1314         : RenderCountCase(testCtx, renderCtx, name, desc)
1315     {
1316     }
1317 
~OccluderDynamicFragDepthCostCase(void)1318     ~OccluderDynamicFragDepthCostCase(void)
1319     {
1320     }
1321 
1322 private:
genOccluderGeometry(void) const1323     virtual ObjectData genOccluderGeometry(void) const
1324     {
1325         return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f);
1326     }
genOccludedGeometry(void) const1327     virtual ObjectData genOccludedGeometry(void) const
1328     {
1329         return Utils::fastQuad(0.8f);
1330     }
1331 
logDescription(void)1332     virtual void logDescription(void)
1333     {
1334         TestLog &log = m_testCtx.getLog();
1335 
1336         log << TestLog::Section("Description", "Test description");
1337         log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1338         log << TestLog::Message
1339             << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second "
1340                "(occluded) is rendered repeatedly"
1341             << TestLog::EndMessage;
1342         log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"
1343             << TestLog::EndMessage;
1344         log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth"
1345             << TestLog::EndMessage;
1346         log << TestLog::Message
1347             << "The time per culled pixel is estimated from the rate of change of rendering time as a function of "
1348                "workload"
1349             << TestLog::EndMessage;
1350         log << TestLog::EndSection;
1351     }
1352 };
1353 
1354 // Constant offset to frag depth in occluder
1355 class OccludedStaticFragDepthCostCase : public RenderCountCase
1356 {
1357 public:
OccludedStaticFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1358     OccludedStaticFragDepthCostCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1359                                     const char *desc)
1360         : RenderCountCase(testCtx, renderCtx, name, desc)
1361     {
1362     }
1363 
~OccludedStaticFragDepthCostCase(void)1364     ~OccludedStaticFragDepthCostCase(void)
1365     {
1366     }
1367 
1368 private:
genOccluderGeometry(void) const1369     virtual ObjectData genOccluderGeometry(void) const
1370     {
1371         return Utils::fastQuad(0.2f);
1372     }
genOccludedGeometry(void) const1373     virtual ObjectData genOccludedGeometry(void) const
1374     {
1375         return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f);
1376     }
1377 
logDescription(void)1378     virtual void logDescription(void)
1379     {
1380         TestLog &log = m_testCtx.getLog();
1381 
1382         log << TestLog::Section("Description", "Test description");
1383         log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1384         log << TestLog::Message
1385             << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second "
1386                "(occluded) is rendered repeatedly"
1387             << TestLog::EndMessage;
1388         log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"
1389             << TestLog::EndMessage;
1390         log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth"
1391             << TestLog::EndMessage;
1392         log << TestLog::Message
1393             << "The time per culled pixel is estimated from the rate of change of rendering time as a function of "
1394                "workload"
1395             << TestLog::EndMessage;
1396         log << TestLog::EndSection;
1397     }
1398 };
1399 
1400 // Dynamic offset to frag depth in occluder
1401 class OccludedDynamicFragDepthCostCase : public RenderCountCase
1402 {
1403 public:
OccludedDynamicFragDepthCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1404     OccludedDynamicFragDepthCostCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1405                                      const char *desc)
1406         : RenderCountCase(testCtx, renderCtx, name, desc)
1407     {
1408     }
1409 
~OccludedDynamicFragDepthCostCase(void)1410     ~OccludedDynamicFragDepthCostCase(void)
1411     {
1412     }
1413 
1414 private:
genOccluderGeometry(void) const1415     virtual ObjectData genOccluderGeometry(void) const
1416     {
1417         return Utils::fastQuad(0.2f);
1418     }
genOccludedGeometry(void) const1419     virtual ObjectData genOccludedGeometry(void) const
1420     {
1421         return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f);
1422     }
1423 
logDescription(void)1424     virtual void logDescription(void)
1425     {
1426         TestLog &log = m_testCtx.getLog();
1427 
1428         log << TestLog::Section("Description", "Test description");
1429         log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1430         log << TestLog::Message
1431             << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second "
1432                "(occluded) is rendered repeatedly"
1433             << TestLog::EndMessage;
1434         log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"
1435             << TestLog::EndMessage;
1436         log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth"
1437             << TestLog::EndMessage;
1438         log << TestLog::Message
1439             << "The time per culled pixel is estimated from the rate of change of rendering time as a function of "
1440                "workload"
1441             << TestLog::EndMessage;
1442         log << TestLog::EndSection;
1443     }
1444 };
1445 
1446 // Culling speed with slightly less trivial geometry
1447 class OccludingGeometryComplexityCostCase : public RenderCountCase
1448 {
1449 public:
OccludingGeometryComplexityCostCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,int resolution,float xyNoise,float zNoise)1450     OccludingGeometryComplexityCostCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1451                                         const char *desc, int resolution, float xyNoise, float zNoise)
1452         : RenderCountCase(testCtx, renderCtx, name, desc)
1453         , m_resolution(resolution)
1454         , m_xyNoise(xyNoise)
1455         , m_zNoise(zNoise)
1456     {
1457     }
1458 
~OccludingGeometryComplexityCostCase(void)1459     ~OccludingGeometryComplexityCostCase(void)
1460     {
1461     }
1462 
1463 private:
genOccluderGeometry(void) const1464     virtual ObjectData genOccluderGeometry(void) const
1465     {
1466         return ObjectData(Utils::getBaseShader(), Utils::getFullScreenGrid(m_resolution,
1467                                                                            deInt32Hash(deStringHash(getName())) ^
1468                                                                                m_testCtx.getCommandLine().getBaseSeed(),
1469                                                                            0.2f, m_zNoise, m_xyNoise));
1470     }
1471 
genOccludedGeometry(void) const1472     virtual ObjectData genOccludedGeometry(void) const
1473     {
1474         return Utils::variableQuad(0.8f);
1475     }
1476 
logDescription(void)1477     virtual void logDescription(void)
1478     {
1479         TestLog &log = m_testCtx.getLog();
1480 
1481         log << TestLog::Section("Description", "Test description");
1482         log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1483         log << TestLog::Message
1484             << "Geometry consists of an occluding grid and an occluded fullsceen quad. The occluding geometry is "
1485                "rendered once, the occluded one is rendered repeatedly"
1486             << TestLog::EndMessage;
1487         log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered"
1488             << TestLog::EndMessage;
1489         log << TestLog::Message
1490             << "The time per culled pixel is estimated from the rate of change of rendering time as a function of "
1491                "workload"
1492             << TestLog::EndMessage;
1493         log << TestLog::EndSection;
1494     }
1495 
1496     const int m_resolution;
1497     const float m_xyNoise;
1498     const float m_zNoise;
1499 };
1500 
1501 // Cases with varying workloads in the fragment shader
1502 class FragmentWorkloadCullCase : public RelativeChangeCase
1503 {
1504 public:
1505     FragmentWorkloadCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc);
~FragmentWorkloadCullCase(void)1506     virtual ~FragmentWorkloadCullCase(void)
1507     {
1508     }
1509 
1510 private:
genOccluderGeometry(void) const1511     virtual ObjectData genOccluderGeometry(void) const
1512     {
1513         return Utils::fastQuad(0.2f);
1514     }
1515 
1516     virtual void logDescription(void);
1517 };
1518 
FragmentWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1519 FragmentWorkloadCullCase::FragmentWorkloadCullCase(TestContext &testCtx, const RenderContext &renderCtx,
1520                                                    const char *name, const char *desc)
1521     : RelativeChangeCase(testCtx, renderCtx, name, desc)
1522 {
1523 }
1524 
logDescription(void)1525 void FragmentWorkloadCullCase::logDescription(void)
1526 {
1527     TestLog &log = m_testCtx.getLog();
1528 
1529     log << TestLog::Section("Description", "Test description");
1530     log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
1531     log << TestLog::Message
1532         << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
1533            "the second (occluded) contains significant fragment shader work"
1534         << TestLog::EndMessage;
1535     log << TestLog::Message
1536         << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1537         << TestLog::EndMessage;
1538     log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1539         << TestLog::EndMessage;
1540     log << TestLog::Message
1541         << "Successfull early Z-testing should result in no correlation between workload and render time"
1542         << TestLog::EndMessage;
1543     log << TestLog::EndSection;
1544 }
1545 
1546 // Additional workload consists of texture lookups
1547 class FragmentTextureWorkloadCullCase : public FragmentWorkloadCullCase
1548 {
1549 public:
1550     FragmentTextureWorkloadCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1551                                     const char *desc);
~FragmentTextureWorkloadCullCase(void)1552     virtual ~FragmentTextureWorkloadCullCase(void)
1553     {
1554     }
1555 
1556     virtual void init(void);
1557     virtual void deinit(void);
1558 
1559 private:
1560     typedef MovePtr<glu::Texture> TexPtr;
1561 
genOccludedGeometry(void) const1562     virtual ObjectData genOccludedGeometry(void) const
1563     {
1564         return ObjectData(Utils::getTextureWorkloadShader(), Utils::getFullscreenQuad(0.8f));
1565     }
1566 
1567     TexPtr m_texture;
1568 };
1569 
FragmentTextureWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1570 FragmentTextureWorkloadCullCase::FragmentTextureWorkloadCullCase(TestContext &testCtx, const RenderContext &renderCtx,
1571                                                                  const char *name, const char *desc)
1572     : FragmentWorkloadCullCase(testCtx, renderCtx, name, desc)
1573 {
1574 }
1575 
init(void)1576 void FragmentTextureWorkloadCullCase::init(void)
1577 {
1578     const glw::Functions &gl = m_renderCtx.getFunctions();
1579     const int size           = 128;
1580     const vector<uint8_t> data(size * size * 4, 255);
1581 
1582     m_texture = MovePtr<glu::Texture>(new glu::Texture(gl));
1583 
1584     gl.bindTexture(GL_TEXTURE_2D, m_texture);
1585     gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
1586     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1587     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1588 }
1589 
deinit(void)1590 void FragmentTextureWorkloadCullCase::deinit(void)
1591 {
1592     m_texture.clear();
1593 }
1594 
1595 // Additional workload consists of arithmetic
1596 class FragmentArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
1597 {
1598 public:
FragmentArithmeticWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1599     FragmentArithmeticWorkloadCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1600                                        const char *desc)
1601         : FragmentWorkloadCullCase(testCtx, renderCtx, name, desc)
1602     {
1603     }
~FragmentArithmeticWorkloadCullCase(void)1604     virtual ~FragmentArithmeticWorkloadCullCase(void)
1605     {
1606     }
1607 
1608 private:
genOccludedGeometry(void) const1609     virtual ObjectData genOccludedGeometry(void) const
1610     {
1611         return ObjectData(Utils::getArithmeticWorkloadShader(), Utils::getFullscreenQuad(0.8f));
1612     }
1613 };
1614 
1615 // Contains dynamicly unused discard after a series of calculations
1616 class FragmentDiscardArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
1617 {
1618 public:
FragmentDiscardArithmeticWorkloadCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1619     FragmentDiscardArithmeticWorkloadCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1620                                               const char *desc)
1621         : FragmentWorkloadCullCase(testCtx, renderCtx, name, desc)
1622     {
1623     }
1624 
~FragmentDiscardArithmeticWorkloadCullCase(void)1625     virtual ~FragmentDiscardArithmeticWorkloadCullCase(void)
1626     {
1627     }
1628 
1629 private:
genOccludedGeometry(void) const1630     virtual ObjectData genOccludedGeometry(void) const
1631     {
1632         return ObjectData(Utils::getArithmeticWorkloadDiscardShader(), Utils::getFullscreenQuad(0.8f));
1633     }
1634 
logDescription(void)1635     virtual void logDescription(void)
1636     {
1637         TestLog &log = m_testCtx.getLog();
1638 
1639         log << TestLog::Section("Description", "Test description");
1640         log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
1641         log << TestLog::Message
1642             << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
1643                "the second (occluded) contains significant fragment shader work and a discard that is never triggers "
1644                "but has a dynamic condition"
1645             << TestLog::EndMessage;
1646         log << TestLog::Message
1647             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1648             << TestLog::EndMessage;
1649         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1650             << TestLog::EndMessage;
1651         log << TestLog::Message
1652             << "Successfull early Z-testing should result in no correlation between workload and render time"
1653             << TestLog::EndMessage;
1654         log << TestLog::EndSection;
1655     }
1656 };
1657 
1658 // Discards fragments from the occluder in a grid pattern
1659 class PartialOccluderDiscardCullCase : public RelativeChangeCase
1660 {
1661 public:
PartialOccluderDiscardCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,int gridsize)1662     PartialOccluderDiscardCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1663                                    const char *desc, int gridsize)
1664         : RelativeChangeCase(testCtx, renderCtx, name, desc)
1665         , m_gridsize(gridsize)
1666     {
1667     }
~PartialOccluderDiscardCullCase(void)1668     virtual ~PartialOccluderDiscardCullCase(void)
1669     {
1670     }
1671 
1672 private:
genOccluderGeometry(void) const1673     virtual ObjectData genOccluderGeometry(void) const
1674     {
1675         return Utils::quadWith(Utils::getGridDiscardShader(m_gridsize), 0.2f);
1676     }
genOccludedGeometry(void) const1677     virtual ObjectData genOccludedGeometry(void) const
1678     {
1679         return Utils::slowQuad(0.8f);
1680     }
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 partially discarded occluder on rendering time"
1688             << TestLog::EndMessage;
1689         log << TestLog::Message
1690             << "Geometry consists of two fullsceen quads. The first (occluding) quad discards half the "
1691                "fragments in a grid pattern, the second (partially occluded) contains significant fragment shader work"
1692             << TestLog::EndMessage;
1693         log << TestLog::Message
1694             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1695             << TestLog::EndMessage;
1696         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1697             << TestLog::EndMessage;
1698         log << TestLog::Message << "Successfull early Z-testing should result in depth testing halving the render time"
1699             << TestLog::EndMessage;
1700         log << TestLog::EndSection;
1701     }
1702 
1703     const int m_gridsize;
1704 };
1705 
1706 // Trivial occluder covering part of screen
1707 class PartialOccluderCullCase : public RelativeChangeCase
1708 {
1709 public:
PartialOccluderCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc,float coverage)1710     PartialOccluderCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc,
1711                             float coverage)
1712         : RelativeChangeCase(testCtx, renderCtx, name, desc)
1713         , m_coverage(coverage)
1714     {
1715     }
~PartialOccluderCullCase(void)1716     ~PartialOccluderCullCase(void)
1717     {
1718     }
1719 
1720 private:
genOccluderGeometry(void) const1721     virtual ObjectData genOccluderGeometry(void) const
1722     {
1723         return ObjectData(Utils::getBaseShader(), Utils::getPartScreenQuad(m_coverage, 0.2f));
1724     }
genOccludedGeometry(void) const1725     virtual ObjectData genOccludedGeometry(void) const
1726     {
1727         return Utils::slowQuad(0.8f);
1728     }
1729 
logDescription(void)1730     virtual void logDescription(void)
1731     {
1732         TestLog &log = m_testCtx.getLog();
1733 
1734         log << TestLog::Section("Description", "Test description");
1735         log << TestLog::Message << "Testing effects of partial occluder on rendering time" << TestLog::EndMessage;
1736         log << TestLog::Message << "Geometry consists of two quads. The first (occluding) quad covers "
1737             << m_coverage * 100.0f
1738             << "% of the screen, while the second (partially occluded, fullscreen) contains significant fragment "
1739                "shader work"
1740             << TestLog::EndMessage;
1741         log << TestLog::Message
1742             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1743             << TestLog::EndMessage;
1744         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1745             << TestLog::EndMessage;
1746         log << TestLog::Message
1747             << "Successfull early Z-testing should result in render time increasing proportionally with unoccluded area"
1748             << TestLog::EndMessage;
1749         log << TestLog::EndSection;
1750     }
1751 
1752     const float m_coverage;
1753 };
1754 
1755 // Constant offset to frag depth in occluder
1756 class StaticOccluderFragDepthCullCase : public RelativeChangeCase
1757 {
1758 public:
StaticOccluderFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1759     StaticOccluderFragDepthCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1760                                     const char *desc)
1761         : RelativeChangeCase(testCtx, renderCtx, name, desc)
1762     {
1763     }
1764 
~StaticOccluderFragDepthCullCase(void)1765     ~StaticOccluderFragDepthCullCase(void)
1766     {
1767     }
1768 
1769 private:
genOccluderGeometry(void) const1770     virtual ObjectData genOccluderGeometry(void) const
1771     {
1772         return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f);
1773     }
genOccludedGeometry(void) const1774     virtual ObjectData genOccludedGeometry(void) const
1775     {
1776         return Utils::slowQuad(0.8f);
1777     }
1778 
logDescription(void)1779     virtual void logDescription(void)
1780     {
1781         TestLog &log = m_testCtx.getLog();
1782 
1783         log << TestLog::Section("Description", "Test description");
1784         log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency"
1785             << TestLog::EndMessage;
1786         log << TestLog::Message
1787             << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second "
1788                "(occluded) contains significant fragment shader work"
1789             << TestLog::EndMessage;
1790         log << TestLog::Message
1791             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1792             << TestLog::EndMessage;
1793         log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth"
1794             << TestLog::EndMessage;
1795         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1796             << TestLog::EndMessage;
1797         log << TestLog::Message
1798             << "Successfull early Z-testing should result in no correlation between workload and render time"
1799             << TestLog::EndMessage;
1800         log << TestLog::EndSection;
1801     }
1802 };
1803 
1804 // Dynamic offset to frag depth in occluder
1805 class DynamicOccluderFragDepthCullCase : public RelativeChangeCase
1806 {
1807 public:
DynamicOccluderFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1808     DynamicOccluderFragDepthCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1809                                      const char *desc)
1810         : RelativeChangeCase(testCtx, renderCtx, name, desc)
1811     {
1812     }
1813 
~DynamicOccluderFragDepthCullCase(void)1814     ~DynamicOccluderFragDepthCullCase(void)
1815     {
1816     }
1817 
1818 private:
genOccluderGeometry(void) const1819     virtual ObjectData genOccluderGeometry(void) const
1820     {
1821         return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f);
1822     }
genOccludedGeometry(void) const1823     virtual ObjectData genOccludedGeometry(void) const
1824     {
1825         return Utils::slowQuad(0.8f);
1826     }
1827 
logDescription(void)1828     virtual void logDescription(void)
1829     {
1830         TestLog &log = m_testCtx.getLog();
1831 
1832         log << TestLog::Section("Description", "Test description");
1833         log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency"
1834             << TestLog::EndMessage;
1835         log << TestLog::Message
1836             << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second "
1837                "(occluded) contains significant fragment shader work"
1838             << TestLog::EndMessage;
1839         log << TestLog::Message
1840             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1841             << TestLog::EndMessage;
1842         log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth"
1843             << TestLog::EndMessage;
1844         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1845             << TestLog::EndMessage;
1846         log << TestLog::Message
1847             << "Successfull early Z-testing should result in no correlation between workload and render time"
1848             << TestLog::EndMessage;
1849         log << TestLog::EndSection;
1850     }
1851 };
1852 
1853 // Constant offset to frag depth in occluded
1854 class StaticOccludedFragDepthCullCase : public RelativeChangeCase
1855 {
1856 public:
StaticOccludedFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1857     StaticOccludedFragDepthCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1858                                     const char *desc)
1859         : RelativeChangeCase(testCtx, renderCtx, name, desc)
1860     {
1861     }
1862 
~StaticOccludedFragDepthCullCase(void)1863     ~StaticOccludedFragDepthCullCase(void)
1864     {
1865     }
1866 
1867 private:
genOccluderGeometry(void) const1868     virtual ObjectData genOccluderGeometry(void) const
1869     {
1870         return Utils::fastQuad(0.2f);
1871     }
genOccludedGeometry(void) const1872     virtual ObjectData genOccludedGeometry(void) const
1873     {
1874         return Utils::quadWith(Utils::getStaticFragDepthArithmeticWorkloadFragmentShader(), 0.2f);
1875     }
1876 
logDescription(void)1877     virtual void logDescription(void)
1878     {
1879         TestLog &log = m_testCtx.getLog();
1880 
1881         log << TestLog::Section("Description", "Test description");
1882         log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
1883         log << TestLog::Message
1884             << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second "
1885                "(occluded) contains significant fragment shader work"
1886             << TestLog::EndMessage;
1887         log << TestLog::Message
1888             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1889             << TestLog::EndMessage;
1890         log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth"
1891             << TestLog::EndMessage;
1892         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1893             << TestLog::EndMessage;
1894         log << TestLog::Message
1895             << "Successfull early Z-testing should result in no correlation between workload and render time"
1896             << TestLog::EndMessage;
1897         log << TestLog::EndSection;
1898     }
1899 };
1900 
1901 // Dynamic offset to frag depth in occluded
1902 class DynamicOccludedFragDepthCullCase : public RelativeChangeCase
1903 {
1904 public:
DynamicOccludedFragDepthCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1905     DynamicOccludedFragDepthCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name,
1906                                      const char *desc)
1907         : RelativeChangeCase(testCtx, renderCtx, name, desc)
1908     {
1909     }
1910 
~DynamicOccludedFragDepthCullCase(void)1911     ~DynamicOccludedFragDepthCullCase(void)
1912     {
1913     }
1914 
1915 private:
genOccluderGeometry(void) const1916     virtual ObjectData genOccluderGeometry(void) const
1917     {
1918         return Utils::fastQuad(0.2f);
1919     }
genOccludedGeometry(void) const1920     virtual ObjectData genOccludedGeometry(void) const
1921     {
1922         return Utils::quadWith(Utils::getDynamicFragDepthArithmeticWorkloadFragmentShader(), 0.2f);
1923     }
1924 
logDescription(void)1925     virtual void logDescription(void)
1926     {
1927         TestLog &log = m_testCtx.getLog();
1928 
1929         log << TestLog::Section("Description", "Test description");
1930         log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
1931         log << TestLog::Message
1932             << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second "
1933                "(occluded) contains significant fragment shader work"
1934             << TestLog::EndMessage;
1935         log << TestLog::Message
1936             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1937             << TestLog::EndMessage;
1938         log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth"
1939             << TestLog::EndMessage;
1940         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1941             << TestLog::EndMessage;
1942         log << TestLog::Message
1943             << "Successfull early Z-testing should result in no correlation between workload and render time"
1944             << TestLog::EndMessage;
1945         log << TestLog::EndSection;
1946     }
1947 };
1948 
1949 // Dynamic offset to frag depth in occluded
1950 class ReversedDepthOrderCullCase : public RelativeChangeCase
1951 {
1952 public:
ReversedDepthOrderCullCase(TestContext & testCtx,const RenderContext & renderCtx,const char * name,const char * desc)1953     ReversedDepthOrderCullCase(TestContext &testCtx, const RenderContext &renderCtx, const char *name, const char *desc)
1954         : RelativeChangeCase(testCtx, renderCtx, name, desc)
1955     {
1956     }
1957 
~ReversedDepthOrderCullCase(void)1958     ~ReversedDepthOrderCullCase(void)
1959     {
1960     }
1961 
1962 private:
genOccluderGeometry(void) const1963     virtual ObjectData genOccluderGeometry(void) const
1964     {
1965         return Utils::fastQuad(0.2f);
1966     }
genOccludedGeometry(void) const1967     virtual ObjectData genOccludedGeometry(void) const
1968     {
1969         return Utils::slowQuad(0.8f);
1970     }
1971 
logDescription(void)1972     virtual void logDescription(void)
1973     {
1974         TestLog &log = m_testCtx.getLog();
1975 
1976         log << TestLog::Section("Description", "Test description");
1977         log << TestLog::Message << "Testing effects of of back first rendering order on culling efficiency"
1978             << TestLog::EndMessage;
1979         log << TestLog::Message
1980             << "Geometry consists of two fullscreen quads. The second (occluding) quad is trivial, while the first "
1981                "(occluded) contains significant fragment shader work"
1982             << TestLog::EndMessage;
1983         log << TestLog::Message
1984             << "Workload indicates the number of iterations of unused work done in the occluded quad's fragment shader"
1985             << TestLog::EndMessage;
1986         log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared"
1987             << TestLog::EndMessage;
1988         log << TestLog::Message
1989             << "Successfull early Z-testing should result in no correlation between workload and render time"
1990             << TestLog::EndMessage;
1991         log << TestLog::EndSection;
1992     }
1993 
1994     // Rendering order of occluder & occluded is reversed, otherwise identical to parent version
renderSample(const RenderData & occluder,const RenderData & occluded,int workload) const1995     Sample renderSample(const RenderData &occluder, const RenderData &occluded, int workload) const
1996     {
1997         const glw::Functions &gl = m_renderCtx.getFunctions();
1998         const GLuint program     = occluded.m_program.getProgram();
1999         Sample sample;
2000         uint64_t now  = 0;
2001         uint64_t prev = 0;
2002         uint8_t buffer[4];
2003 
2004         gl.useProgram(program);
2005         gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
2006 
2007         // Warmup (this workload seems to reduce variation in following workloads)
2008         {
2009             gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2010             gl.disable(GL_DEPTH_TEST);
2011 
2012             gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
2013         }
2014 
2015         // Null time
2016         {
2017             prev = deGetMicroseconds();
2018 
2019             gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2020             gl.disable(GL_DEPTH_TEST);
2021 
2022             gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
2023 
2024             now = deGetMicroseconds();
2025 
2026             sample.nullTime = now - prev;
2027         }
2028 
2029         // Test time
2030         {
2031             prev = deGetMicroseconds();
2032 
2033             gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2034             gl.enable(GL_DEPTH_TEST);
2035 
2036             render(occluded);
2037             render(occluder);
2038 
2039             gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
2040 
2041             now = deGetMicroseconds();
2042 
2043             sample.testTime = now - prev;
2044         }
2045 
2046         // Base time
2047         {
2048             prev = deGetMicroseconds();
2049 
2050             gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2051             gl.disable(GL_DEPTH_TEST);
2052 
2053             render(occluded);
2054             render(occluder);
2055 
2056             gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
2057 
2058             now = deGetMicroseconds();
2059 
2060             sample.baseTime = now - prev;
2061         }
2062 
2063         sample.workload = 0;
2064 
2065         return sample;
2066     }
2067 };
2068 
2069 } // namespace
2070 
DepthTests(Context & context)2071 DepthTests::DepthTests(Context &context) : TestCaseGroup(context, "depth", "Depth culling performance")
2072 {
2073 }
2074 
init(void)2075 void DepthTests::init(void)
2076 {
2077     TestContext &testCtx           = m_context.getTestContext();
2078     const RenderContext &renderCtx = m_context.getRenderContext();
2079 
2080     {
2081         tcu::TestCaseGroup *const cullEfficiencyGroup =
2082             new tcu::TestCaseGroup(m_testCtx, "cull_efficiency", "Fragment cull efficiency");
2083 
2084         addChild(cullEfficiencyGroup);
2085 
2086         {
2087             tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(m_testCtx, "workload", "Workload");
2088 
2089             cullEfficiencyGroup->addChild(group);
2090 
2091             group->addChild(new FragmentTextureWorkloadCullCase(testCtx, renderCtx, "workload_texture",
2092                                                                 "Fragment shader with texture lookup workload"));
2093             group->addChild(new FragmentArithmeticWorkloadCullCase(testCtx, renderCtx, "workload_arithmetic",
2094                                                                    "Fragment shader with arithmetic workload"));
2095             group->addChild(new FragmentDiscardArithmeticWorkloadCullCase(
2096                 testCtx, renderCtx, "workload_arithmetic_discard",
2097                 "Fragment shader that may discard with arithmetic workload"));
2098         }
2099 
2100         {
2101             tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(m_testCtx, "occluder_discard", "Discard");
2102 
2103             cullEfficiencyGroup->addChild(group);
2104 
2105             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_256",
2106                                                                "Parts of occluder geometry discarded", 256));
2107             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_128",
2108                                                                "Parts of occluder geometry discarded", 128));
2109             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_64",
2110                                                                "Parts of occluder geometry discarded", 64));
2111             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_32",
2112                                                                "Parts of occluder geometry discarded", 32));
2113             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_16",
2114                                                                "Parts of occluder geometry discarded", 16));
2115             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_8",
2116                                                                "Parts of occluder geometry discarded", 8));
2117             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_4",
2118                                                                "Parts of occluder geometry discarded", 4));
2119             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_2",
2120                                                                "Parts of occluder geometry discarded", 2));
2121             group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_1",
2122                                                                "Parts of occluder geometry discarded", 1));
2123         }
2124 
2125         {
2126             tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(m_testCtx, "partial_coverage", "Partial Coverage");
2127 
2128             cullEfficiencyGroup->addChild(group);
2129 
2130             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "100",
2131                                                         "Occluder covering only part of occluded geometry", 1.00f));
2132             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "099",
2133                                                         "Occluder covering only part of occluded geometry", 0.99f));
2134             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "095",
2135                                                         "Occluder covering only part of occluded geometry", 0.95f));
2136             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "090",
2137                                                         "Occluder covering only part of occluded geometry", 0.90f));
2138             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "080",
2139                                                         "Occluder covering only part of occluded geometry", 0.80f));
2140             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "070",
2141                                                         "Occluder covering only part of occluded geometry", 0.70f));
2142             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "050",
2143                                                         "Occluder covering only part of occluded geometry", 0.50f));
2144             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "025",
2145                                                         "Occluder covering only part of occluded geometry", 0.25f));
2146             group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "010",
2147                                                         "Occluder covering only part of occluded geometry", 0.10f));
2148         }
2149 
2150         {
2151             tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Partial Coverage");
2152 
2153             cullEfficiencyGroup->addChild(group);
2154 
2155             group->addChild(new StaticOccluderFragDepthCullCase(testCtx, renderCtx, "occluder_static", ""));
2156             group->addChild(new DynamicOccluderFragDepthCullCase(testCtx, renderCtx, "occluder_dynamic", ""));
2157             group->addChild(new StaticOccludedFragDepthCullCase(testCtx, renderCtx, "occluded_static", ""));
2158             group->addChild(new DynamicOccludedFragDepthCullCase(testCtx, renderCtx, "occluded_dynamic", ""));
2159         }
2160 
2161         {
2162             tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(m_testCtx, "order", "Rendering order");
2163 
2164             cullEfficiencyGroup->addChild(group);
2165 
2166             group->addChild(
2167                 new ReversedDepthOrderCullCase(testCtx, renderCtx, "reversed", "Back to front rendering order"));
2168         }
2169     }
2170 
2171     {
2172         tcu::TestCaseGroup *const testCostGroup =
2173             new tcu::TestCaseGroup(m_testCtx, "culled_pixel_cost", "Fragment cull efficiency");
2174 
2175         addChild(testCostGroup);
2176 
2177         {
2178             tcu::TestCaseGroup *const group =
2179                 new tcu::TestCaseGroup(m_testCtx, "gradient", "Gradients with small depth differences");
2180 
2181             testCostGroup->addChild(group);
2182 
2183             group->addChild(new BaseCostCase(testCtx, renderCtx, "flat", ""));
2184             group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_050", "", 0.50f));
2185             group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_010", "", 0.10f));
2186             group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_005", "", 0.05f));
2187             group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_002", "", 0.02f));
2188             group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_001", "", 0.01f));
2189         }
2190 
2191         {
2192             tcu::TestCaseGroup *const group =
2193                 new tcu::TestCaseGroup(m_testCtx, "occluder_geometry", "Occluders with varying geometry complexity");
2194 
2195             testCostGroup->addChild(group);
2196 
2197             group->addChild(
2198                 new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_5", "", 5, 0.0f, 0.0f));
2199             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_15", "", 15,
2200                                                                     0.0f, 0.0f));
2201             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_25", "", 25,
2202                                                                     0.0f, 0.0f));
2203             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_50", "", 50,
2204                                                                     0.0f, 0.0f));
2205             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_100", "",
2206                                                                     100, 0.0f, 0.0f));
2207 
2208             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_5", "", 5,
2209                                                                     1.0f / 5.0f, 0.0f));
2210             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_15", "", 15,
2211                                                                     1.0f / 15.0f, 0.0f));
2212             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_25", "", 25,
2213                                                                     1.0f / 25.0f, 0.0f));
2214             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_50", "", 50,
2215                                                                     1.0f / 50.0f, 0.0f));
2216             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_100", "", 100,
2217                                                                     1.0f / 100.0f, 0.0f));
2218 
2219             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_5", "", 5,
2220                                                                     0.0f, 0.2f));
2221             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_15", "",
2222                                                                     15, 0.0f, 0.2f));
2223             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_25", "",
2224                                                                     25, 0.0f, 0.2f));
2225             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_50", "",
2226                                                                     50, 0.0f, 0.2f));
2227             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_100", "",
2228                                                                     100, 0.0f, 0.2f));
2229 
2230             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_5", "", 5,
2231                                                                     1.0f / 5.0f, 0.2f));
2232             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_15", "", 15,
2233                                                                     1.0f / 15.0f, 0.2f));
2234             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_25", "", 25,
2235                                                                     1.0f / 25.0f, 0.2f));
2236             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_50", "", 50,
2237                                                                     1.0f / 50.0f, 0.2f));
2238             group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_100", "",
2239                                                                     100, 1.0f / 100.0f, 0.2f));
2240         }
2241 
2242         {
2243             tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Modifying gl_FragDepth");
2244 
2245             testCostGroup->addChild(group);
2246 
2247             group->addChild(new OccluderStaticFragDepthCostCase(testCtx, renderCtx, "occluder_static", ""));
2248             group->addChild(new OccluderDynamicFragDepthCostCase(testCtx, renderCtx, "occluder_dynamic", ""));
2249             group->addChild(new OccludedStaticFragDepthCostCase(testCtx, renderCtx, "occluded_static", ""));
2250             group->addChild(new OccludedDynamicFragDepthCostCase(testCtx, renderCtx, "occluded_dynamic", ""));
2251         }
2252     }
2253 }
2254 
2255 } // namespace Performance
2256 } // namespace gles3
2257 } // namespace deqp
2258