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