1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Depth buffer performance tests.
22 *//*--------------------------------------------------------------------*/
24 #include "es3pDepthTests.hpp"
26 #include "glsCalibration.hpp"
28 #include "gluShaderProgram.hpp"
29 #include "gluObjectWrapper.hpp"
30 #include "gluPixelTransfer.hpp"
32 #include "glwFunctions.hpp"
33 #include "glwEnums.hpp"
35 #include "tcuTestLog.hpp"
36 #include "tcuStringTemplate.hpp"
37 #include "tcuCPUWarmup.hpp"
38 #include "tcuCommandLine.hpp"
39 #include "tcuResultCollector.hpp"
44 #include "deStringUtil.hpp"
45 #include "deRandom.hpp"
46 #include "deUniquePtr.hpp"
61 using tcu::TestContext;
66 using glu::RenderContext;
67 using glu::ProgramSources;
68 using glu::ShaderSource;
87 SampleParams(int step_, int measurement_) : step(step_), measurement(measurement_) {}
90 typedef vector<float> Geometry;
94 ProgramSources shader;
97 ObjectData (const ProgramSources& shader_, const Geometry& geometry_) : shader(shader_), geometry(geometry_) {}
103 RenderData (const ObjectData& object, const glu::RenderContext& renderCtx, TestLog& log);
104 ~RenderData (void) {};
106 const glu::ShaderProgram m_program;
107 const glu::VertexArray m_vao;
108 const glu::Buffer m_vbo;
110 const int m_numVertices;
113 RenderData::RenderData (const ObjectData& object, const glu::RenderContext& renderCtx, TestLog& log)
114 : m_program (renderCtx, object.shader)
115 , m_vao (renderCtx.getFunctions())
116 , m_vbo (renderCtx.getFunctions())
117 , m_numVertices (int(object.geometry.size())/4)
119 const glw::Functions& gl = renderCtx.getFunctions();
121 if (!m_program.isOk())
124 gl.bindBuffer(GL_ARRAY_BUFFER, *m_vbo);
125 gl.bufferData(GL_ARRAY_BUFFER, object.geometry.size() * sizeof(float), &object.geometry[0], GL_STATIC_DRAW);
126 gl.bindAttribLocation(m_program.getProgram(), 0, "a_position");
128 gl.bindVertexArray(*m_vao);
129 gl.vertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
130 gl.enableVertexAttribArray(0);
131 gl.bindVertexArray(0);
136 vector<float> getFullscreenQuad (float depth)
140 +1.0f, +1.0f, depth, 0.0f, // .w is gl_VertexId%3 since Nexus 4&5 can't handle that on their own
141 +1.0f, -1.0f, depth, 1.0f,
142 -1.0f, -1.0f, depth, 2.0f,
143 -1.0f, -1.0f, depth, 0.0f,
144 -1.0f, +1.0f, depth, 1.0f,
145 +1.0f, +1.0f, depth, 2.0f,
148 return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
151 vector<float> getFullscreenQuadWithGradient (float depth0, float depth1)
155 +1.0f, +1.0f, depth0, 0.0f,
156 +1.0f, -1.0f, depth0, 1.0f,
157 -1.0f, -1.0f, depth1, 2.0f,
158 -1.0f, -1.0f, depth1, 0.0f,
159 -1.0f, +1.0f, depth1, 1.0f,
160 +1.0f, +1.0f, depth0, 2.0f,
163 return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
166 vector<float> getPartScreenQuad (float coverage, float depth)
168 const float xMax = -1.0f + 2.0f*coverage;
171 xMax, +1.0f, depth, 0.0f,
172 xMax, -1.0f, depth, 1.0f,
173 -1.0f, -1.0f, depth, 2.0f,
174 -1.0f, -1.0f, depth, 0.0f,
175 -1.0f, +1.0f, depth, 1.0f,
176 xMax, +1.0f, depth, 2.0f,
179 return vector<float>(DE_ARRAY_BEGIN(data), DE_ARRAY_END(data));
182 // Axis aligned grid. Depth of vertices is baseDepth +/- depthNoise
183 vector<float> getFullScreenGrid (int resolution, deUint32 seed, float baseDepth, float depthNoise, float xyNoise)
185 const int gridsize = resolution+1;
186 vector<Vec3> vertices (gridsize*gridsize);
187 vector<float> retval;
188 de::Random rng (seed);
190 for (int y = 0; y < gridsize; y++)
191 for (int x = 0; x < gridsize; x++)
193 const bool isEdge = x == 0 || y == 0 || x == resolution || y == resolution;
194 const float x_ = float(x)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
195 const float y_ = float(y)/float(resolution)*2.0f - 1.0f + (isEdge ? 0.0f : rng.getFloat(-xyNoise, +xyNoise));
196 const float z_ = baseDepth + rng.getFloat(-depthNoise, +depthNoise);
198 vertices[y*gridsize + x] = Vec3(x_, y_, z_);
201 retval.reserve(resolution*resolution*6);
203 for (int y = 0; y < resolution; y++)
204 for (int x = 0; x < resolution; x++)
206 const Vec3& p0 = vertices[(y+0)*gridsize + (x+0)];
207 const Vec3& p1 = vertices[(y+0)*gridsize + (x+1)];
208 const Vec3& p2 = vertices[(y+1)*gridsize + (x+0)];
209 const Vec3& p3 = vertices[(y+1)*gridsize + (x+1)];
211 const float temp[6*4] =
213 p0.x(), p0.y(), p0.z(), 0.0f,
214 p2.x(), p2.y(), p2.z(), 1.0f,
215 p1.x(), p1.y(), p1.z(), 2.0f,
217 p3.x(), p3.y(), p3.z(), 0.0f,
218 p1.x(), p1.y(), p1.z(), 1.0f,
219 p2.x(), p2.y(), p2.z(), 2.0f,
222 retval.insert(retval.end(), DE_ARRAY_BEGIN(temp), DE_ARRAY_END(temp));
228 // Outputs barycentric coordinates as v_bcoords. Otherwise a passthrough shader
229 string getBaseVertexShader (void)
231 return "#version 300 es\n"
232 "in highp vec4 a_position;\n"
233 "out mediump vec3 v_bcoords;\n"
236 " v_bcoords = vec3(0, 0, 0);\n"
237 " v_bcoords[int(a_position.w)] = 1.0;\n"
238 " gl_Position = vec4(a_position.xyz, 1.0);\n"
242 // Adds noise to coordinates based on InstanceID Outputs barycentric coordinates as v_bcoords
243 string getInstanceNoiseVertexShader (void)
245 return "#version 300 es\n"
246 "in highp vec4 a_position;\n"
247 "out mediump vec3 v_bcoords;\n"
250 " v_bcoords = vec3(0, 0, 0);\n"
251 " v_bcoords[int(a_position.w)] = 1.0;\n"
252 " vec3 noise = vec3(sin(float(gl_InstanceID)*1.05), sin(float(gl_InstanceID)*1.23), sin(float(gl_InstanceID)*1.71));\n"
253 " gl_Position = vec4(a_position.xyz + noise * 0.005, 1.0);\n"
257 // Renders green triangles with edges highlighted. Exact shade depends on depth.
258 string getDepthAsGreenFragmentShader (void)
260 return "#version 300 es\n"
261 "in mediump vec3 v_bcoords;\n"
262 "out mediump vec4 fragColor;\n"
265 " mediump float d = gl_FragCoord.z;\n"
266 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
267 " fragColor = vec4(d,1,d,1);\n"
269 " fragColor = vec4(0,d,0,1);\n"
273 // Renders green triangles with edges highlighted. Exact shade depends on depth.
274 string getDepthAsRedFragmentShader (void)
276 return "#version 300 es\n"
277 "in mediump vec3 v_bcoords;\n"
278 "out mediump vec4 fragColor;\n"
281 " mediump float d = gl_FragCoord.z;\n"
282 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
283 " fragColor = vec4(1,d,d,1);\n"
285 " fragColor = vec4(d,0,0,1);\n"
289 // Basic time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
290 string getArithmeticWorkloadFragmentShader (void)
293 return "#version 300 es\n"
294 "in mediump vec3 v_bcoords;\n"
295 "out mediump vec4 fragColor;\n"
296 "uniform mediump int u_iterations;\n"
299 " mediump float d = gl_FragCoord.z;\n"
300 " for (int i = 0; i<u_iterations; i++)\n"
301 // cos(a)^2 + sin(a)^2 == 1. since d is in range [0,1] this will lose a few ULP's of precision per iteration but should not significantly change the value of d without extreme iteration counts
302 " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
303 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
304 " fragColor = vec4(1,d,d,1);\n"
306 " fragColor = vec4(d,0,0,1);\n"
310 // Arithmetic workload shader but contains discard
311 string getArithmeticWorkloadDiscardFragmentShader (void)
313 return "#version 300 es\n"
314 "in mediump vec3 v_bcoords;\n"
315 "out mediump vec4 fragColor;\n"
316 "uniform mediump int u_iterations;\n"
319 " mediump float d = gl_FragCoord.z;\n"
320 " for (int i = 0; i<u_iterations; i++)\n"
321 " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
322 " if (d < 0.5) discard;\n"
323 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
324 " fragColor = vec4(1,d,d,1);\n"
326 " fragColor = vec4(d,0,0,1);\n"
330 // Texture fetch based time waster. Renders red triangles with edges highlighted. Exact shade depends on depth.
331 string getTextureWorkloadFragmentShader (void)
333 return "#version 300 es\n"
334 "in mediump vec3 v_bcoords;\n"
335 "out mediump vec4 fragColor;\n"
336 "uniform mediump int u_iterations;\n"
337 "uniform sampler2D u_texture;\n"
340 " mediump float d = gl_FragCoord.z;\n"
341 " for (int i = 0; i<u_iterations; i++)\n"
342 " d *= texture(u_texture, (gl_FragCoord.xy+vec2(i))/512.0).r;\n" // Texture is expected to be fully white
343 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
344 " fragColor = vec4(1,1,1,1);\n"
346 " fragColor = vec4(d,0,0,1);\n"
350 // Discard fragments in a grid pattern
351 string getGridDiscardFragmentShader (int gridsize)
353 const string fragSrc = "#version 300 es\n"
354 "in mediump vec3 v_bcoords;\n"
355 "out mediump vec4 fragColor;\n"
358 " mediump float d = gl_FragCoord.z;\n"
359 " if ((int(gl_FragCoord.x)/${GRIDRENDER_SIZE} + int(gl_FragCoord.y)/${GRIDRENDER_SIZE})%2 == 0)\n"
361 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
362 " fragColor = vec4(d,1,d,1);\n"
364 " fragColor = vec4(0,d,0,1);\n"
366 map<string, string> params;
368 params["GRIDRENDER_SIZE"] = de::toString(gridsize);
370 return tcu::StringTemplate(fragSrc).specialize(params);
373 // A static increment to frag depth
374 string getStaticFragDepthFragmentShader (void)
376 return "#version 300 es\n"
377 "in mediump vec3 v_bcoords;\n"
378 "out mediump vec4 fragColor;\n"
381 " mediump float d = gl_FragCoord.z;\n"
382 " gl_FragDepth = gl_FragCoord.z + 0.1;\n"
383 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
384 " fragColor = vec4(d,1,d,1);\n"
386 " fragColor = vec4(0,d,0,1);\n"
390 // A trivial dynamic change to frag depth
391 string getDynamicFragDepthFragmentShader (void)
393 return "#version 300 es\n"
394 "in mediump vec3 v_bcoords;\n"
395 "out mediump vec4 fragColor;\n"
398 " mediump float d = gl_FragCoord.z;\n"
399 " gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1
400 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
401 " fragColor = vec4(d,1,d,1);\n"
403 " fragColor = vec4(0,d,0,1);\n"
407 // A static increment to frag depth
408 string getStaticFragDepthArithmeticWorkloadFragmentShader (void)
410 return "#version 300 es\n"
411 "in mediump vec3 v_bcoords;\n"
412 "out mediump vec4 fragColor;\n"
413 "uniform mediump int u_iterations;\n"
416 " mediump float d = gl_FragCoord.z;\n"
417 " gl_FragDepth = gl_FragCoord.z + 0.1;\n"
418 " for (int i = 0; i<u_iterations; i++)\n"
419 " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
420 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
421 " fragColor = vec4(1,d,d,1);\n"
423 " fragColor = vec4(d,0,0,1);\n"
427 // A trivial dynamic change to frag depth
428 string getDynamicFragDepthArithmeticWorkloadFragmentShader (void)
430 return "#version 300 es\n"
431 "in mediump vec3 v_bcoords;\n"
432 "out mediump vec4 fragColor;\n"
433 "uniform mediump int u_iterations;\n"
436 " mediump float d = gl_FragCoord.z;\n"
437 " gl_FragDepth = gl_FragCoord.z + (v_bcoords.x + v_bcoords.y + v_bcoords.z)*0.05;\n" // Sum of v_bcoords components is allways 1
438 " for (int i = 0; i<u_iterations; i++)\n"
439 " d = d*sin(d)*sin(d) + d*cos(d)*cos(d);\n"
440 " if (v_bcoords.x < 0.02 || v_bcoords.y < 0.02 || v_bcoords.z < 0.02)\n"
441 " fragColor = vec4(1,d,d,1);\n"
443 " fragColor = vec4(d,0,0,1);\n"
447 glu::ProgramSources getBaseShader (void)
449 return glu::makeVtxFragSources(getBaseVertexShader(), getDepthAsGreenFragmentShader());
452 glu::ProgramSources getArithmeticWorkloadShader (void)
454 return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadFragmentShader());
457 glu::ProgramSources getArithmeticWorkloadDiscardShader (void)
459 return glu::makeVtxFragSources(getBaseVertexShader(), getArithmeticWorkloadDiscardFragmentShader());
462 glu::ProgramSources getTextureWorkloadShader (void)
464 return glu::makeVtxFragSources(getBaseVertexShader(), getTextureWorkloadFragmentShader());
467 glu::ProgramSources getGridDiscardShader (int gridsize)
469 return glu::makeVtxFragSources(getBaseVertexShader(), getGridDiscardFragmentShader(gridsize));
472 inline ObjectData quadWith (const glu::ProgramSources& shader, float depth)
474 return ObjectData(shader, getFullscreenQuad(depth));
477 inline ObjectData quadWith (const string& fragShader, float depth)
479 return ObjectData(glu::makeVtxFragSources(getBaseVertexShader(), fragShader), getFullscreenQuad(depth));
482 inline ObjectData variableQuad (float depth)
484 return ObjectData(glu::makeVtxFragSources(getInstanceNoiseVertexShader(), getDepthAsRedFragmentShader()), getFullscreenQuad(depth));
487 inline ObjectData fastQuad (float depth)
489 return ObjectData(getBaseShader(), getFullscreenQuad(depth));
492 inline ObjectData slowQuad (float depth)
494 return ObjectData(getArithmeticWorkloadShader(), getFullscreenQuad(depth));
497 inline ObjectData fastQuadWithGradient (float depth0, float depth1)
499 return ObjectData(getBaseShader(), getFullscreenQuadWithGradient(depth0, depth1));
504 class BaseCase : public tcu::TestCase
507 enum {RENDER_SIZE = 512};
509 BaseCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
510 virtual ~BaseCase (void) {}
512 virtual IterateResult iterate (void);
515 void logSamples (const vector<Sample>& samples, const string& name, const string& desc);
516 void logGeometry (const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg);
517 virtual void logAnalysis (const vector<Sample>& samples) = 0;
518 virtual void logDescription (void) = 0;
520 virtual ObjectData genOccluderGeometry (void) const = 0;
521 virtual ObjectData genOccludedGeometry (void) const = 0;
523 virtual int calibrate (void) const = 0;
524 virtual Sample renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const = 0;
526 void render (const RenderData& data) const;
527 void render (const RenderData& data, int instances) const;
529 const RenderContext& m_renderCtx;
530 tcu::ResultCollector m_results;
532 enum {ITERATION_STEPS = 10, ITERATION_SAMPLES = 16};
535 BaseCase::BaseCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
536 : TestCase (testCtx, tcu::NODETYPE_PERFORMANCE, name, desc)
537 , m_renderCtx (renderCtx)
541 BaseCase::IterateResult BaseCase::iterate (void)
543 typedef de::MovePtr<RenderData> RenderDataP;
545 const glw::Functions& gl = m_renderCtx.getFunctions();
546 TestLog& log = m_testCtx.getLog();
548 const glu::Framebuffer framebuffer (gl);
549 const glu::Renderbuffer renderbuffer (gl);
550 const glu::Renderbuffer depthbuffer (gl);
552 vector<Sample> results;
554 RenderDataP occluderData;
555 RenderDataP occludedData;
556 tcu::TextureLevel resultTex (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), RENDER_SIZE, RENDER_SIZE);
558 de::Random rng (deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed());
562 gl.bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer);
563 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE);
564 gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuffer);
565 gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, RENDER_SIZE, RENDER_SIZE);
567 gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
568 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *renderbuffer);
569 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *depthbuffer);
570 gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
571 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
573 maxWorkload = calibrate();
576 occluderData = RenderDataP(new RenderData (genOccluderGeometry(), m_renderCtx, log));
577 occludedData = RenderDataP(new RenderData (genOccludedGeometry(), m_renderCtx, log));
579 TCU_CHECK(occluderData->m_program.isOk());
580 TCU_CHECK(occludedData->m_program.isOk());
582 // Force initialization of GPU resources
583 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
584 gl.enable(GL_DEPTH_TEST);
586 render(*occluderData);
587 render(*occludedData);
588 glu::readPixels(m_renderCtx, 0, 0, resultTex.getAccess());
590 logGeometry(resultTex.getAccess(), occluderData->m_program, occludedData->m_program);
592 params.reserve(ITERATION_STEPS*ITERATION_SAMPLES);
595 for (int step = 0; step < ITERATION_STEPS; step++)
597 const int workload = maxWorkload*step/ITERATION_STEPS;
599 for (int count = 0; count < ITERATION_SAMPLES; count++)
600 params.push_back(workload);
603 rng.shuffle(params.begin(), params.end());
606 for (size_t ndx = 0; ndx < params.size(); ndx++)
608 const int workload = params[ndx];
609 Sample sample = renderSample(*occluderData, *occludedData, workload);
611 sample.workload = workload;
612 sample.order = int(ndx);
614 results.push_back(sample);
617 logSamples(results, "Samples", "Samples");
618 logAnalysis(results);
620 m_results.setTestContextResult(m_testCtx);
625 void BaseCase::logSamples (const vector<Sample>& samples, const string& name, const string& desc)
627 TestLog& log = m_testCtx.getLog();
629 bool testOnly = true;
631 for (size_t ndx = 0; ndx < samples.size(); ndx++)
633 if (samples[ndx].baseTime != 0 || samples[ndx].nullTime != 0)
640 log << TestLog::SampleList(name, desc);
644 log << TestLog::SampleInfo
645 << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
646 << TestLog::ValueInfo("Order", "Order of sample", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
647 << TestLog::ValueInfo("TestTime", "Test render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
648 << TestLog::EndSampleInfo;
650 for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
652 const Sample& sample = samples[sampleNdx];
654 log << TestLog::Sample << sample.workload << sample.order << sample.testTime << TestLog::EndSample;
659 log << TestLog::SampleInfo
660 << TestLog::ValueInfo("Workload", "Workload", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
661 << TestLog::ValueInfo("Order", "Order of sample", "", QP_SAMPLE_VALUE_TAG_PREDICTOR)
662 << TestLog::ValueInfo("TestTime", "Test render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
663 << TestLog::ValueInfo("NullTime", "Read pixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
664 << TestLog::ValueInfo("BaseTime", "Base render time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
665 << TestLog::EndSampleInfo;
667 for (size_t sampleNdx = 0; sampleNdx < samples.size(); sampleNdx++)
669 const Sample& sample = samples[sampleNdx];
671 log << TestLog::Sample << sample.workload << sample.order << sample.testTime << sample.nullTime << sample.baseTime << TestLog::EndSample;
675 log << TestLog::EndSampleList;
678 void BaseCase::logGeometry (const tcu::ConstPixelBufferAccess& sample, const glu::ShaderProgram& occluderProg, const glu::ShaderProgram& occludedProg)
680 TestLog& log = m_testCtx.getLog();
682 log << TestLog::Section("Geometry", "Geometry");
683 log << TestLog::Message << "Occluding geometry is green with shade dependent on depth (rgb == 0, depth, 0)" << TestLog::EndMessage;
684 log << TestLog::Message << "Occluded geometry is red with shade dependent on depth (rgb == depth, 0, 0)" << TestLog::EndMessage;
685 log << TestLog::Message << "Primitive edges are a lighter shade of red/green" << TestLog::EndMessage;
687 log << TestLog::Image("Test Geometry", "Test Geometry", sample);
688 log << TestLog::EndSection;
690 log << TestLog::Section("Occluder", "Occluder");
692 log << TestLog::EndSection;
694 log << TestLog::Section("Occluded", "Occluded");
696 log << TestLog::EndSection;
699 void BaseCase::render (const RenderData& data) const
701 const glw::Functions& gl = m_renderCtx.getFunctions();
703 gl.useProgram(data.m_program.getProgram());
705 gl.bindVertexArray(*data.m_vao);
706 gl.drawArrays(GL_TRIANGLES, 0, data.m_numVertices);
707 gl.bindVertexArray(0);
710 void BaseCase::render (const RenderData& data, int instances) const
712 const glw::Functions& gl = m_renderCtx.getFunctions();
714 gl.useProgram(data.m_program.getProgram());
716 gl.bindVertexArray(*data.m_vao);
717 gl.drawArraysInstanced(GL_TRIANGLES, 0, data.m_numVertices, instances);
718 gl.bindVertexArray(0);
721 // Render occluder once, then repeatedly render occluded geometry. Sample with multiple repetition counts & establish time per call with linear regression
722 class RenderCountCase : public BaseCase
725 RenderCountCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
726 ~RenderCountCase (void) {}
729 virtual void logAnalysis (const vector<Sample>& samples);
732 virtual int calibrate (void) const;
733 virtual Sample renderSample (const RenderData& occluder, const RenderData& occluded, int callcount) const;
736 RenderCountCase::RenderCountCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
737 : BaseCase (testCtx, renderCtx, name, desc)
741 void RenderCountCase::logAnalysis (const vector<Sample>& samples)
745 TestLog& log = m_testCtx.getLog();
747 vector<Vec2> testSamples (samples.size());
749 for (size_t ndx = 0; ndx < samples.size(); ndx++)
751 const Sample& sample = samples[ndx];
753 testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
755 maxWorkload = de::max(maxWorkload, sample.workload);
759 const float confidence = 0.60f;
760 const LineParametersWithConfidence testParam = theilSenSiegelLinearRegression(testSamples, confidence);
761 const float usPerCall = testParam.coefficient;
762 const float pxPerCall = RENDER_SIZE*RENDER_SIZE;
763 const float pxPerUs = pxPerCall/usPerCall;
764 const float mpxPerS = pxPerUs;
766 log << TestLog::Section("Linear Regression", "Linear Regression");
767 log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage;
768 log << TestLog::Message << "Render time for scene with depth test was\n\t"
769 << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset << ", " << testParam.offsetConfidenceUpper << "]us +"
770 << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]"
771 << "us/workload" << TestLog::EndMessage;
772 log << TestLog::EndSection;
774 log << TestLog::Section("Result", "Result");
776 if (testParam.coefficientConfidenceLower < 0.0f)
778 log << TestLog::Message << "Coefficient confidence bounds include values below 0.0, the operation likely has neglible per-pixel cost" << TestLog::EndMessage;
779 m_results.addResult(QP_TEST_RESULT_PASS, "Pass");
781 else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25)
783 log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage;
784 m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
788 log << TestLog::Message << "Culled hidden pixels @ " << mpxPerS << "Mpx/s" << TestLog::EndMessage;
789 m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(mpxPerS, 2));
792 log << TestLog::EndSection;
796 Sample RenderCountCase::renderSample (const RenderData& occluder, const RenderData& occluded, int callcount) const
798 const glw::Functions& gl = m_renderCtx.getFunctions();
806 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
807 gl.enable(GL_DEPTH_TEST);
808 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
811 prev = deGetMicroseconds();
813 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
814 gl.enable(GL_DEPTH_TEST);
817 render(occluded, callcount);
819 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
821 now = deGetMicroseconds();
823 sample.testTime = now - prev;
826 sample.workload = callcount;
831 int RenderCountCase::calibrate (void) const
835 const glw::Functions& gl = m_renderCtx.getFunctions();
836 TestLog& log = m_testCtx.getLog();
838 const RenderData occluderGeometry (genOccluderGeometry(), m_renderCtx, log);
839 const RenderData occludedGeometry (genOccludedGeometry(), m_renderCtx, log);
841 TheilSenCalibrator calibrator (CalibratorParameters(20, // Initial workload
842 10, // Max iteration frames
843 20.0f, // Iteration shortcut threshold ms
844 20, // Max iterations
845 33.0f, // Target frame time
846 40.0f, // Frame time cap
847 1000.0f // Target measurement duration
852 switch(calibrator.getState())
854 case TheilSenCalibrator::STATE_FINISHED:
855 logCalibrationInfo(m_testCtx.getLog(), calibrator);
856 return calibrator.getCallCount();
858 case TheilSenCalibrator::STATE_MEASURE:
864 prev = deGetMicroseconds();
866 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
867 gl.disable(GL_DEPTH_TEST);
869 render(occluderGeometry);
870 render(occludedGeometry, calibrator.getCallCount());
872 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
874 now = deGetMicroseconds();
876 calibrator.recordIteration(now - prev);
880 case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
881 calibrator.recomputeParameters();
890 // Compares time/workload gradients of same geometry with and without depth testing
891 class RelativeChangeCase : public BaseCase
894 RelativeChangeCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
895 virtual ~RelativeChangeCase (void) {}
898 Sample renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const;
900 virtual void logAnalysis (const vector<Sample>& samples);
903 int calibrate (void) const;
906 RelativeChangeCase::RelativeChangeCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
907 : BaseCase (testCtx, renderCtx, name, desc)
911 int RelativeChangeCase::calibrate (void) const
915 const glw::Functions& gl = m_renderCtx.getFunctions();
916 TestLog& log = m_testCtx.getLog();
918 const RenderData geom (genOccludedGeometry(), m_renderCtx, log);
920 TheilSenCalibrator calibrator(CalibratorParameters( 20, // Initial workload
921 10, // Max iteration frames
922 20.0f, // Iteration shortcut threshold ms
923 20, // Max iterations
924 33.0f, // Target frame time
925 40.0f, // Frame time cap
926 1000.0f // Target measurement duration
931 switch(calibrator.getState())
933 case TheilSenCalibrator::STATE_FINISHED:
934 logCalibrationInfo(m_testCtx.getLog(), calibrator);
935 return calibrator.getCallCount();
937 case TheilSenCalibrator::STATE_MEASURE:
940 const GLuint program = geom.m_program.getProgram();
942 gl.useProgram(program);
943 gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), calibrator.getCallCount());
945 const deInt64 prev = deGetMicroseconds();
947 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
948 gl.disable(GL_DEPTH_TEST);
952 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
954 const deInt64 now = deGetMicroseconds();
956 calibrator.recordIteration(now - prev);
960 case TheilSenCalibrator::STATE_RECOMPUTE_PARAMS:
961 calibrator.recomputeParameters();
970 Sample RelativeChangeCase::renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const
972 const glw::Functions& gl = m_renderCtx.getFunctions();
973 const GLuint program = occluded.m_program.getProgram();
979 gl.useProgram(program);
980 gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
982 // Warmup (this workload seems to reduce variation in following workloads)
984 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
985 gl.disable(GL_DEPTH_TEST);
987 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
992 prev = deGetMicroseconds();
994 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
995 gl.disable(GL_DEPTH_TEST);
997 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
999 now = deGetMicroseconds();
1001 sample.nullTime = now - prev;
1006 prev = deGetMicroseconds();
1008 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1009 gl.enable(GL_DEPTH_TEST);
1014 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1016 now = deGetMicroseconds();
1018 sample.testTime = now - prev;
1023 prev = deGetMicroseconds();
1025 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1026 gl.disable(GL_DEPTH_TEST);
1031 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1033 now = deGetMicroseconds();
1035 sample.baseTime = now - prev;
1038 sample.workload = 0;
1043 void RelativeChangeCase::logAnalysis (const vector<Sample>& samples)
1045 using namespace gls;
1047 TestLog& log = m_testCtx.getLog();
1049 int maxWorkload = 0;
1051 vector<Vec2> nullSamples (samples.size());
1052 vector<Vec2> baseSamples (samples.size());
1053 vector<Vec2> testSamples (samples.size());
1055 for (size_t ndx = 0; ndx < samples.size(); ndx++)
1057 const Sample& sample = samples[ndx];
1059 nullSamples[ndx] = Vec2((float)sample.workload, (float)sample.nullTime);
1060 baseSamples[ndx] = Vec2((float)sample.workload, (float)sample.baseTime);
1061 testSamples[ndx] = Vec2((float)sample.workload, (float)sample.testTime);
1063 maxWorkload = de::max(maxWorkload, sample.workload);
1067 const float confidence = 0.60f;
1069 const LineParametersWithConfidence nullParam = theilSenSiegelLinearRegression(nullSamples, confidence);
1070 const LineParametersWithConfidence baseParam = theilSenSiegelLinearRegression(baseSamples, confidence);
1071 const LineParametersWithConfidence testParam = theilSenSiegelLinearRegression(testSamples, confidence);
1073 if (!de::inRange(0.0f, nullParam.coefficientConfidenceLower, nullParam.coefficientConfidenceUpper))
1075 m_results.addResult(QP_TEST_RESULT_FAIL, "Constant operation sequence duration not constant");
1076 log << TestLog::Message << "Constant operation sequence timing may vary as a function of workload. Result quality extremely low" << TestLog::EndMessage;
1079 if (de::inRange(0.0f, baseParam.coefficientConfidenceLower, baseParam.coefficientConfidenceUpper))
1081 m_results.addResult(QP_TEST_RESULT_FAIL, "Workload has no effect on duration");
1082 log << TestLog::Message << "Workload factor has no effect on duration of sample (smart optimizer?)" << TestLog::EndMessage;
1085 log << TestLog::Section("Linear Regression", "Linear Regression");
1086 log << TestLog::Message << "Offset & coefficient presented as [confidence interval min, estimate, confidence interval max]. Reported confidence interval for this test is " << confidence << TestLog::EndMessage;
1088 log << TestLog::Message << "Render time for empty scene was\n\t"
1089 << "[" << nullParam.offsetConfidenceLower << ", " << nullParam.offset << ", " << nullParam.offsetConfidenceUpper << "]us +"
1090 << "[" << nullParam.coefficientConfidenceLower << ", " << nullParam.coefficient << ", " << nullParam.coefficientConfidenceUpper << "]"
1091 << "us/workload" << TestLog::EndMessage;
1093 log << TestLog::Message << "Render time for scene without depth test was\n\t"
1094 << "[" << baseParam.offsetConfidenceLower << ", " << baseParam.offset << ", " << baseParam.offsetConfidenceUpper << "]us +"
1095 << "[" << baseParam.coefficientConfidenceLower << ", " << baseParam.coefficient << ", " << baseParam.coefficientConfidenceUpper << "]"
1096 << "us/workload" << TestLog::EndMessage;
1098 log << TestLog::Message << "Render time for scene with depth test was\n\t"
1099 << "[" << testParam.offsetConfidenceLower << ", " << testParam.offset << ", " << testParam.offsetConfidenceUpper << "]us +"
1100 << "[" << testParam.coefficientConfidenceLower << ", " << testParam.coefficient << ", " << testParam.coefficientConfidenceUpper << "]"
1101 << "us/workload" << TestLog::EndMessage;
1103 log << TestLog::EndSection;
1105 if (de::inRange(0.0f, testParam.coefficientConfidenceLower, testParam.coefficientConfidenceUpper))
1107 log << TestLog::Message << "Test duration not dependent on culled workload" << TestLog::EndMessage;
1108 m_results.addResult(QP_TEST_RESULT_PASS, "0.0");
1110 else if (testParam.coefficientConfidenceLower < testParam.coefficientConfidenceUpper*0.25)
1112 log << TestLog::Message << "Coefficient confidence range is extremely large, cannot give reliable result" << TestLog::EndMessage;
1113 m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
1115 else if (baseParam.coefficientConfidenceLower < baseParam.coefficientConfidenceUpper*0.25)
1117 log << TestLog::Message << "Coefficient confidence range for base render time is extremely large, cannot give reliable result" << TestLog::EndMessage;
1118 m_results.addResult(QP_TEST_RESULT_PASS, "Result confidence extremely low");
1122 log << TestLog::Message << "Test duration is dependent on culled workload" << TestLog::EndMessage;
1123 m_results.addResult(QP_TEST_RESULT_PASS, de::floatToString(de::abs(testParam.coefficient)/de::abs(baseParam.coefficient), 2));
1128 // Speed of trivial culling
1129 class BaseCostCase : public RenderCountCase
1132 BaseCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1133 : RenderCountCase (testCtx, renderCtx, name, desc) {}
1135 ~BaseCostCase (void) {}
1138 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); }
1139 virtual ObjectData genOccludedGeometry (void) const { return Utils::variableQuad(0.8f); }
1141 virtual void logDescription (void)
1143 TestLog& log = m_testCtx.getLog();
1145 log << TestLog::Section("Description", "Test description");
1146 log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1147 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1148 log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1149 log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage;
1150 log << TestLog::EndSection;
1155 class GradientCostCase : public RenderCountCase
1158 GradientCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float gradientDistance)
1159 : RenderCountCase (testCtx, renderCtx, name, desc)
1160 , m_gradientDistance (gradientDistance)
1164 ~GradientCostCase (void) {}
1167 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuadWithGradient(0.0f, 1.0f - m_gradientDistance); }
1168 virtual ObjectData genOccludedGeometry (void) const
1170 return ObjectData(glu::makeVtxFragSources(Utils::getInstanceNoiseVertexShader(), Utils::getDepthAsRedFragmentShader()), Utils::getFullscreenQuadWithGradient(m_gradientDistance, 1.0f));
1173 virtual void logDescription (void)
1175 TestLog& log = m_testCtx.getLog();
1177 log << TestLog::Section("Description", "Test description");
1178 log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1179 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1180 log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1181 log << TestLog::Message << "The quads are tilted so that the left edge of the occluded quad has a depth of 1.0 and the right edge of the occluding quad has a depth of 0.0." << TestLog::EndMessage;
1182 log << TestLog::Message << "The quads are spaced to have a depth difference of " << m_gradientDistance << " at all points." << TestLog::EndMessage;
1183 log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage;
1184 log << TestLog::EndSection;
1187 const float m_gradientDistance;
1190 // Constant offset to frag depth in occluder
1191 class OccluderStaticFragDepthCostCase : public RenderCountCase
1194 OccluderStaticFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1195 : RenderCountCase(testCtx, renderCtx, name, desc)
1199 ~OccluderStaticFragDepthCostCase (void) {}
1202 virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
1203 virtual ObjectData genOccludedGeometry (void) const { return Utils::fastQuad(0.8f); }
1205 virtual void logDescription (void)
1207 TestLog& log = m_testCtx.getLog();
1209 log << TestLog::Section("Description", "Test description");
1210 log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1211 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1212 log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1213 log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1214 log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage;
1215 log << TestLog::EndSection;
1219 // Dynamic offset to frag depth in occluder
1220 class OccluderDynamicFragDepthCostCase : public RenderCountCase
1223 OccluderDynamicFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1224 : RenderCountCase(testCtx, renderCtx, name, desc)
1228 ~OccluderDynamicFragDepthCostCase (void) {}
1231 virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
1232 virtual ObjectData genOccludedGeometry (void) const { return Utils::fastQuad(0.8f); }
1234 virtual void logDescription (void)
1236 TestLog& log = m_testCtx.getLog();
1238 log << TestLog::Section("Description", "Test description");
1239 log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1240 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1241 log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1242 log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1243 log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage;
1244 log << TestLog::EndSection;
1248 // Constant offset to frag depth in occluder
1249 class OccludedStaticFragDepthCostCase : public RenderCountCase
1252 OccludedStaticFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1253 : RenderCountCase(testCtx, renderCtx, name, desc)
1257 ~OccludedStaticFragDepthCostCase (void) {}
1260 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); }
1261 virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
1263 virtual void logDescription (void)
1265 TestLog& log = m_testCtx.getLog();
1267 log << TestLog::Section("Description", "Test description");
1268 log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1269 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1270 log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1271 log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1272 log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage;
1273 log << TestLog::EndSection;
1277 // Dynamic offset to frag depth in occluder
1278 class OccludedDynamicFragDepthCostCase : public RenderCountCase
1281 OccludedDynamicFragDepthCostCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1282 : RenderCountCase(testCtx, renderCtx, name, desc)
1286 ~OccludedDynamicFragDepthCostCase (void) {}
1289 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); }
1290 virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
1292 virtual void logDescription (void)
1294 TestLog& log = m_testCtx.getLog();
1296 log << TestLog::Section("Description", "Test description");
1297 log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1298 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) is rendered once, the second (occluded) is rendered repeatedly" << TestLog::EndMessage;
1299 log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1300 log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1301 log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage;
1302 log << TestLog::EndSection;
1306 // Culling speed with slightly less trivial geometry
1307 class OccludingGeometryComplexityCostCase : public RenderCountCase
1310 OccludingGeometryComplexityCostCase (TestContext& testCtx,
1311 const RenderContext& renderCtx,
1317 : RenderCountCase (testCtx, renderCtx, name, desc)
1318 , m_resolution (resolution)
1319 , m_xyNoise (xyNoise)
1324 ~OccludingGeometryComplexityCostCase (void) {}
1327 virtual ObjectData genOccluderGeometry (void) const
1329 return ObjectData(Utils::getBaseShader(),
1330 Utils::getFullScreenGrid(m_resolution,
1331 deInt32Hash(deStringHash(getName())) ^ m_testCtx.getCommandLine().getBaseSeed(),
1337 virtual ObjectData genOccludedGeometry (void) const { return Utils::variableQuad(0.8f); }
1339 virtual void logDescription (void)
1341 TestLog& log = m_testCtx.getLog();
1343 log << TestLog::Section("Description", "Test description");
1344 log << TestLog::Message << "Testing hidden fragment culling speed" << TestLog::EndMessage;
1345 log << TestLog::Message << "Geometry consists of an occluding grid and an occluded fullsceen quad. The occluding geometry is rendered once, the occluded one is rendered repeatedly" << TestLog::EndMessage;
1346 log << TestLog::Message << "Workload indicates the number of times the occluded quad is rendered" << TestLog::EndMessage;
1347 log << TestLog::Message << "The time per culled pixel is estimated from the rate of change of rendering time as a function of workload" << TestLog::EndMessage;
1348 log << TestLog::EndSection;
1351 const int m_resolution;
1352 const float m_xyNoise;
1353 const float m_zNoise;
1357 // Cases with varying workloads in the fragment shader
1358 class FragmentWorkloadCullCase : public RelativeChangeCase
1361 FragmentWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
1362 virtual ~FragmentWorkloadCullCase (void) {}
1365 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); }
1367 virtual void logDescription (void);
1370 FragmentWorkloadCullCase::FragmentWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1371 : RelativeChangeCase (testCtx, renderCtx, name, desc)
1375 void FragmentWorkloadCullCase::logDescription (void)
1377 TestLog& log = m_testCtx.getLog();
1379 log << TestLog::Section("Description", "Test description");
1380 log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
1381 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
1382 "the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1383 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1384 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1385 log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage;
1386 log << TestLog::EndSection;
1389 // Additional workload consists of texture lookups
1390 class FragmentTextureWorkloadCullCase : public FragmentWorkloadCullCase
1393 FragmentTextureWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc);
1394 virtual ~FragmentTextureWorkloadCullCase (void) {}
1396 virtual void init (void);
1397 virtual void deinit (void);
1400 typedef MovePtr<glu::Texture> TexPtr;
1402 virtual ObjectData genOccludedGeometry (void) const
1404 return ObjectData(Utils::getTextureWorkloadShader(), Utils::getFullscreenQuad(0.8f));
1410 FragmentTextureWorkloadCullCase::FragmentTextureWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1411 : FragmentWorkloadCullCase (testCtx, renderCtx, name, desc)
1415 void FragmentTextureWorkloadCullCase::init (void)
1417 const glw::Functions& gl = m_renderCtx.getFunctions();
1418 const int size = 128;
1419 const vector<deUint8> data (size*size*4, 255);
1421 m_texture = MovePtr<glu::Texture>(new glu::Texture(gl));
1423 gl.bindTexture(GL_TEXTURE_2D, m_texture);
1424 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
1425 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1426 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1429 void FragmentTextureWorkloadCullCase::deinit (void)
1434 // Additional workload consists of arithmetic
1435 class FragmentArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
1438 FragmentArithmeticWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1439 : FragmentWorkloadCullCase (testCtx, renderCtx, name, desc)
1442 virtual ~FragmentArithmeticWorkloadCullCase (void) {}
1445 virtual ObjectData genOccludedGeometry (void) const
1447 return ObjectData(Utils::getArithmeticWorkloadShader(), Utils::getFullscreenQuad(0.8f));
1451 // Contains dynamicly unused discard after a series of calculations
1452 class FragmentDiscardArithmeticWorkloadCullCase : public FragmentWorkloadCullCase
1455 FragmentDiscardArithmeticWorkloadCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1456 : FragmentWorkloadCullCase (testCtx, renderCtx, name, desc)
1460 virtual ~FragmentDiscardArithmeticWorkloadCullCase (void) {}
1463 virtual ObjectData genOccludedGeometry (void) const
1465 return ObjectData(Utils::getArithmeticWorkloadDiscardShader(), Utils::getFullscreenQuad(0.8f));
1468 virtual void logDescription (void)
1470 TestLog& log = m_testCtx.getLog();
1472 log << TestLog::Section("Description", "Test description");
1473 log << TestLog::Message << "Testing effects of culled fragment workload on render time" << TestLog::EndMessage;
1474 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad uses a trivial shader,"
1475 "the second (occluded) contains significant fragment shader work and a discard that is never triggers but has a dynamic condition" << TestLog::EndMessage;
1476 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1477 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1478 log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage;
1479 log << TestLog::EndSection;
1483 // Discards fragments from the occluder in a grid pattern
1484 class PartialOccluderDiscardCullCase : public RelativeChangeCase
1487 PartialOccluderDiscardCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, int gridsize)
1488 : RelativeChangeCase (testCtx, renderCtx, name, desc)
1489 , m_gridsize (gridsize)
1492 virtual ~PartialOccluderDiscardCullCase (void) {}
1495 virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getGridDiscardShader(m_gridsize), 0.2f); }
1496 virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); }
1498 virtual void logDescription (void)
1500 TestLog& log = m_testCtx.getLog();
1502 log << TestLog::Section("Description", "Test description");
1503 log << TestLog::Message << "Testing effects of partially discarded occluder on rendering time" << TestLog::EndMessage;
1504 log << TestLog::Message << "Geometry consists of two fullsceen quads. The first (occluding) quad discards half the "
1505 "fragments in a grid pattern, the second (partially occluded) contains significant fragment shader work" << TestLog::EndMessage;
1506 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1507 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1508 log << TestLog::Message << "Successfull early Z-testing should result in depth testing halving the render time" << TestLog::EndMessage;
1509 log << TestLog::EndSection;
1512 const int m_gridsize;
1515 // Trivial occluder covering part of screen
1516 class PartialOccluderCullCase : public RelativeChangeCase
1519 PartialOccluderCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc, float coverage)
1520 : RelativeChangeCase (testCtx, renderCtx, name, desc)
1521 , m_coverage (coverage)
1524 ~PartialOccluderCullCase (void) {}
1527 virtual ObjectData genOccluderGeometry (void) const { return ObjectData(Utils::getBaseShader(), Utils::getPartScreenQuad(m_coverage, 0.2f)); }
1528 virtual ObjectData genOccludedGeometry (void) const {return Utils::slowQuad(0.8f); }
1530 virtual void logDescription (void)
1532 TestLog& log = m_testCtx.getLog();
1534 log << TestLog::Section("Description", "Test description");
1535 log << TestLog::Message << "Testing effects of partial occluder on rendering time" << TestLog::EndMessage;
1536 log << TestLog::Message << "Geometry consists of two quads. The first (occluding) quad covers " << m_coverage*100.0f
1537 << "% of the screen, while the second (partially occluded, fullscreen) contains significant fragment shader work" << TestLog::EndMessage;
1538 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1539 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1540 log << TestLog::Message << "Successfull early Z-testing should result in render time increasing proportionally with unoccluded area" << TestLog::EndMessage;
1541 log << TestLog::EndSection;
1544 const float m_coverage;
1547 // Constant offset to frag depth in occluder
1548 class StaticOccluderFragDepthCullCase : public RelativeChangeCase
1551 StaticOccluderFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1552 : RelativeChangeCase(testCtx, renderCtx, name, desc)
1556 ~StaticOccluderFragDepthCullCase (void) {}
1559 virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthFragmentShader(), 0.2f); }
1560 virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); }
1562 virtual void logDescription (void)
1564 TestLog& log = m_testCtx.getLog();
1566 log << TestLog::Section("Description", "Test description");
1567 log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage;
1568 log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1569 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1570 log << TestLog::Message << "The occluder quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1571 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1572 log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage;
1573 log << TestLog::EndSection;
1577 // Dynamic offset to frag depth in occluder
1578 class DynamicOccluderFragDepthCullCase : public RelativeChangeCase
1581 DynamicOccluderFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1582 : RelativeChangeCase(testCtx, renderCtx, name, desc)
1586 ~DynamicOccluderFragDepthCullCase (void) {}
1589 virtual ObjectData genOccluderGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthFragmentShader(), 0.2f); }
1590 virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); }
1592 virtual void logDescription (void)
1594 TestLog& log = m_testCtx.getLog();
1596 log << TestLog::Section("Description", "Test description");
1597 log << TestLog::Message << "Testing effects of non-default frag depth on culling efficiency" << TestLog::EndMessage;
1598 log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1599 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1600 log << TestLog::Message << "The occluder quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1601 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1602 log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage;
1603 log << TestLog::EndSection;
1607 // Constant offset to frag depth in occluded
1608 class StaticOccludedFragDepthCullCase : public RelativeChangeCase
1611 StaticOccludedFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1612 : RelativeChangeCase(testCtx, renderCtx, name, desc)
1616 ~StaticOccludedFragDepthCullCase (void) {}
1619 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); }
1620 virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getStaticFragDepthArithmeticWorkloadFragmentShader(), 0.2f); }
1622 virtual void logDescription (void)
1624 TestLog& log = m_testCtx.getLog();
1626 log << TestLog::Section("Description", "Test description");
1627 log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
1628 log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1629 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1630 log << TestLog::Message << "The occluded quad has a static offset applied to gl_FragDepth" << TestLog::EndMessage;
1631 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1632 log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage;
1633 log << TestLog::EndSection;
1637 // Dynamic offset to frag depth in occluded
1638 class DynamicOccludedFragDepthCullCase : public RelativeChangeCase
1641 DynamicOccludedFragDepthCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1642 : RelativeChangeCase(testCtx, renderCtx, name, desc)
1646 ~DynamicOccludedFragDepthCullCase (void) {}
1649 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); }
1650 virtual ObjectData genOccludedGeometry (void) const { return Utils::quadWith(Utils::getDynamicFragDepthArithmeticWorkloadFragmentShader(), 0.2f); }
1652 virtual void logDescription (void)
1654 TestLog& log = m_testCtx.getLog();
1656 log << TestLog::Section("Description", "Test description");
1657 log << TestLog::Message << "Testing effects of non-default frag depth on rendering time" << TestLog::EndMessage;
1658 log << TestLog::Message << "Geometry consists of two fullscreen quads. The first (occluding) quad is trivial, while the second (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1659 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1660 log << TestLog::Message << "The occluded quad has a dynamic offset applied to gl_FragDepth" << TestLog::EndMessage;
1661 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1662 log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage;
1663 log << TestLog::EndSection;
1667 // Dynamic offset to frag depth in occluded
1668 class ReversedDepthOrderCullCase : public RelativeChangeCase
1671 ReversedDepthOrderCullCase (TestContext& testCtx, const RenderContext& renderCtx, const char* name, const char* desc)
1672 : RelativeChangeCase(testCtx, renderCtx, name, desc)
1676 ~ReversedDepthOrderCullCase (void) {}
1679 virtual ObjectData genOccluderGeometry (void) const { return Utils::fastQuad(0.2f); }
1680 virtual ObjectData genOccludedGeometry (void) const { return Utils::slowQuad(0.8f); }
1682 virtual void logDescription (void)
1684 TestLog& log = m_testCtx.getLog();
1686 log << TestLog::Section("Description", "Test description");
1687 log << TestLog::Message << "Testing effects of of back first rendering order on culling efficiency" << TestLog::EndMessage;
1688 log << TestLog::Message << "Geometry consists of two fullscreen quads. The second (occluding) quad is trivial, while the first (occluded) contains significant fragment shader work" << TestLog::EndMessage;
1689 log << TestLog::Message << "Workload indicates the number of iterations of dummy work done in the occluded quad's fragment shader" << TestLog::EndMessage;
1690 log << TestLog::Message << "The ratio of rendering times of this scene with/without depth testing are compared" << TestLog::EndMessage;
1691 log << TestLog::Message << "Successfull early Z-testing should result in no correlation between workload and render time" << TestLog::EndMessage;
1692 log << TestLog::EndSection;
1695 // Rendering order of occluder & occluded is reversed, otherwise identical to parent version
1696 Sample renderSample (const RenderData& occluder, const RenderData& occluded, int workload) const
1698 const glw::Functions& gl = m_renderCtx.getFunctions();
1699 const GLuint program = occluded.m_program.getProgram();
1705 gl.useProgram(program);
1706 gl.uniform1i(gl.getUniformLocation(program, "u_iterations"), workload);
1708 // Warmup (this workload seems to reduce variation in following workloads)
1710 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1711 gl.disable(GL_DEPTH_TEST);
1713 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1718 prev = deGetMicroseconds();
1720 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1721 gl.disable(GL_DEPTH_TEST);
1723 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1725 now = deGetMicroseconds();
1727 sample.nullTime = now - prev;
1732 prev = deGetMicroseconds();
1734 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1735 gl.enable(GL_DEPTH_TEST);
1740 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1742 now = deGetMicroseconds();
1744 sample.testTime = now - prev;
1749 prev = deGetMicroseconds();
1751 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1752 gl.disable(GL_DEPTH_TEST);
1757 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
1759 now = deGetMicroseconds();
1761 sample.baseTime = now - prev;
1764 sample.workload = 0;
1772 DepthTests::DepthTests (Context& context)
1773 : TestCaseGroup (context, "depth", "Depth culling performance")
1777 void DepthTests::init (void)
1779 TestContext& testCtx = m_context.getTestContext();
1780 const RenderContext& renderCtx = m_context.getRenderContext();
1783 tcu::TestCaseGroup* const cullEfficiencyGroup = new tcu::TestCaseGroup(m_testCtx, "cull_efficiency", "Fragment cull efficiency");
1785 addChild(cullEfficiencyGroup);
1788 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "workload", "Workload");
1790 cullEfficiencyGroup->addChild(group);
1792 group->addChild(new FragmentTextureWorkloadCullCase( testCtx, renderCtx, "workload_texture", "Fragment shader with texture lookup workload"));
1793 group->addChild(new FragmentArithmeticWorkloadCullCase( testCtx, renderCtx, "workload_arithmetic", "Fragment shader with arithmetic workload"));
1794 group->addChild(new FragmentDiscardArithmeticWorkloadCullCase( testCtx, renderCtx, "workload_arithmetic_discard", "Fragment shader that may discard with arithmetic workload"));
1798 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_discard", "Discard");
1800 cullEfficiencyGroup->addChild(group);
1802 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_256", "Parts of occluder geometry discarded", 256));
1803 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_128", "Parts of occluder geometry discarded", 128));
1804 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_64", "Parts of occluder geometry discarded", 64));
1805 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_32", "Parts of occluder geometry discarded", 32));
1806 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_16", "Parts of occluder geometry discarded", 16));
1807 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_8", "Parts of occluder geometry discarded", 8));
1808 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_4", "Parts of occluder geometry discarded", 4));
1809 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_2", "Parts of occluder geometry discarded", 2));
1810 group->addChild(new PartialOccluderDiscardCullCase(testCtx, renderCtx, "grid_1", "Parts of occluder geometry discarded", 1));
1814 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "partial_coverage", "Partial Coverage");
1816 cullEfficiencyGroup->addChild(group);
1818 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "100", "Occluder covering only part of occluded geometry", 1.00f));
1819 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "099", "Occluder covering only part of occluded geometry", 0.99f));
1820 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "095", "Occluder covering only part of occluded geometry", 0.95f));
1821 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "090", "Occluder covering only part of occluded geometry", 0.90f));
1822 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "080", "Occluder covering only part of occluded geometry", 0.80f));
1823 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "070", "Occluder covering only part of occluded geometry", 0.70f));
1824 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "050", "Occluder covering only part of occluded geometry", 0.50f));
1825 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "025", "Occluder covering only part of occluded geometry", 0.25f));
1826 group->addChild(new PartialOccluderCullCase(testCtx, renderCtx, "010", "Occluder covering only part of occluded geometry", 0.10f));
1830 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Partial Coverage");
1832 cullEfficiencyGroup->addChild(group);
1834 group->addChild(new StaticOccluderFragDepthCullCase( testCtx, renderCtx, "occluder_static", ""));
1835 group->addChild(new DynamicOccluderFragDepthCullCase(testCtx, renderCtx, "occluder_dynamic", ""));
1836 group->addChild(new StaticOccludedFragDepthCullCase( testCtx, renderCtx, "occluded_static", ""));
1837 group->addChild(new DynamicOccludedFragDepthCullCase(testCtx, renderCtx, "occluded_dynamic", ""));
1841 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "order", "Rendering order");
1843 cullEfficiencyGroup->addChild(group);
1845 group->addChild(new ReversedDepthOrderCullCase(testCtx, renderCtx, "reversed", "Back to front rendering order"));
1850 tcu::TestCaseGroup* const testCostGroup = new tcu::TestCaseGroup(m_testCtx, "culled_pixel_cost", "Fragment cull efficiency");
1852 addChild(testCostGroup);
1855 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "gradient", "Gradients with small depth differences");
1857 testCostGroup->addChild(group);
1859 group->addChild(new BaseCostCase(testCtx, renderCtx, "flat", ""));
1860 group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_050", "", 0.50f));
1861 group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_010", "", 0.10f));
1862 group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_005", "", 0.05f));
1863 group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_002", "", 0.02f));
1864 group->addChild(new GradientCostCase(testCtx, renderCtx, "gradient_001", "", 0.01f));
1868 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "occluder_geometry", "Occluders with varying geometry complexity");
1870 testCostGroup->addChild(group);
1872 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_5", "", 5, 0.0f, 0.0f));
1873 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_15", "", 15, 0.0f, 0.0f));
1874 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_25", "", 25, 0.0f, 0.0f));
1875 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_50", "", 50, 0.0f, 0.0f));
1876 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_uniform_grid_100", "", 100, 0.0f, 0.0f));
1878 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_5", "", 5, 1.0f/5.0f, 0.0f));
1879 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_15", "", 15, 1.0f/15.0f, 0.0f));
1880 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_25", "", 25, 1.0f/25.0f, 0.0f));
1881 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_50", "", 50, 1.0f/50.0f, 0.0f));
1882 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "flat_noisy_grid_100", "", 100, 1.0f/100.0f, 0.0f));
1884 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_5", "", 5, 0.0f, 0.2f));
1885 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_15", "", 15, 0.0f, 0.2f));
1886 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_25", "", 25, 0.0f, 0.2f));
1887 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_50", "", 50, 0.0f, 0.2f));
1888 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_uniform_grid_100", "", 100, 0.0f, 0.2f));
1890 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_5", "", 5, 1.0f/5.0f, 0.2f));
1891 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_15", "", 15, 1.0f/15.0f, 0.2f));
1892 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_25", "", 25, 1.0f/25.0f, 0.2f));
1893 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_50", "", 50, 1.0f/50.0f, 0.2f));
1894 group->addChild(new OccludingGeometryComplexityCostCase(testCtx, renderCtx, "uneven_noisy_grid_100", "", 100, 1.0f/100.0f, 0.2f));
1898 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "frag_depth", "Modifying gl_FragDepth");
1900 testCostGroup->addChild(group);
1902 group->addChild(new OccluderStaticFragDepthCostCase( testCtx, renderCtx, "occluder_static", ""));
1903 group->addChild(new OccluderDynamicFragDepthCostCase(testCtx, renderCtx, "occluder_dynamic", ""));
1904 group->addChild(new OccludedStaticFragDepthCostCase( testCtx, renderCtx, "occluded_static", ""));
1905 group->addChild(new OccludedDynamicFragDepthCostCase(testCtx, renderCtx, "occluded_dynamic", ""));