31c123eab7a5821a5d24600314a96f89a6232030
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fPrimitiveBoundingBoxTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2015 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 Primitive bounding box tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fPrimitiveBoundingBoxTests.hpp"
25
26 #include "tcuTestLog.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "gluCallLogWrapper.hpp"
32 #include "gluContextInfo.hpp"
33 #include "gluRenderContext.hpp"
34 #include "gluStrUtil.hpp"
35 #include "gluShaderProgram.hpp"
36 #include "gluObjectWrapper.hpp"
37 #include "gluPixelTransfer.hpp"
38 #include "glsStateQueryUtil.hpp"
39 #include "glwFunctions.hpp"
40 #include "glwEnums.hpp"
41 #include "deRandom.hpp"
42 #include "deUniquePtr.hpp"
43 #include "deStringUtil.hpp"
44
45 #include <vector>
46 #include <sstream>
47 #include <algorithm>
48
49 namespace deqp
50 {
51 namespace gles31
52 {
53 namespace Functional
54 {
55 namespace
56 {
57
58 namespace StateQueryUtil = ::deqp::gls::StateQueryUtil;
59
60 struct BoundingBox
61 {
62         tcu::Vec4 min;
63         tcu::Vec4 max;
64
65         /*--------------------------------------------------------------------*//*!
66          * Get component by index of a 8-component vector constructed by
67          * concatenating 4-component min and max vectors.
68          *//*--------------------------------------------------------------------*/
69         float&                  getComponentAccess      (int ndx);
70         const float&    getComponentAccess      (int ndx) const;
71 };
72
73 float& BoundingBox::getComponentAccess (int ndx)
74 {
75         DE_ASSERT(ndx >= 0 && ndx < 8);
76         if (ndx < 4)
77                 return min[ndx];
78         else
79                 return max[ndx-4];
80 }
81
82 const float& BoundingBox::getComponentAccess (int ndx) const
83 {
84         return const_cast<BoundingBox*>(this)->getComponentAccess(ndx);
85 }
86
87 struct ProjectedBBox
88 {
89         tcu::Vec3       min;
90         tcu::Vec3       max;
91 };
92
93 static ProjectedBBox projectBoundingBox (const BoundingBox& bbox)
94 {
95         const float             wMin    = de::max(0.0f, bbox.min.w()); // clamp to w=0 as extension requires
96         const float             wMax    = de::max(0.0f, bbox.max.w());
97         ProjectedBBox   retVal;
98
99         retVal.min = tcu::min(bbox.min.swizzle(0, 1, 2) / wMin,
100                                                   bbox.min.swizzle(0, 1, 2) / wMax);
101         retVal.max = tcu::max(bbox.max.swizzle(0, 1, 2) / wMin,
102                                                   bbox.max.swizzle(0, 1, 2) / wMax);
103         return retVal;
104 }
105
106 static tcu::IVec4 getViewportBoundingBoxArea (const ProjectedBBox& bbox, const tcu::IVec2& viewportSize, float size = 0.0f)
107 {
108         tcu::Vec4       vertexBox;
109         tcu::IVec4      pixelBox;
110
111         vertexBox.x() = (bbox.min.x() * 0.5f + 0.5f) * viewportSize.x();
112         vertexBox.y() = (bbox.min.y() * 0.5f + 0.5f) * viewportSize.y();
113         vertexBox.z() = (bbox.max.x() * 0.5f + 0.5f) * viewportSize.x();
114         vertexBox.w() = (bbox.max.y() * 0.5f + 0.5f) * viewportSize.y();
115
116         pixelBox.x() = deFloorFloatToInt32(vertexBox.x() - size/2.0f);
117         pixelBox.y() = deFloorFloatToInt32(vertexBox.y() - size/2.0f);
118         pixelBox.z() = deCeilFloatToInt32(vertexBox.z() + size/2.0f);
119         pixelBox.w() = deCeilFloatToInt32(vertexBox.w() + size/2.0f);
120         return pixelBox;
121 }
122
123
124 class InitialValueCase : public TestCase
125 {
126 public:
127                                         InitialValueCase        (Context& context, const char* name, const char* desc);
128
129         void                    init                            (void);
130         IterateResult   iterate                         (void);
131 };
132
133 InitialValueCase::InitialValueCase (Context& context, const char* name, const char* desc)
134         : TestCase(context, name, desc)
135 {
136 }
137
138 void InitialValueCase::init (void)
139 {
140         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_primitive_bounding_box"))
141                 throw tcu::NotSupportedError("Test requires GL_EXT_primitive_bounding_box extension");
142 }
143
144 InitialValueCase::IterateResult InitialValueCase::iterate (void)
145 {
146         StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLfloat[8]>     state;
147         glu::CallLogWrapper                                                                                     gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
148
149         gl.enableLogging(true);
150
151         m_testCtx.getLog()
152                 << tcu::TestLog::Message
153                 << "Querying GL_PRIMITIVE_BOUNDING_BOX_EXT, expecting (-1, -1, -1, 1) (1, 1, 1, 1)"
154                 << tcu::TestLog::EndMessage;
155
156         gl.glGetFloatv(GL_PRIMITIVE_BOUNDING_BOX_EXT, state);
157         GLU_EXPECT_NO_ERROR(gl.glGetError(), "query");
158
159         if (!state.verifyValidity(m_testCtx))
160                 return STOP;
161
162         m_testCtx.getLog()
163                 << tcu::TestLog::Message
164                 << "Got " << tcu::formatArray(&state[0], &state[8])
165                 << tcu::TestLog::EndMessage;
166
167         if ((state[0] != -1.0f) || (state[1] != -1.0f) || (state[2] != -1.0f) || (state[3] != 1.0f) ||
168                 (state[4] !=  1.0f) || (state[5] !=  1.0f) || (state[6] !=  1.0f) || (state[7] != 1.0f))
169         {
170                 m_testCtx.getLog()
171                         << tcu::TestLog::Message
172                         << "Error, unexpected value"
173                         << tcu::TestLog::EndMessage;
174
175                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid initial value");
176         }
177         else
178                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
179
180         return STOP;
181 }
182
183 class QueryCase : public TestCase
184 {
185 public:
186         enum QueryMethod
187         {
188                 QUERY_FLOAT = 0,
189                 QUERY_BOOLEAN,
190                 QUERY_INT,
191                 QUERY_INT64,
192
193                 QUERY_LAST
194         };
195
196                                                 QueryCase       (Context& context, const char* name, const char* desc, QueryMethod method);
197
198 private:
199         void                            init            (void);
200         IterateResult           iterate         (void);
201
202         bool                            verifyState     (glu::CallLogWrapper& gl, const BoundingBox& bbox) const;
203
204         const QueryMethod       m_method;
205 };
206
207 QueryCase::QueryCase (Context& context, const char* name, const char* desc, QueryMethod method)
208         : TestCase      (context, name, desc)
209         , m_method      (method)
210 {
211         DE_ASSERT(method < QUERY_LAST);
212 }
213
214 void QueryCase::init (void)
215 {
216         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_primitive_bounding_box"))
217                 throw tcu::NotSupportedError("Test requires GL_EXT_primitive_bounding_box extension");
218 }
219
220 QueryCase::IterateResult QueryCase::iterate (void)
221 {
222         static const BoundingBox fixedCases[] =
223         {
224                 { tcu::Vec4( 0.0f,  0.0f,  0.0f,  0.0f), tcu::Vec4( 0.0f,  0.0f,  0.0f,  0.0f) },
225                 { tcu::Vec4(-0.0f, -0.0f, -0.0f, -0.0f), tcu::Vec4( 0.0f,  0.0f,  0.0f, -0.0f) },
226                 { tcu::Vec4( 0.0f,  0.0f,  0.0f,  0.0f), tcu::Vec4( 1.0f,  1.0f,  1.0f, -1.0f) },
227                 { tcu::Vec4( 2.0f,  2.0f,  2.0f,  2.0f), tcu::Vec4( 1.5f,  1.5f,  1.5f,  1.0f) },
228                 { tcu::Vec4( 1.0f,  1.0f,  1.0f,  1.0f), tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f) },
229                 { tcu::Vec4( 1.0f,  1.0f,  1.0f,  0.3f), tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.2f) },
230         };
231
232         const int                                       numRandomCases  = 9;
233         glu::CallLogWrapper                     gl                              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
234         de::Random                                      rnd                             (0xDE3210);
235         std::vector<BoundingBox>        cases;
236
237         cases.insert(cases.begin(), DE_ARRAY_BEGIN(fixedCases), DE_ARRAY_END(fixedCases));
238         for (int ndx = 0; ndx < numRandomCases; ++ndx)
239         {
240                 BoundingBox     boundingBox;
241
242                 // parameter evaluation order is not guaranteed, cannot just do "max = (rand(), rand(), ...)
243                 for (int coordNdx = 0; coordNdx < 8; ++coordNdx)
244                         boundingBox.getComponentAccess(coordNdx) = rnd.getFloat(-4.0f, 4.0f);
245
246                 cases.push_back(boundingBox);
247         }
248
249         gl.enableLogging(true);
250         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
251
252         for (int caseNdx = 0; caseNdx < (int)cases.size(); ++caseNdx)
253         {
254                 const tcu::ScopedLogSection     section         (m_testCtx.getLog(), "Iteration", "Iteration " + de::toString(caseNdx+1));
255                 const BoundingBox&                      boundingBox     = cases[caseNdx];
256
257                 gl.glPrimitiveBoundingBoxEXT(boundingBox.min.x(), boundingBox.min.y(), boundingBox.min.z(), boundingBox.min.w(),
258                                                                          boundingBox.max.x(), boundingBox.max.y(), boundingBox.max.z(), boundingBox.max.w());
259
260                 if (!verifyState(gl, boundingBox))
261                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected query result");
262         }
263
264         return STOP;
265 }
266
267 bool QueryCase::verifyState (glu::CallLogWrapper& gl, const BoundingBox& bbox) const
268 {
269         switch (m_method)
270         {
271                 case QUERY_FLOAT:
272                 {
273                         StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLfloat[8]>     state;
274                         bool                                                                                                            error = false;
275
276                         gl.glGetFloatv(GL_PRIMITIVE_BOUNDING_BOX_EXT, state);
277                         GLU_EXPECT_NO_ERROR(gl.glGetError(), "query");
278
279                         if (!state.verifyValidity(m_testCtx))
280                                 return false;
281
282                         m_testCtx.getLog()
283                                         << tcu::TestLog::Message
284                                         << "glGetFloatv returned " << tcu::formatArray(&state[0], &state[8])
285                                         << tcu::TestLog::EndMessage;
286
287                         for (int ndx = 0; ndx < 8; ++ndx)
288                                 if (state[ndx] != bbox.getComponentAccess(ndx))
289                                         error = true;
290
291                         if (error)
292                         {
293                                 m_testCtx.getLog()
294                                         << tcu::TestLog::Message
295                                         << "Error, unexpected value\n"
296                                         << "Expected ["
297                                         << bbox.min.x() << ", " << bbox.min.y() << ", " << bbox.min.z() << ", " << bbox.min.w() << ", "
298                                         << bbox.max.x() << ", " << bbox.max.y() << ", " << bbox.max.z() << ", " << bbox.max.w() << "]"
299                                         << tcu::TestLog::EndMessage;
300                                 return false;
301                         }
302                         return true;
303                 }
304
305                 case QUERY_INT:
306                 {
307                         StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint[8]>       state;
308                         bool                                                                                                            error = false;
309
310                         gl.glGetIntegerv(GL_PRIMITIVE_BOUNDING_BOX_EXT, state);
311                         GLU_EXPECT_NO_ERROR(gl.glGetError(), "query");
312
313                         if (!state.verifyValidity(m_testCtx))
314                                 return false;
315
316                         m_testCtx.getLog()
317                                         << tcu::TestLog::Message
318                                         << "glGetIntegerv returned " << tcu::formatArray(&state[0], &state[8])
319                                         << tcu::TestLog::EndMessage;
320
321                         for (int ndx = 0; ndx < 8; ++ndx)
322                                 if (state[ndx] != StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<glw::GLint>(bbox.getComponentAccess(ndx)) &&
323                                         state[ndx] != StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<glw::GLint>(bbox.getComponentAccess(ndx)))
324                                         error = true;
325
326                         if (error)
327                         {
328                                 tcu::MessageBuilder builder(&m_testCtx.getLog());
329
330                                 builder << "Error, unexpected value\n"
331                                                 << "Expected [";
332
333                                 for (int ndx = 0; ndx < 8; ++ndx)
334                                 {
335                                         const glw::GLint roundDown      = StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<glw::GLint>(bbox.getComponentAccess(ndx));
336                                         const glw::GLint roundUp        = StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<glw::GLint>(bbox.getComponentAccess(ndx));
337
338                                         if (ndx != 0)
339                                                 builder << ", ";
340
341                                         if (roundDown == roundUp)
342                                                 builder << roundDown;
343                                         else
344                                                 builder << "{" << roundDown << ", " << roundUp << "}";
345                                 }
346
347                                 builder << "]"
348                                                 << tcu::TestLog::EndMessage;
349                                 return false;
350                         }
351                         return true;
352                 }
353
354                 case QUERY_INT64:
355                 {
356                         StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint64[8]>     state;
357                         bool                                                                                                                            error = false;
358
359                         gl.glGetInteger64v(GL_PRIMITIVE_BOUNDING_BOX_EXT, state);
360                         GLU_EXPECT_NO_ERROR(gl.glGetError(), "query");
361
362                         if (!state.verifyValidity(m_testCtx))
363                                 return false;
364
365                         m_testCtx.getLog()
366                                         << tcu::TestLog::Message
367                                         << "glGetInteger64v returned " << tcu::formatArray(&state[0], &state[8])
368                                         << tcu::TestLog::EndMessage;
369
370                         for (int ndx = 0; ndx < 8; ++ndx)
371                                 if (state[ndx] != StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<glw::GLint64>(bbox.getComponentAccess(ndx)) &&
372                                         state[ndx] != StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<glw::GLint64>(bbox.getComponentAccess(ndx)))
373                                         error = true;
374
375                         if (error)
376                         {
377                                 tcu::MessageBuilder builder(&m_testCtx.getLog());
378
379                                 builder << "Error, unexpected value\n"
380                                                 << "Expected [";
381
382                                 for (int ndx = 0; ndx < 8; ++ndx)
383                                 {
384                                         const glw::GLint64 roundDown    = StateQueryUtil::roundGLfloatToNearestIntegerHalfDown<glw::GLint64>(bbox.getComponentAccess(ndx));
385                                         const glw::GLint64 roundUp              = StateQueryUtil::roundGLfloatToNearestIntegerHalfUp<glw::GLint64>(bbox.getComponentAccess(ndx));
386
387                                         if (ndx != 0)
388                                                 builder << ", ";
389
390                                         if (roundDown == roundUp)
391                                                 builder << roundDown;
392                                         else
393                                                 builder << "{" << roundDown << ", " << roundUp << "}";
394                                 }
395
396                                 builder << "]"
397                                                 << tcu::TestLog::EndMessage;
398                                 return false;
399                         }
400                         return true;
401                 }
402
403                 case QUERY_BOOLEAN:
404                 {
405                         StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLboolean[8]>   state;
406                         bool                                                                                                                    error = false;
407
408                         gl.glGetBooleanv(GL_PRIMITIVE_BOUNDING_BOX_EXT, state);
409                         GLU_EXPECT_NO_ERROR(gl.glGetError(), "query");
410
411                         if (!state.verifyValidity(m_testCtx))
412                                 return false;
413
414                         m_testCtx.getLog()
415                                         << tcu::TestLog::Message
416                                         << "glGetBooleanv returned ["
417                                         << glu::getBooleanStr(state[0]) << ", " << glu::getBooleanStr(state[1]) << ", " << glu::getBooleanStr(state[2]) << ", " << glu::getBooleanStr(state[3]) << ", "
418                                         << glu::getBooleanStr(state[4]) << ", " << glu::getBooleanStr(state[5]) << ", " << glu::getBooleanStr(state[6]) << ", " << glu::getBooleanStr(state[7]) << "]\n"
419                                         << tcu::TestLog::EndMessage;
420
421                         for (int ndx = 0; ndx < 8; ++ndx)
422                                 if (state[ndx] != ((bbox.getComponentAccess(ndx) != 0.0f) ? (GL_TRUE) : (GL_FALSE)))
423                                         error = true;
424
425                         if (error)
426                         {
427                                 tcu::MessageBuilder builder(&m_testCtx.getLog());
428
429                                 builder << "Error, unexpected value\n"
430                                                 << "Expected [";
431
432                                 for (int ndx = 0; ndx < 8; ++ndx)
433                                 {
434                                         if (ndx != 0)
435                                                 builder << ", ";
436
437                                         builder << ((bbox.getComponentAccess(ndx) != 0.0f) ? ("GL_TRUE") : ("GL_FALSE"));
438                                 }
439
440                                 builder << "]"
441                                                 << tcu::TestLog::EndMessage;
442                                 return false;
443                         }
444                         return true;
445                 }
446
447                 default:
448                         DE_ASSERT(false);
449                         return true;
450         }
451 }
452
453 class BBoxRenderCase : public TestCase
454 {
455 public:
456         enum
457         {
458                 FLAG_RENDERTARGET_DEFAULT       = 1u << 0, //!< render to default renderbuffer
459                 FLAG_RENDERTARGET_FBO           = 1u << 1, //!< render to framebuffer object
460
461                 FLAG_BBOXSIZE_EQUAL                     = 1u << 2, //!< set tight primitive bounding box
462                 FLAG_BBOXSIZE_LARGER            = 1u << 3, //!< set padded primitive bounding box
463                 FLAG_BBOXSIZE_SMALLER           = 1u << 4, //!< set too small primitive bounding box
464
465                 FLAG_TESSELLATION                       = 1u << 5, //!< use tessellation shader
466                 FLAG_GEOMETRY                           = 1u << 6, //!< use geometry shader
467
468                 FLAG_SET_BBOX_STATE                     = 1u << 7, //!< set primitive bounding box using global state
469                 FLAG_SET_BBOX_OUTPUT            = 1u << 8, //!< set primitive bounding box using tessellation output
470                 FLAG_PER_PRIMITIVE_BBOX         = 1u << 9, //!< set primitive bounding per primitive
471
472                 FLAGBIT_USER_BIT                        = 10u //!< bits N and and up are reserved for subclasses
473         };
474
475                                                                         BBoxRenderCase                                  (Context& context, const char* name, const char* description, int numIterations, deUint32 flags);
476                                                                         ~BBoxRenderCase                                 (void);
477
478 protected:
479         enum RenderTarget
480         {
481                 RENDERTARGET_DEFAULT,
482                 RENDERTARGET_FBO,
483         };
484         enum BBoxSize
485         {
486                 BBOXSIZE_EQUAL,
487                 BBOXSIZE_LARGER,
488                 BBOXSIZE_SMALLER,
489         };
490
491         enum
492         {
493                 RENDER_TARGET_MIN_SIZE  = 256,
494                 FBO_SIZE                                = 512,
495                 MIN_VIEWPORT_SIZE               = 256,
496                 MAX_VIEWPORT_SIZE               = 512,
497         };
498         DE_STATIC_ASSERT(MIN_VIEWPORT_SIZE <= RENDER_TARGET_MIN_SIZE);
499
500         enum
501         {
502                 VA_POS_VEC_NDX          = 0,
503                 VA_COL_VEC_NDX          = 1,
504                 VA_NUM_ATTRIB_VECS      = 2,
505         };
506
507         enum AABBRoundDirection
508         {
509                 ROUND_INWARDS = 0,
510                 ROUND_OUTWARDS
511         };
512
513         struct IterationConfig
514         {
515                 tcu::IVec2      viewportPos;
516                 tcu::IVec2      viewportSize;
517                 tcu::Vec2       patternPos;             //!< in NDC
518                 tcu::Vec2       patternSize;    //!< in NDC
519                 BoundingBox     bbox;
520         };
521
522         virtual void                                    init                                                    (void);
523         virtual void                                    deinit                                                  (void);
524         IterateResult                                   iterate                                                 (void);
525
526         virtual std::string                             genVertexSource                                 (void) const = 0;
527         virtual std::string                             genFragmentSource                               (void) const = 0;
528         virtual std::string                             genTessellationControlSource    (void) const = 0;
529         virtual std::string                             genTessellationEvaluationSource (void) const = 0;
530         virtual std::string                             genGeometrySource                               (void) const = 0;
531
532         virtual IterationConfig                 generateConfig                                  (int iteration, const tcu::IVec2& renderTargetSize) const = 0;
533         virtual void                                    getAttributeData                                (std::vector<tcu::Vec4>& data) const = 0;
534         virtual void                                    renderTestPattern                               (const IterationConfig& config) = 0;
535         virtual void                                    verifyRenderResult                              (const IterationConfig& config) = 0;
536
537         IterationConfig                                 generateRandomConfig                    (int seed, const tcu::IVec2& renderTargetSize) const;
538         tcu::IVec4                                              getViewportPatternArea                  (const tcu::Vec2& patternPos, const tcu::Vec2& patternSize, const tcu::IVec2& viewportSize, AABBRoundDirection roundDir) const;
539
540         void                                                    setupRender                                             (const IterationConfig& config);
541
542         enum ShaderFunction
543         {
544                 SHADER_FUNC_MIRROR_X,
545                 SHADER_FUNC_MIRROR_Y,
546                 SHADER_FUNC_INSIDE_BBOX,
547         };
548
549         const char*                                             genShaderFunction                               (ShaderFunction func) const;
550
551         const RenderTarget                              m_renderTarget;
552         const BBoxSize                                  m_bboxSize;
553         const bool                                              m_hasTessellationStage;
554         const bool                                              m_hasGeometryStage;
555         const bool                                              m_useGlobalState;
556         const bool                                              m_calcPerPrimitiveBBox;
557         const int                                               m_numIterations;
558
559         de::MovePtr<glu::ShaderProgram> m_program;
560         de::MovePtr<glu::Buffer>                m_vbo;
561         de::MovePtr<glu::Framebuffer>   m_fbo;
562
563 private:
564         std::vector<IterationConfig>    m_iterationConfigs;
565         int                                                             m_iteration;
566 };
567
568 BBoxRenderCase::BBoxRenderCase (Context& context, const char* name, const char* description, int numIterations, deUint32 flags)
569         : TestCase                                      (context, name, description)
570         , m_renderTarget                        ((flags & FLAG_RENDERTARGET_DEFAULT) ? (RENDERTARGET_DEFAULT) : (RENDERTARGET_FBO))
571         , m_bboxSize                            ((flags & FLAG_BBOXSIZE_EQUAL) ? (BBOXSIZE_EQUAL) : (flags & FLAG_BBOXSIZE_SMALLER) ? (BBOXSIZE_SMALLER) : (BBOXSIZE_LARGER))
572         , m_hasTessellationStage        ((flags & FLAG_TESSELLATION) != 0)
573         , m_hasGeometryStage            ((flags & FLAG_GEOMETRY) != 0)
574         , m_useGlobalState                      ((flags & FLAG_SET_BBOX_STATE) != 0)
575         , m_calcPerPrimitiveBBox        ((flags & FLAG_PER_PRIMITIVE_BBOX) != 0)
576         , m_numIterations                       (numIterations)
577         , m_iteration                           (0)
578 {
579         // validate flags
580         DE_ASSERT((((m_renderTarget == RENDERTARGET_DEFAULT)    ?       (FLAG_RENDERTARGET_DEFAULT)     : (0)) |
581                            ((m_renderTarget == RENDERTARGET_FBO)                ?       (FLAG_RENDERTARGET_FBO)         : (0)) |
582                            ((m_bboxSize == BBOXSIZE_EQUAL)                              ?       (FLAG_BBOXSIZE_EQUAL)           : (0)) |
583                            ((m_bboxSize == BBOXSIZE_LARGER)                             ?       (FLAG_BBOXSIZE_LARGER)          : (0)) |
584                            ((m_bboxSize == BBOXSIZE_SMALLER)                    ?       (FLAG_BBOXSIZE_SMALLER)         : (0)) |
585                            ((m_hasTessellationStage)                                    ?       (FLAG_TESSELLATION)                     : (0)) |
586                            ((m_hasGeometryStage)                                                ?       (FLAG_GEOMETRY)                         : (0)) |
587                            ((m_useGlobalState)                                                  ?       (FLAG_SET_BBOX_STATE)           : (0)) |
588                            ((!m_useGlobalState)                                                 ?       (FLAG_SET_BBOX_OUTPUT)          : (0)) |
589                            ((m_calcPerPrimitiveBBox)                                    ?       (FLAG_PER_PRIMITIVE_BBOX)       : (0))) == (flags & ((1u << FLAGBIT_USER_BIT) - 1)));
590
591         DE_ASSERT(m_useGlobalState || m_hasTessellationStage); // using non-global state requires tessellation
592
593         if (m_calcPerPrimitiveBBox)
594         {
595                 DE_ASSERT(!m_useGlobalState); // per-primitive test requires per-primitive (non-global) state
596                 DE_ASSERT(m_bboxSize == BBOXSIZE_EQUAL); // smaller is hard to verify, larger not interesting
597         }
598 }
599
600 BBoxRenderCase::~BBoxRenderCase (void)
601 {
602         deinit();
603 }
604
605 void BBoxRenderCase::init (void)
606 {
607         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
608         const tcu::IVec2                renderTargetSize        = (m_renderTarget == RENDERTARGET_DEFAULT) ?
609                                                                                                         (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight())) :
610                                                                                                         (tcu::IVec2(FBO_SIZE, FBO_SIZE));
611
612         // requirements
613         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_primitive_bounding_box"))
614                 throw tcu::NotSupportedError("Test requires GL_EXT_primitive_bounding_box extension");
615         if (m_hasTessellationStage && !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
616                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
617         if (m_hasGeometryStage && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
618                 throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
619         if (m_renderTarget == RENDERTARGET_DEFAULT && (renderTargetSize.x() < RENDER_TARGET_MIN_SIZE || renderTargetSize.y() < RENDER_TARGET_MIN_SIZE))
620                 throw tcu::NotSupportedError(std::string() + "Test requires " + de::toString<int>(RENDER_TARGET_MIN_SIZE) + "x" + de::toString<int>(RENDER_TARGET_MIN_SIZE) + " default framebuffer");
621
622         // log case specifics
623         m_testCtx.getLog()
624                 << tcu::TestLog::Message
625                 << "Setting primitive bounding box "
626                         << ((m_calcPerPrimitiveBBox)         ? ("to exactly cover each generated primitive")
627                           : (m_bboxSize == BBOXSIZE_EQUAL)   ? ("to exactly cover rendered grid")
628                           : (m_bboxSize == BBOXSIZE_LARGER)  ? ("to cover the grid and include some padding")
629                           : (m_bboxSize == BBOXSIZE_SMALLER) ? ("to cover only a subset of the grid")
630                           : (DE_NULL))
631                         << ".\n"
632                 << "Rendering with vertex"
633                         << ((m_hasTessellationStage) ? ("-tessellation{ctrl,eval}") : (""))
634                         << ((m_hasGeometryStage) ? ("-geometry") : (""))
635                         << "-fragment program.\n"
636                 << "Set bounding box using "
637                         << ((m_useGlobalState) ? ("PRIMITIVE_BOUNDING_BOX_EXT state") : ("gl_BoundingBoxEXT output"))
638                         << "\n"
639                 << "Verifying rendering results are valid within the bounding box."
640                 << tcu::TestLog::EndMessage;
641
642         // resources
643
644         {
645                 glu::ProgramSources sources;
646                 sources << glu::VertexSource(genVertexSource());
647                 sources << glu::FragmentSource(genFragmentSource());
648
649                 if (m_hasTessellationStage)
650                         sources << glu::TessellationControlSource(genTessellationControlSource())
651                                         << glu::TessellationEvaluationSource(genTessellationEvaluationSource());
652                 if (m_hasGeometryStage)
653                         sources << glu::GeometrySource(genGeometrySource());
654
655                 m_program = de::MovePtr<glu::ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(), sources));
656                 GLU_EXPECT_NO_ERROR(gl.getError(), "build program");
657
658                 {
659                         const tcu::ScopedLogSection section(m_testCtx.getLog(), "ShaderProgram", "Shader program");
660                         m_testCtx.getLog() << *m_program;
661                 }
662
663                 if (!m_program->isOk())
664                         throw tcu::TestError("failed to build program");
665         }
666
667         if (m_renderTarget == RENDERTARGET_FBO)
668         {
669                 glu::Texture colorAttachment(m_context.getRenderContext());
670
671                 gl.bindTexture(GL_TEXTURE_2D, *colorAttachment);
672                 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, FBO_SIZE, FBO_SIZE);
673                 GLU_EXPECT_NO_ERROR(gl.getError(), "gen tex");
674
675                 m_fbo = de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(m_context.getRenderContext()));
676                 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo);
677                 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *colorAttachment, 0);
678                 GLU_EXPECT_NO_ERROR(gl.getError(), "attach");
679
680                 // unbind to prevent texture name deletion from removing it from current fbo attachments
681                 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
682         }
683
684         {
685                 std::vector<tcu::Vec4> data;
686
687                 getAttributeData(data);
688
689                 m_vbo = de::MovePtr<glu::Buffer>(new glu::Buffer(m_context.getRenderContext()));
690                 gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
691                 gl.bufferData(GL_ARRAY_BUFFER, (int)(data.size() * sizeof(tcu::Vec4)), &data[0], GL_STATIC_DRAW);
692                 GLU_EXPECT_NO_ERROR(gl.getError(), "create vbo");
693         }
694
695         // Iterations
696         for (int iterationNdx = 0; iterationNdx < m_numIterations; ++iterationNdx)
697                 m_iterationConfigs.push_back(generateConfig(iterationNdx, renderTargetSize));
698 }
699
700 void BBoxRenderCase::deinit (void)
701 {
702         m_program.clear();
703         m_vbo.clear();
704         m_fbo.clear();
705 }
706
707 BBoxRenderCase::IterateResult BBoxRenderCase::iterate (void)
708 {
709         const tcu::ScopedLogSection     section         (m_testCtx.getLog(),
710                                                                                          std::string() + "Iteration" + de::toString((int)m_iteration),
711                                                                                          std::string() + "Iteration " + de::toString((int)m_iteration+1) + "/" + de::toString((int)m_iterationConfigs.size()));
712         const IterationConfig&          config          = m_iterationConfigs[m_iteration];
713
714         // default
715         if (m_iteration == 0)
716                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
717
718         renderTestPattern(config);
719         verifyRenderResult(config);
720
721         if (++m_iteration < (int)m_iterationConfigs.size())
722                 return CONTINUE;
723
724         return STOP;
725 }
726
727 BBoxRenderCase::IterationConfig BBoxRenderCase::generateRandomConfig (int seed, const tcu::IVec2& renderTargetSize) const
728 {
729         de::Random              rnd             (seed);
730         IterationConfig config;
731
732         // viewport config
733         config.viewportSize.x() = rnd.getInt(MIN_VIEWPORT_SIZE, de::min<int>(renderTargetSize.x(), MAX_VIEWPORT_SIZE));
734         config.viewportSize.y() = rnd.getInt(MIN_VIEWPORT_SIZE, de::min<int>(renderTargetSize.y(), MAX_VIEWPORT_SIZE));
735         config.viewportPos.x()  = rnd.getInt(0, renderTargetSize.x() - config.viewportSize.x());
736         config.viewportPos.y()  = rnd.getInt(0, renderTargetSize.y() - config.viewportSize.y());
737
738         // pattern location inside viewport
739         config.patternSize.x()  = rnd.getFloat(0.4f, 1.4f);
740         config.patternSize.y()  = rnd.getFloat(0.4f, 1.4f);
741         config.patternPos.x()   = rnd.getFloat(-1.0f, 1.0f - config.patternSize.x());
742         config.patternPos.y()   = rnd.getFloat(-1.0f, 1.0f - config.patternSize.y());
743
744         // accurate bounding box
745         config.bbox.min                 = tcu::Vec4(config.patternPos.x(), config.patternPos.y(), 0.0f, 1.0f);
746         config.bbox.max                 = tcu::Vec4(config.patternPos.x() + config.patternSize.x(), config.patternPos.y() + config.patternSize.y(), 0.0f, 1.0f);
747
748         if (m_bboxSize == BBOXSIZE_LARGER)
749         {
750                 // increase bbox size
751                 config.bbox.min.x() -= rnd.getFloat() * 0.5f;
752                 config.bbox.min.y() -= rnd.getFloat() * 0.5f;
753                 config.bbox.min.z() -= rnd.getFloat() * 0.5f;
754
755                 config.bbox.max.x() += rnd.getFloat() * 0.5f;
756                 config.bbox.max.y() += rnd.getFloat() * 0.5f;
757                 config.bbox.max.z() += rnd.getFloat() * 0.5f;
758         }
759         else if (m_bboxSize == BBOXSIZE_SMALLER)
760         {
761                 // reduce bbox size
762                 config.bbox.min.x() += rnd.getFloat() * 0.4f * config.patternSize.x();
763                 config.bbox.min.y() += rnd.getFloat() * 0.4f * config.patternSize.y();
764
765                 config.bbox.max.x() -= rnd.getFloat() * 0.4f * config.patternSize.x();
766                 config.bbox.max.y() -= rnd.getFloat() * 0.4f * config.patternSize.y();
767         }
768
769         return config;
770 }
771
772 tcu::IVec4 BBoxRenderCase::getViewportPatternArea (const tcu::Vec2& patternPos, const tcu::Vec2& patternSize, const tcu::IVec2& viewportSize, AABBRoundDirection roundDir) const
773 {
774         const float     halfPixel       = 0.5f;
775         tcu::Vec4       vertexBox;
776         tcu::IVec4      pixelBox;
777
778         vertexBox.x() = (patternPos.x() * 0.5f + 0.5f) * viewportSize.x();
779         vertexBox.y() = (patternPos.y() * 0.5f + 0.5f) * viewportSize.y();
780         vertexBox.z() = ((patternPos.x() + patternSize.x()) * 0.5f + 0.5f) * viewportSize.x();
781         vertexBox.w() = ((patternPos.y() + patternSize.y()) * 0.5f + 0.5f) * viewportSize.y();
782
783         if (roundDir == ROUND_INWARDS)
784         {
785                 pixelBox.x() = (int)deFloatCeil(vertexBox.x()+halfPixel);
786                 pixelBox.y() = (int)deFloatCeil(vertexBox.y()+halfPixel);
787                 pixelBox.z() = (int)deFloatFloor(vertexBox.z()-halfPixel);
788                 pixelBox.w() = (int)deFloatFloor(vertexBox.w()-halfPixel);
789         }
790         else
791         {
792                 pixelBox.x() = (int)deFloatFloor(vertexBox.x()-halfPixel);
793                 pixelBox.y() = (int)deFloatFloor(vertexBox.y()-halfPixel);
794                 pixelBox.z() = (int)deFloatCeil(vertexBox.z()+halfPixel);
795                 pixelBox.w() = (int)deFloatCeil(vertexBox.w()+halfPixel);
796         }
797
798         return pixelBox;
799 }
800
801 void BBoxRenderCase::setupRender (const IterationConfig& config)
802 {
803         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
804         const glw::GLint                posLocation                     = gl.getAttribLocation(m_program->getProgram(), "a_position");
805         const glw::GLint                colLocation                     = gl.getAttribLocation(m_program->getProgram(), "a_color");
806         const glw::GLint                posScaleLocation        = gl.getUniformLocation(m_program->getProgram(), "u_posScale");
807
808         TCU_CHECK(posLocation != -1);
809         TCU_CHECK(colLocation != -1);
810         TCU_CHECK(posScaleLocation != -1);
811
812         m_testCtx.getLog()
813                 << tcu::TestLog::Message
814                 << "Setting viewport to ("
815                         << "x: " << config.viewportPos.x() << ", "
816                         << "y: " << config.viewportPos.y() << ", "
817                         << "w: " << config.viewportSize.x() << ", "
818                         << "h: " << config.viewportSize.y() << ")\n"
819                 << "Vertex coordinates are in range:\n"
820                         << "\tx: [" << config.patternPos.x() << ", " << (config.patternPos.x() + config.patternSize.x()) << "]\n"
821                         << "\ty: [" << config.patternPos.y() << ", " << (config.patternPos.y() + config.patternSize.y()) << "]\n"
822                 << tcu::TestLog::EndMessage;
823
824         if (!m_calcPerPrimitiveBBox)
825                 m_testCtx.getLog()
826                         << tcu::TestLog::Message
827                         << "Setting primitive bounding box to:\n"
828                                 << "\t" << config.bbox.min << "\n"
829                                 << "\t" << config.bbox.max << "\n"
830                         << tcu::TestLog::EndMessage;
831
832         if (m_useGlobalState)
833                 gl.primitiveBoundingBoxEXT(config.bbox.min.x(), config.bbox.min.y(), config.bbox.min.z(), config.bbox.min.w(),
834                                                                    config.bbox.max.x(), config.bbox.max.y(), config.bbox.max.z(), config.bbox.max.w());
835         else
836                 // state is overriden by the tessellation output, set bbox to invisible area to imitiate dirty state left by application
837                 gl.primitiveBoundingBoxEXT(-2.0f, -2.0f, 0.0f, 1.0f,
838                                                                    -1.7f, -1.7f, 0.0f, 1.0f);
839
840         if (m_fbo)
841                 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo);
842
843         gl.viewport(config.viewportPos.x(), config.viewportPos.y(), config.viewportSize.x(), config.viewportSize.y());
844         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
845         gl.clear(GL_COLOR_BUFFER_BIT);
846
847         gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
848         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, (int)(VA_NUM_ATTRIB_VECS * sizeof(float[4])), (const float*)DE_NULL + 4 * VA_POS_VEC_NDX);
849         gl.vertexAttribPointer(colLocation, 4, GL_FLOAT, GL_FALSE, (int)(VA_NUM_ATTRIB_VECS * sizeof(float[4])), (const float*)DE_NULL + 4 * VA_COL_VEC_NDX);
850         gl.enableVertexAttribArray(posLocation);
851         gl.enableVertexAttribArray(colLocation);
852         gl.useProgram(m_program->getProgram());
853         gl.uniform4f(posScaleLocation, config.patternPos.x(), config.patternPos.y(), config.patternSize.x(), config.patternSize.y());
854
855         {
856                 const glw::GLint bboxMinPos = gl.getUniformLocation(m_program->getProgram(), "u_primitiveBBoxMin");
857                 const glw::GLint bboxMaxPos = gl.getUniformLocation(m_program->getProgram(), "u_primitiveBBoxMax");
858
859                 gl.uniform4f(bboxMinPos, config.bbox.min.x(), config.bbox.min.y(), config.bbox.min.z(), config.bbox.min.w());
860                 gl.uniform4f(bboxMaxPos, config.bbox.max.x(), config.bbox.max.y(), config.bbox.max.z(), config.bbox.max.w());
861         }
862
863         gl.uniform2i(gl.getUniformLocation(m_program->getProgram(), "u_viewportPos"), config.viewportPos.x(), config.viewportPos.y());
864         gl.uniform2i(gl.getUniformLocation(m_program->getProgram(), "u_viewportSize"), config.viewportSize.x(), config.viewportSize.y());
865
866         GLU_EXPECT_NO_ERROR(gl.getError(), "setup");
867 }
868
869 const char* BBoxRenderCase::genShaderFunction (ShaderFunction func) const
870 {
871         switch (func)
872         {
873                 case SHADER_FUNC_MIRROR_X:
874                         return  "vec4 mirrorX(in highp vec4 p)\n"
875                                         "{\n"
876                                         "       highp vec2 patternOffset = u_posScale.xy;\n"
877                                         "       highp vec2 patternScale = u_posScale.zw;\n"
878                                         "       highp vec2 patternCenter = patternOffset + patternScale * 0.5;\n"
879                                         "       return vec4(2.0 * patternCenter.x - p.x, p.y, p.z, p.w);\n"
880                                         "}\n";
881
882                 case SHADER_FUNC_MIRROR_Y:
883                         return  "vec4 mirrorY(in highp vec4 p)\n"
884                                         "{\n"
885                                         "       highp vec2 patternOffset = u_posScale.xy;\n"
886                                         "       highp vec2 patternScale = u_posScale.zw;\n"
887                                         "       highp vec2 patternCenter = patternOffset + patternScale * 0.5;\n"
888                                         "       return vec4(p.x, 2.0 * patternCenter.y - p.y, p.z, p.w);\n"
889                                         "}\n";
890
891                 case SHADER_FUNC_INSIDE_BBOX:
892                         return  "uniform highp ivec2 u_viewportPos;\n"
893                                         "uniform highp ivec2 u_viewportSize;\n"
894                                         "flat in highp float v_bbox_expansionSize;\n"
895                                         "flat in highp vec3 v_bbox_clipMin;\n"
896                                         "flat in highp vec3 v_bbox_clipMax;\n"
897                                         "\n"
898                                         "bool fragmentInsideTheBBox(in highp float depth)\n"
899                                         "{\n"
900                                         "       highp vec4 wc = vec4(floor((v_bbox_clipMin.x * 0.5 + 0.5) * float(u_viewportSize.x) - v_bbox_expansionSize/2.0),\n"
901                                         "                            floor((v_bbox_clipMin.y * 0.5 + 0.5) * float(u_viewportSize.y) - v_bbox_expansionSize/2.0),\n"
902                                         "                            ceil((v_bbox_clipMax.x * 0.5 + 0.5) * float(u_viewportSize.x) + v_bbox_expansionSize/2.0),\n"
903                                         "                            ceil((v_bbox_clipMax.y * 0.5 + 0.5) * float(u_viewportSize.y) + v_bbox_expansionSize/2.0));\n"
904                                         "       if (gl_FragCoord.x < float(u_viewportPos.x) + wc.x || gl_FragCoord.x > float(u_viewportPos.x) + wc.z ||\n"
905                                         "           gl_FragCoord.y < float(u_viewportPos.y) + wc.y || gl_FragCoord.y > float(u_viewportPos.y) + wc.w)\n"
906                                         "           return false;\n"
907                                         "       const highp float dEpsilon = 0.001;\n"
908                                         "       if (depth*2.0-1.0 < v_bbox_clipMin.z - dEpsilon || depth*2.0-1.0 > v_bbox_clipMax.z + dEpsilon)\n"
909                                         "           return false;\n"
910                                         "       return true;\n"
911                                         "}\n";
912                 default:
913                         DE_ASSERT(false);
914                         return "";
915         }
916 }
917
918 class GridRenderCase : public BBoxRenderCase
919 {
920 public:
921                                         GridRenderCase                                  (Context& context, const char* name, const char* description, deUint32 flags);
922                                         ~GridRenderCase                                 (void);
923
924 private:
925         void                    init                                                    (void);
926
927         std::string             genVertexSource                                 (void) const;
928         std::string             genFragmentSource                               (void) const;
929         std::string             genTessellationControlSource    (void) const;
930         std::string             genTessellationEvaluationSource (void) const;
931         std::string             genGeometrySource                               (void) const;
932
933         IterationConfig generateConfig                                  (int iteration, const tcu::IVec2& renderTargetSize) const;
934         void                    getAttributeData                                (std::vector<tcu::Vec4>& data) const;
935         void                    renderTestPattern                               (const IterationConfig& config);
936         void                    verifyRenderResult                              (const IterationConfig& config);
937
938         const int               m_gridSize;
939 };
940
941 GridRenderCase::GridRenderCase (Context& context, const char* name, const char* description, deUint32 flags)
942         : BBoxRenderCase        (context, name, description, 12, flags)
943         , m_gridSize            (24)
944 {
945 }
946
947 GridRenderCase::~GridRenderCase (void)
948 {
949 }
950
951 void GridRenderCase::init (void)
952 {
953         m_testCtx.getLog()
954                 << tcu::TestLog::Message
955                 << "Rendering yellow-green grid to " << ((m_renderTarget == RENDERTARGET_DEFAULT) ? ("default frame buffer") : ("fbo")) << ".\n"
956                 << "Grid cells are in random order, varying grid size and location for each iteration.\n"
957                 << "Marking all discardable fragments (fragments outside the bounding box) with a fully saturated blue channel."
958                 << tcu::TestLog::EndMessage;
959
960         BBoxRenderCase::init();
961 }
962
963 std::string GridRenderCase::genVertexSource (void) const
964 {
965         std::ostringstream      buf;
966
967         buf <<  "#version 310 es\n"
968                         "in highp vec4 a_position;\n"
969                         "in highp vec4 a_color;\n"
970                         "out highp vec4 vtx_color;\n"
971                         "uniform highp vec4 u_posScale;\n"
972                         "\n";
973         if (!m_hasTessellationStage)
974         {
975                 DE_ASSERT(m_useGlobalState);
976                 buf <<  "uniform highp vec4 u_primitiveBBoxMin;\n"
977                                 "uniform highp vec4 u_primitiveBBoxMax;\n"
978                                 "\n"
979                                 "flat out highp float v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize;\n"
980                                 "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin;\n"
981                                 "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax;\n"
982                                 "\n";
983         }
984
985         buf <<  "void main()\n"
986                         "{\n"
987                         "       highp vec2 patternOffset = u_posScale.xy;\n"
988                         "       highp vec2 patternScale = u_posScale.zw;\n"
989                         "       gl_Position = vec4(a_position.xy * patternScale + patternOffset, a_position.z, a_position.w);\n"
990                         "       vtx_color = a_color;\n";
991
992         if (!m_hasTessellationStage)
993         {
994                 DE_ASSERT(m_useGlobalState);
995                 buf <<  "\n"
996                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize = 0.0;\n"
997                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin =\n"
998                                 "           min(vec3(u_primitiveBBoxMin.x, u_primitiveBBoxMin.y, u_primitiveBBoxMin.z) / u_primitiveBBoxMin.w,\n"
999                                 "               vec3(u_primitiveBBoxMin.x, u_primitiveBBoxMin.y, u_primitiveBBoxMin.z) / u_primitiveBBoxMax.w);\n"
1000                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax =\n"
1001                                 "           min(vec3(u_primitiveBBoxMax.x, u_primitiveBBoxMax.y, u_primitiveBBoxMax.z) / u_primitiveBBoxMin.w,\n"
1002                                 "               vec3(u_primitiveBBoxMax.x, u_primitiveBBoxMax.y, u_primitiveBBoxMax.z) / u_primitiveBBoxMax.w);\n";
1003         }
1004
1005         buf<<   "}\n";
1006
1007         return buf.str();
1008 }
1009
1010 std::string GridRenderCase::genFragmentSource (void) const
1011 {
1012         const char* const       colorInputName = (m_hasGeometryStage) ? ("geo_color") : (m_hasTessellationStage) ? ("tess_color") : ("vtx_color");
1013         std::ostringstream      buf;
1014
1015         buf <<  "#version 310 es\n"
1016                         "in mediump vec4 " << colorInputName << ";\n"
1017                         "layout(location = 0) out mediump vec4 o_color;\n"
1018                 <<      genShaderFunction(SHADER_FUNC_INSIDE_BBOX)
1019                 <<      "\n"
1020                         "void main()\n"
1021                         "{\n"
1022                         "       mediump vec4 baseColor = " << colorInputName << ";\n"
1023                         "       mediump float blueChannel;\n"
1024                         "       if (fragmentInsideTheBBox(gl_FragCoord.z))\n"
1025                         "               blueChannel = 0.0;\n"
1026                         "       else\n"
1027                         "               blueChannel = 1.0;\n"
1028                         "       o_color = vec4(baseColor.r, baseColor.g, blueChannel, baseColor.a);\n"
1029                         "}\n";
1030
1031         return buf.str();
1032 }
1033
1034 std::string GridRenderCase::genTessellationControlSource (void) const
1035 {
1036         std::ostringstream      buf;
1037
1038         buf <<  "#version 310 es\n"
1039                         "#extension GL_EXT_tessellation_shader : require\n"
1040                         "#extension GL_EXT_primitive_bounding_box : require\n"
1041                         "layout(vertices=3) out;\n"
1042                         "\n"
1043                         "in highp vec4 vtx_color[];\n"
1044                         "out highp vec4 tess_ctrl_color[];\n"
1045                         "uniform highp float u_tessellationLevel;\n"
1046                         "uniform highp vec4 u_posScale;\n";
1047
1048         if (!m_calcPerPrimitiveBBox)
1049         {
1050                 buf <<  "uniform highp vec4 u_primitiveBBoxMin;\n"
1051                                 "uniform highp vec4 u_primitiveBBoxMax;\n";
1052         }
1053
1054         buf <<  "patch out highp float vp_bbox_expansionSize;\n"
1055                         "patch out highp vec3 vp_bbox_clipMin;\n"
1056                         "patch out highp vec3 vp_bbox_clipMax;\n";
1057
1058         if (m_calcPerPrimitiveBBox)
1059         {
1060                 buf <<  "\n";
1061                 if (m_hasGeometryStage)
1062                         buf << genShaderFunction(SHADER_FUNC_MIRROR_X);
1063                 buf << genShaderFunction(SHADER_FUNC_MIRROR_Y);
1064
1065                 buf <<  "vec4 transformVec(in highp vec4 p)\n"
1066                                 "{\n"
1067                                 "       return " << ((m_hasGeometryStage) ? ("mirrorX(mirrorY(p))") : ("mirrorY(p)")) << ";\n"
1068                                 "}\n";
1069         }
1070
1071         buf <<  "\n"
1072                         "void main()\n"
1073                         "{\n"
1074                         "       // convert to nonsensical coordinates, just in case\n"
1075                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position.wzxy;\n"
1076                         "       tess_ctrl_color[gl_InvocationID] = vtx_color[gl_InvocationID];\n"
1077                         "\n"
1078                         "       gl_TessLevelOuter[0] = u_tessellationLevel;\n"
1079                         "       gl_TessLevelOuter[1] = u_tessellationLevel;\n"
1080                         "       gl_TessLevelOuter[2] = u_tessellationLevel;\n"
1081                         "       gl_TessLevelInner[0] = u_tessellationLevel;\n";
1082
1083         if (m_calcPerPrimitiveBBox)
1084         {
1085                 buf <<  "\n"
1086                                 "       highp vec4 bboxMin = min(min(transformVec(gl_in[0].gl_Position),\n"
1087                                 "                                    transformVec(gl_in[1].gl_Position)),\n"
1088                                 "                                transformVec(gl_in[2].gl_Position));\n"
1089                                 "       highp vec4 bboxMax = max(max(transformVec(gl_in[0].gl_Position),\n"
1090                                 "                                    transformVec(gl_in[1].gl_Position)),\n"
1091                                 "                                transformVec(gl_in[2].gl_Position));\n";
1092         }
1093         else
1094         {
1095                 buf <<  "\n"
1096                                 "       highp vec4 bboxMin = u_primitiveBBoxMin;\n"
1097                                 "       highp vec4 bboxMax = u_primitiveBBoxMax;\n";
1098         }
1099
1100         if (!m_useGlobalState)
1101                 buf <<  "\n"
1102                                 "       gl_BoundingBoxEXT[0] = bboxMin;\n"
1103                                 "       gl_BoundingBoxEXT[1] = bboxMax;\n";
1104
1105         buf <<  "       vp_bbox_expansionSize = 0.0;\n"
1106                         "       vp_bbox_clipMin = min(vec3(bboxMin.x, bboxMin.y, bboxMin.z) / bboxMin.w,\n"
1107                         "                             vec3(bboxMin.x, bboxMin.y, bboxMin.z) / bboxMax.w);\n"
1108                         "       vp_bbox_clipMax = max(vec3(bboxMax.x, bboxMax.y, bboxMax.z) / bboxMin.w,\n"
1109                         "                             vec3(bboxMax.x, bboxMax.y, bboxMax.z) / bboxMax.w);\n"
1110                         "}\n";
1111
1112         return buf.str();
1113 }
1114
1115 std::string GridRenderCase::genTessellationEvaluationSource (void) const
1116 {
1117         std::ostringstream      buf;
1118
1119         buf <<  "#version 310 es\n"
1120                         "#extension GL_EXT_tessellation_shader : require\n"
1121                         "#extension GL_EXT_gpu_shader5 : require\n"
1122                         "layout(triangles) in;\n"
1123                         "\n"
1124                         "in highp vec4 tess_ctrl_color[];\n"
1125                         "out highp vec4 tess_color;\n"
1126                         "uniform highp vec4 u_posScale;\n"
1127                         "patch in highp float vp_bbox_expansionSize;\n"
1128                         "patch in highp vec3 vp_bbox_clipMin;\n"
1129                         "patch in highp vec3 vp_bbox_clipMax;\n"
1130                         "flat out highp float v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize;\n"
1131                         "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin;\n"
1132                         "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax;\n"
1133                         "\n"
1134                         "precise gl_Position;\n"
1135                         "\n"
1136                 <<      genShaderFunction(SHADER_FUNC_MIRROR_Y)
1137                 <<      "void main()\n"
1138                         "{\n"
1139                         "       // non-trivial tessellation evaluation shader, convert from nonsensical coords, flip vertically\n"
1140                         "       gl_Position = mirrorY(gl_TessCoord.x * gl_in[0].gl_Position.zwyx +\n"
1141                         "                             gl_TessCoord.y * gl_in[1].gl_Position.zwyx +\n"
1142                         "                             gl_TessCoord.z * gl_in[2].gl_Position.zwyx);\n"
1143                         "       tess_color = tess_ctrl_color[0];\n"
1144                         "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize = vp_bbox_expansionSize;\n"
1145                         "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin = vp_bbox_clipMin;\n"
1146                         "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax = vp_bbox_clipMax;\n"
1147                         "}\n";
1148
1149         return buf.str();
1150 }
1151
1152 std::string GridRenderCase::genGeometrySource (void) const
1153 {
1154         const char* const       colorInputName = (m_hasTessellationStage) ? ("tess_color") : ("vtx_color");
1155         std::ostringstream      buf;
1156
1157         buf <<  "#version 310 es\n"
1158                         "#extension GL_EXT_geometry_shader : require\n"
1159                         "layout(triangles) in;\n"
1160                         "layout(max_vertices=9, triangle_strip) out;\n"
1161                         "\n"
1162                         "in highp vec4 " << colorInputName << "[3];\n"
1163                         "out highp vec4 geo_color;\n"
1164                         "uniform highp vec4 u_posScale;\n"
1165                         "\n"
1166                         "flat in highp float v_geo_bbox_expansionSize[3];\n"
1167                         "flat in highp vec3 v_geo_bbox_clipMin[3];\n"
1168                         "flat in highp vec3 v_geo_bbox_clipMax[3];\n"
1169                         "flat out highp vec3 v_bbox_clipMin;\n"
1170                         "flat out highp vec3 v_bbox_clipMax;\n"
1171                         "flat out highp float v_bbox_expansionSize;\n"
1172                 <<      genShaderFunction(SHADER_FUNC_MIRROR_X)
1173                 <<      "\n"
1174                         "void setVisualizationVaryings()\n"
1175                         "{\n"
1176                         "       v_bbox_expansionSize = v_geo_bbox_expansionSize[0];\n"
1177                         "       v_bbox_clipMin = v_geo_bbox_clipMin[0];\n"
1178                         "       v_bbox_clipMax = v_geo_bbox_clipMax[0];\n"
1179                         "}\n"
1180                         "void main()\n"
1181                         "{\n"
1182                         "       // Non-trivial geometry shader: 1-to-3 amplification, mirror horizontally\n"
1183                         "       highp vec4 p0 = mirrorX(gl_in[0].gl_Position);\n"
1184                         "       highp vec4 p1 = mirrorX(gl_in[1].gl_Position);\n"
1185                         "       highp vec4 p2 = mirrorX(gl_in[2].gl_Position);\n"
1186                         "       highp vec4 pCentroid = vec4((p0.xyz + p1.xyz + p2.xyz) / 3.0, 1.0);\n"
1187                         "       highp vec4 triangleColor = " << colorInputName << "[0];\n"
1188                         "\n"
1189                         "       gl_Position = p0; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1190                         "       gl_Position = p1; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1191                         "       gl_Position = pCentroid; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1192                         "       EndPrimitive();\n"
1193                         "\n"
1194                         "       gl_Position = p1; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1195                         "       gl_Position = p2; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1196                         "       gl_Position = pCentroid; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1197                         "       EndPrimitive();\n"
1198                         "\n"
1199                         "       gl_Position = p2; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1200                         "       gl_Position = p0; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1201                         "       gl_Position = pCentroid; geo_color = triangleColor; setVisualizationVaryings(); EmitVertex();\n"
1202                         "       EndPrimitive();\n"
1203                         "}\n";
1204
1205         return buf.str();
1206 }
1207
1208 GridRenderCase::IterationConfig GridRenderCase::generateConfig (int iteration, const tcu::IVec2& renderTargetSize) const
1209 {
1210         return generateRandomConfig(0xDEDEDEu * (deUint32)iteration, renderTargetSize);
1211 }
1212
1213 void GridRenderCase::getAttributeData (std::vector<tcu::Vec4>& data) const
1214 {
1215         const tcu::Vec4         green                           (0.0f, 1.0f, 0.0f, 1.0f);
1216         const tcu::Vec4         yellow                          (1.0f, 1.0f, 0.0f, 1.0f);
1217         std::vector<int>        cellOrder                       (m_gridSize * m_gridSize);
1218         de::Random                      rnd                                     (0xDE56789);
1219
1220         // generate grid with cells in random order
1221         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
1222                 cellOrder[ndx] = ndx;
1223         rnd.shuffle(cellOrder.begin(), cellOrder.end());
1224
1225         data.resize(m_gridSize * m_gridSize * 6 * 2);
1226         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
1227         {
1228                 const int                       cellNdx         = cellOrder[ndx];
1229                 const int                       cellX           = cellNdx % m_gridSize;
1230                 const int                       cellY           = cellNdx / m_gridSize;
1231                 const tcu::Vec4&        cellColor       = ((cellX+cellY)%2 == 0) ? (green) : (yellow);
1232
1233                 data[(ndx * 6 + 0) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((cellX+0) / float(m_gridSize), (cellY+0) / float(m_gridSize), 0.0f, 1.0f);
1234                 data[(ndx * 6 + 0) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = cellColor;
1235                 data[(ndx * 6 + 1) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((cellX+1) / float(m_gridSize), (cellY+1) / float(m_gridSize), 0.0f, 1.0f);
1236                 data[(ndx * 6 + 1) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = cellColor;
1237                 data[(ndx * 6 + 2) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((cellX+0) / float(m_gridSize), (cellY+1) / float(m_gridSize), 0.0f, 1.0f);
1238                 data[(ndx * 6 + 2) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = cellColor;
1239                 data[(ndx * 6 + 3) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((cellX+0) / float(m_gridSize), (cellY+0) / float(m_gridSize), 0.0f, 1.0f);
1240                 data[(ndx * 6 + 3) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = cellColor;
1241                 data[(ndx * 6 + 4) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((cellX+1) / float(m_gridSize), (cellY+0) / float(m_gridSize), 0.0f, 1.0f);
1242                 data[(ndx * 6 + 4) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = cellColor;
1243                 data[(ndx * 6 + 5) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((cellX+1) / float(m_gridSize), (cellY+1) / float(m_gridSize), 0.0f, 1.0f);
1244                 data[(ndx * 6 + 5) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = cellColor;
1245         }
1246 }
1247
1248 void GridRenderCase::renderTestPattern (const IterationConfig& config)
1249 {
1250         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1251
1252         setupRender(config);
1253
1254         if (m_hasTessellationStage)
1255         {
1256                 const glw::GLint        tessLevelPos    = gl.getUniformLocation(m_program->getProgram(), "u_tessellationLevel");
1257                 const glw::GLfloat      tessLevel               = 2.8f; // will be rounded up
1258
1259                 TCU_CHECK(tessLevelPos != -1);
1260
1261                 m_testCtx.getLog() << tcu::TestLog::Message << "u_tessellationLevel = " << tessLevel << tcu::TestLog::EndMessage;
1262
1263                 gl.uniform1f(tessLevelPos, tessLevel);
1264                 gl.patchParameteri(GL_PATCH_VERTICES, 3);
1265                 GLU_EXPECT_NO_ERROR(gl.getError(), "patch param");
1266         }
1267
1268         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering grid." << tcu::TestLog::EndMessage;
1269
1270         gl.drawArrays((m_hasTessellationStage) ? (GL_PATCHES) : (GL_TRIANGLES), 0, m_gridSize * m_gridSize * 6);
1271         GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1272 }
1273
1274 void GridRenderCase::verifyRenderResult (const IterationConfig& config)
1275 {
1276         const glw::Functions&   gl                                              = m_context.getRenderContext().getFunctions();
1277         const ProjectedBBox             projectedBBox                   = projectBoundingBox(config.bbox);
1278         const tcu::IVec4                viewportBBoxArea                = getViewportBoundingBoxArea(projectedBBox, config.viewportSize);
1279         const tcu::IVec4                viewportGridOuterArea   = getViewportPatternArea(config.patternPos, config.patternSize, config.viewportSize, ROUND_OUTWARDS);
1280         const tcu::IVec4                viewportGridInnerArea   = getViewportPatternArea(config.patternPos, config.patternSize, config.viewportSize, ROUND_INWARDS);
1281         tcu::Surface                    viewportSurface                 (config.viewportSize.x(), config.viewportSize.y());
1282         tcu::Surface                    errorMask                               (config.viewportSize.x(), config.viewportSize.y());
1283         bool                                    anyError                                = false;
1284
1285         if (!m_calcPerPrimitiveBBox)
1286                 m_testCtx.getLog()
1287                         << tcu::TestLog::Message
1288                         << "Projected bounding box: (clip space)\n"
1289                                 << "\tx: [" << projectedBBox.min.x() << "," << projectedBBox.max.x() << "]\n"
1290                                 << "\ty: [" << projectedBBox.min.y() << "," << projectedBBox.max.y() << "]\n"
1291                                 << "\tz: [" << projectedBBox.min.z() << "," << projectedBBox.max.z() << "]\n"
1292                         << "In viewport coordinates:\n"
1293                                 << "\tx: [" << viewportBBoxArea.x() << ", " << viewportBBoxArea.z() << "]\n"
1294                                 << "\ty: [" << viewportBBoxArea.y() << ", " << viewportBBoxArea.w() << "]\n"
1295                         << "Verifying render results within the bounding box.\n"
1296                         << tcu::TestLog::EndMessage;
1297         else
1298                 m_testCtx.getLog()
1299                         << tcu::TestLog::Message
1300                         << "Verifying render result."
1301                         << tcu::TestLog::EndMessage;
1302
1303         if (m_fbo)
1304                 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
1305         glu::readPixels(m_context.getRenderContext(), config.viewportPos.x(), config.viewportPos.y(), viewportSurface.getAccess());
1306
1307         tcu::clear(errorMask.getAccess(), tcu::IVec4(0,0,0,255));
1308
1309         for (int y = de::max(viewportBBoxArea.y(), 0); y < de::min(viewportBBoxArea.w(), config.viewportSize.y()); ++y)
1310         for (int x = de::max(viewportBBoxArea.x(), 0); x < de::min(viewportBBoxArea.z(), config.viewportSize.x()); ++x)
1311         {
1312                 const tcu::RGBA pixel           = viewportSurface.getPixel(x, y);
1313                 const bool              outsideGrid     = x < viewportGridOuterArea.x() ||
1314                                                                           y < viewportGridOuterArea.y() ||
1315                                                                           x > viewportGridOuterArea.z() ||
1316                                                                           y > viewportGridOuterArea.w();
1317                 const bool              insideGrid      = x > viewportGridInnerArea.x() &&
1318                                                                           y > viewportGridInnerArea.y() &&
1319                                                                           x < viewportGridInnerArea.z() &&
1320                                                                           y < viewportGridInnerArea.w();
1321
1322                 bool                    error           = false;
1323
1324                 if (outsideGrid)
1325                 {
1326                         // expect black
1327                         if (pixel.getRed() != 0 || pixel.getGreen() != 0 || pixel.getBlue() != 0)
1328                                 error = true;
1329                 }
1330
1331                 else if (insideGrid)
1332                 {
1333                         // expect green, yellow or a combination of these
1334                         if (pixel.getGreen() != 255 || pixel.getBlue() != 0)
1335                                 error = true;
1336                 }
1337                 else
1338                 {
1339                         // boundary, allow anything
1340                 }
1341
1342                 if (error)
1343                 {
1344                         errorMask.setPixel(x, y, tcu::RGBA::red);
1345                         anyError = true;
1346                 }
1347         }
1348
1349         if (anyError)
1350         {
1351                 m_testCtx.getLog()
1352                         << tcu::TestLog::Message
1353                         << "Image verification failed."
1354                         << tcu::TestLog::EndMessage
1355                         << tcu::TestLog::ImageSet("Images", "Image verification")
1356                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewportSurface.getAccess())
1357                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
1358                         << tcu::TestLog::EndImageSet;
1359
1360                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1361         }
1362         else
1363         {
1364                 m_testCtx.getLog()
1365                         << tcu::TestLog::Message
1366                         << "Result image ok."
1367                         << tcu::TestLog::EndMessage
1368                         << tcu::TestLog::ImageSet("Images", "Image verification")
1369                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewportSurface.getAccess())
1370                         << tcu::TestLog::EndImageSet;
1371         }
1372 }
1373
1374 class LineRenderCase : public BBoxRenderCase
1375 {
1376 public:
1377         enum
1378         {
1379                 LINEFLAG_WIDE = 1u << FLAGBIT_USER_BIT, //!< use wide lines
1380         };
1381
1382                                         LineRenderCase                                  (Context& context, const char* name, const char* description, deUint32 flags);
1383                                         ~LineRenderCase                                 (void);
1384
1385 private:
1386         enum
1387         {
1388                 GREEN_COMPONENT_NDX = 1,
1389                 BLUE_COMPONENT_NDX = 2,
1390
1391                 SCAN_ROW_COMPONENT_NDX = GREEN_COMPONENT_NDX, // \note: scans are orthogonal to the line
1392                 SCAN_COL_COMPONENT_NDX = BLUE_COMPONENT_NDX,
1393         };
1394
1395         enum QueryDirection
1396         {
1397                 DIRECTION_HORIZONTAL = 0,
1398                 DIRECTION_VERTICAL,
1399         };
1400
1401         void                            init                                                    (void);
1402
1403         std::string                     genVertexSource                                 (void) const;
1404         std::string                     genFragmentSource                               (void) const;
1405         std::string                     genTessellationControlSource    (void) const;
1406         std::string                     genTessellationEvaluationSource (void) const;
1407         std::string                     genGeometrySource                               (void) const;
1408
1409         IterationConfig         generateConfig                                  (int iteration, const tcu::IVec2& renderTargetSize) const;
1410         void                            getAttributeData                                (std::vector<tcu::Vec4>& data) const;
1411         void                            renderTestPattern                               (const IterationConfig& config);
1412         void                            verifyRenderResult                              (const IterationConfig& config);
1413
1414         tcu::IVec2                      getNumberOfLinesRange                   (int queryAreaBegin, int queryAreaEnd, float patternStart, float patternSize, int viewportArea, QueryDirection queryDir) const;
1415         bool                            scanRow                                                 (const tcu::ConstPixelBufferAccess& access, int row, int rowBegin, int rowEnd, const tcu::IVec2& numLines, int& floodCounter) const;
1416         bool                            scanColumn                                              (const tcu::ConstPixelBufferAccess& access, int column, int columnBegin, int columnEnd, const tcu::IVec2& numLines, int& floodCounter) const;
1417         bool                            checkAreaNumLines                               (const tcu::ConstPixelBufferAccess& access, const tcu::IVec4& area, int& floodCounter, int componentNdx, const tcu::IVec2& numLines) const;
1418         tcu::IVec2                      getNumMinimaMaxima                              (const tcu::ConstPixelBufferAccess& access, int componentNdx) const;
1419         bool                            checkLineWidths                                 (const tcu::ConstPixelBufferAccess& access, const tcu::IVec2& begin, const tcu::IVec2& end, int componentNdx, int& floodCounter) const;
1420         void                            printLineWidthError                             (const tcu::IVec2& pos, int detectedLineWidth, const tcu::IVec2& lineWidthRange, bool isHorizontal, int& floodCounter) const;
1421
1422         const int                       m_patternSide;
1423         const bool                      m_isWideLineCase;
1424         const int                       m_wideLineLineWidth;
1425 };
1426
1427 LineRenderCase::LineRenderCase (Context& context, const char* name, const char* description, deUint32 flags)
1428         : BBoxRenderCase                (context, name, description, 12, flags)
1429         , m_patternSide                 (12)
1430         , m_isWideLineCase              ((flags & LINEFLAG_WIDE) != 0)
1431         , m_wideLineLineWidth   (5)
1432 {
1433 }
1434
1435 LineRenderCase::~LineRenderCase (void)
1436 {
1437 }
1438
1439 void LineRenderCase::init (void)
1440 {
1441         m_testCtx.getLog()
1442                 << tcu::TestLog::Message
1443                 << "Rendering line pattern to " << ((m_renderTarget == RENDERTARGET_DEFAULT) ? ("default frame buffer") : ("fbo")) << ".\n"
1444                 << "Vertical lines are green, horizontal lines blue. Using additive blending.\n"
1445                 << "Line segments are in random order, varying pattern size and location for each iteration.\n"
1446                 << "Marking all discardable fragments (fragments outside the bounding box) with a fully saturated red channel."
1447                 << tcu::TestLog::EndMessage;
1448
1449         if (m_isWideLineCase)
1450         {
1451                 glw::GLfloat lineWidthRange[2] = {0.0f, 0.0f};
1452                 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, lineWidthRange);
1453
1454                 if (lineWidthRange[1] < (float)m_wideLineLineWidth)
1455                         throw tcu::NotSupportedError("Test requires line width " + de::toString(m_wideLineLineWidth));
1456         }
1457
1458         BBoxRenderCase::init();
1459 }
1460
1461 std::string LineRenderCase::genVertexSource (void) const
1462 {
1463         std::ostringstream      buf;
1464
1465         buf <<  "#version 310 es\n"
1466                         "in highp vec4 a_position;\n"
1467                         "in highp vec4 a_color;\n"
1468                         "out highp vec4 vtx_color;\n"
1469                         "uniform highp vec4 u_posScale;\n"
1470                         "uniform highp float u_lineWidth;\n"
1471                         "\n";
1472         if (!m_hasTessellationStage)
1473         {
1474                 DE_ASSERT(m_useGlobalState);
1475                 buf <<  "uniform highp vec4 u_primitiveBBoxMin;\n"
1476                                 "uniform highp vec4 u_primitiveBBoxMax;\n"
1477                                 "\n"
1478                                 "flat out highp float v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize;\n"
1479                                 "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin;\n"
1480                                 "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax;\n"
1481                                 "\n";
1482         }
1483         buf <<  "void main()\n"
1484                         "{\n"
1485                         "       highp vec2 patternOffset = u_posScale.xy;\n"
1486                         "       highp vec2 patternScale = u_posScale.zw;\n"
1487                         "       gl_Position = vec4(a_position.xy * patternScale + patternOffset, a_position.z, a_position.w);\n"
1488                         "       vtx_color = a_color;\n";
1489         if (!m_hasTessellationStage)
1490         {
1491                 DE_ASSERT(m_useGlobalState);
1492                 buf <<  "\n"
1493                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize = u_lineWidth;\n"
1494                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin =\n"
1495                                 "           min(vec3(u_primitiveBBoxMin.x, u_primitiveBBoxMin.y, u_primitiveBBoxMin.z) / u_primitiveBBoxMin.w,\n"
1496                                 "               vec3(u_primitiveBBoxMin.x, u_primitiveBBoxMin.y, u_primitiveBBoxMin.z) / u_primitiveBBoxMax.w);\n"
1497                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax =\n"
1498                                 "           min(vec3(u_primitiveBBoxMax.x, u_primitiveBBoxMax.y, u_primitiveBBoxMax.z) / u_primitiveBBoxMin.w,\n"
1499                                 "               vec3(u_primitiveBBoxMax.x, u_primitiveBBoxMax.y, u_primitiveBBoxMax.z) / u_primitiveBBoxMax.w);\n";
1500         }
1501         buf <<  "}\n";
1502
1503         return buf.str();
1504 }
1505
1506 std::string LineRenderCase::genFragmentSource (void) const
1507 {
1508         const char* const       colorInputName = (m_hasGeometryStage) ? ("geo_color") : (m_hasTessellationStage) ? ("tess_color") : ("vtx_color");
1509         std::ostringstream      buf;
1510
1511         buf <<  "#version 310 es\n"
1512                         "in mediump vec4 " << colorInputName << ";\n"
1513                         "layout(location = 0) out mediump vec4 o_color;\n"
1514                 <<      genShaderFunction(SHADER_FUNC_INSIDE_BBOX)
1515                 <<      "\n"
1516                         "void main()\n"
1517                         "{\n"
1518                         "       mediump vec4 baseColor = " << colorInputName << ";\n"
1519                         "       mediump float redChannel;\n"
1520                         "       if (fragmentInsideTheBBox(gl_FragCoord.z))\n"
1521                         "               redChannel = 0.0;\n"
1522                         "       else\n"
1523                         "               redChannel = 1.0;\n"
1524                         "       o_color = vec4(redChannel, baseColor.g, baseColor.b, baseColor.a);\n"
1525                         "}\n";
1526
1527         return buf.str();
1528 }
1529
1530 std::string LineRenderCase::genTessellationControlSource (void) const
1531 {
1532         std::ostringstream      buf;
1533
1534         buf <<  "#version 310 es\n"
1535                         "#extension GL_EXT_tessellation_shader : require\n"
1536                         "#extension GL_EXT_primitive_bounding_box : require\n"
1537                         "layout(vertices=2) out;"
1538                         "\n"
1539                         "in highp vec4 vtx_color[];\n"
1540                         "out highp vec4 tess_ctrl_color[];\n"
1541                         "uniform highp float u_tessellationLevel;\n"
1542                         "uniform highp vec4 u_posScale;\n"
1543                         "uniform highp float u_lineWidth;\n";
1544
1545         if (!m_calcPerPrimitiveBBox)
1546         {
1547                 buf <<  "uniform highp vec4 u_primitiveBBoxMin;\n"
1548                                 "uniform highp vec4 u_primitiveBBoxMax;\n";
1549         }
1550
1551         buf <<  "patch out highp float vp_bbox_expansionSize;\n"
1552                         "patch out highp vec3 vp_bbox_clipMin;\n"
1553                         "patch out highp vec3 vp_bbox_clipMax;\n";
1554
1555         if (m_calcPerPrimitiveBBox)
1556         {
1557                 buf <<  "\n";
1558                 if (m_hasGeometryStage)
1559                         buf << genShaderFunction(SHADER_FUNC_MIRROR_X);
1560                 buf << genShaderFunction(SHADER_FUNC_MIRROR_Y);
1561
1562                 buf <<  "vec4 transformVec(in highp vec4 p)\n"
1563                                 "{\n"
1564                                 "       return " << ((m_hasGeometryStage) ? ("mirrorX(mirrorY(p))") : ("mirrorY(p)")) << ";\n"
1565                                 "}\n";
1566         }
1567
1568         buf <<  "\n"
1569                         "void main()\n"
1570                         "{\n"
1571                         "       // convert to nonsensical coordinates, just in case\n"
1572                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position.wzxy;\n"
1573                         "       tess_ctrl_color[gl_InvocationID] = vtx_color[gl_InvocationID];\n"
1574                         "\n"
1575                         "       gl_TessLevelOuter[0] = 0.8; // will be rounded up to 1\n"
1576                         "       gl_TessLevelOuter[1] = u_tessellationLevel;\n";
1577
1578         if (m_calcPerPrimitiveBBox)
1579         {
1580                 buf <<  "\n"
1581                                 "       highp vec4 bboxMin = min(transformVec(gl_in[0].gl_Position),\n"
1582                                 "                                transformVec(gl_in[1].gl_Position));\n"
1583                                 "       highp vec4 bboxMax = max(transformVec(gl_in[0].gl_Position),\n"
1584                                 "                                transformVec(gl_in[1].gl_Position));\n";
1585         }
1586         else
1587         {
1588                 buf <<  "\n"
1589                                 "       highp vec4 bboxMin = u_primitiveBBoxMin;\n"
1590                                 "       highp vec4 bboxMax = u_primitiveBBoxMax;\n";
1591         }
1592
1593         if (!m_useGlobalState)
1594                 buf <<  "\n"
1595                                 "       gl_BoundingBoxEXT[0] = bboxMin;\n"
1596                                 "       gl_BoundingBoxEXT[1] = bboxMax;\n";
1597
1598         buf <<  "       vp_bbox_expansionSize = u_lineWidth;\n"
1599                         "       vp_bbox_clipMin = min(vec3(bboxMin.x, bboxMin.y, bboxMin.z) / bboxMin.w,\n"
1600                         "                             vec3(bboxMin.x, bboxMin.y, bboxMin.z) / bboxMax.w);\n"
1601                         "       vp_bbox_clipMax = max(vec3(bboxMax.x, bboxMax.y, bboxMax.z) / bboxMin.w,\n"
1602                         "                             vec3(bboxMax.x, bboxMax.y, bboxMax.z) / bboxMax.w);\n"
1603                         "}\n";
1604
1605         return buf.str();
1606 }
1607
1608 std::string LineRenderCase::genTessellationEvaluationSource (void) const
1609 {
1610         std::ostringstream      buf;
1611
1612         buf <<  "#version 310 es\n"
1613                         "#extension GL_EXT_tessellation_shader : require\n"
1614                         "layout(isolines) in;"
1615                         "\n"
1616                         "in highp vec4 tess_ctrl_color[];\n"
1617                         "out highp vec4 tess_color;\n"
1618                         "uniform highp vec4 u_posScale;\n"
1619                         "\n"
1620                         "patch in highp float vp_bbox_expansionSize;\n"
1621                         "patch in highp vec3 vp_bbox_clipMin;\n"
1622                         "patch in highp vec3 vp_bbox_clipMax;\n"
1623                         "flat out highp float v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize;\n"
1624                         "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin;\n"
1625                         "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax;\n"
1626                 <<      genShaderFunction(SHADER_FUNC_MIRROR_Y)
1627                 <<      "void main()\n"
1628                         "{\n"
1629                         "       // non-trivial tessellation evaluation shader, convert from nonsensical coords, flip vertically\n"
1630                         "       gl_Position = mirrorY(mix(gl_in[0].gl_Position.zwyx, gl_in[1].gl_Position.zwyx, gl_TessCoord.x));\n"
1631                         "       tess_color = tess_ctrl_color[0];\n"
1632                         "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize = vp_bbox_expansionSize;\n"
1633                         "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin = vp_bbox_clipMin;\n"
1634                         "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax = vp_bbox_clipMax;\n"
1635                         "}\n";
1636
1637         return buf.str();
1638 }
1639
1640 std::string LineRenderCase::genGeometrySource (void) const
1641 {
1642         const char* const       colorInputName = (m_hasTessellationStage) ? ("tess_color") : ("vtx_color");
1643         std::ostringstream      buf;
1644
1645         buf <<  "#version 310 es\n"
1646                         "#extension GL_EXT_geometry_shader : require\n"
1647                         "layout(lines) in;\n"
1648                         "layout(max_vertices=5, line_strip) out;\n"
1649                         "\n"
1650                         "in highp vec4 " << colorInputName << "[2];\n"
1651                         "out highp vec4 geo_color;\n"
1652                         "uniform highp vec4 u_posScale;\n"
1653                         "\n"
1654                         "\n"
1655                         "flat in highp float v_geo_bbox_expansionSize[2];\n"
1656                         "flat in highp vec3 v_geo_bbox_clipMin[2];\n"
1657                         "flat in highp vec3 v_geo_bbox_clipMax[2];\n"
1658                         "flat out highp vec3 v_bbox_clipMin;\n"
1659                         "flat out highp vec3 v_bbox_clipMax;\n"
1660                         "flat out highp float v_bbox_expansionSize;\n"
1661                 <<      genShaderFunction(SHADER_FUNC_MIRROR_X)
1662                 <<      "\n"
1663                         "void setVisualizationVaryings()\n"
1664                         "{\n"
1665                         "       v_bbox_expansionSize = v_geo_bbox_expansionSize[0];\n"
1666                         "       v_bbox_clipMin = v_geo_bbox_clipMin[0];\n"
1667                         "       v_bbox_clipMax = v_geo_bbox_clipMax[0];\n"
1668                         "}\n"
1669                         "void main()\n"
1670                         "{\n"
1671                         "       // Non-trivial geometry shader: 1-to-3 amplification, mirror horizontally\n"
1672                         "       highp vec4 p0 = mirrorX(gl_in[0].gl_Position);\n"
1673                         "       highp vec4 p1 = mirrorX(gl_in[1].gl_Position);\n"
1674                         "       highp vec4 lineColor = " << colorInputName << "[0];\n"
1675                         "\n"
1676                         "       // output two separate primitives, just in case\n"
1677                         "       gl_Position = mix(p0, p1, 0.00); geo_color = lineColor; setVisualizationVaryings(); EmitVertex();\n"
1678                         "       gl_Position = mix(p0, p1, 0.33); geo_color = lineColor; setVisualizationVaryings(); EmitVertex();\n"
1679                         "       EndPrimitive();\n"
1680                         "\n"
1681                         "       gl_Position = mix(p0, p1, 0.33); geo_color = lineColor; setVisualizationVaryings(); EmitVertex();\n"
1682                         "       gl_Position = mix(p0, p1, 0.67); geo_color = lineColor; setVisualizationVaryings(); EmitVertex();\n"
1683                         "       gl_Position = mix(p0, p1, 1.00); geo_color = lineColor; setVisualizationVaryings(); EmitVertex();\n"
1684                         "       EndPrimitive();\n"
1685                         "}\n";
1686
1687         return buf.str();
1688 }
1689
1690 LineRenderCase::IterationConfig LineRenderCase::generateConfig (int iteration, const tcu::IVec2& renderTargetSize) const
1691 {
1692         const int numMaxAttempts = 128;
1693
1694         // Avoid too narrow viewports, lines could merge together. Require viewport is at least 2.5x the size of the line bodies.
1695         for (int attemptNdx = 0; attemptNdx < numMaxAttempts; ++attemptNdx)
1696         {
1697                 const IterationConfig& config = generateRandomConfig((0xDEDEDEu * (deUint32)iteration) ^ (0xABAB13 * attemptNdx), renderTargetSize);
1698
1699                 if (config.viewportSize.x() * (config.patternSize.x() * 0.5f) > 2.5f * m_patternSide * m_wideLineLineWidth &&
1700                         config.viewportSize.y() * (config.patternSize.y() * 0.5f) > 2.5f * m_patternSide * m_wideLineLineWidth)
1701                 {
1702                         return config;
1703                 }
1704         }
1705
1706         DE_ASSERT(false);
1707         return IterationConfig();
1708 }
1709
1710 void LineRenderCase::getAttributeData (std::vector<tcu::Vec4>& data) const
1711 {
1712         const tcu::Vec4         green           (0.0f, 1.0f, 0.0f, 1.0f);
1713         const tcu::Vec4         blue            (0.0f, 0.0f, 1.0f, 1.0f);
1714         std::vector<int>        cellOrder       (m_patternSide * m_patternSide * 2);
1715         de::Random                      rnd                     (0xDE12345);
1716
1717         // generate crosshatch pattern with segments in random order
1718         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
1719                 cellOrder[ndx] = ndx;
1720         rnd.shuffle(cellOrder.begin(), cellOrder.end());
1721
1722         data.resize(cellOrder.size() * 4);
1723         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
1724         {
1725                 const int segmentID             = cellOrder[ndx];
1726                 const int direction             = segmentID & 0x01;
1727                 const int majorCoord    = (segmentID >> 1) / m_patternSide;
1728                 const int minorCoord    = (segmentID >> 1) % m_patternSide;
1729
1730                 if (direction)
1731                 {
1732                         data[(ndx * 2 + 0) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4(minorCoord / float(m_patternSide), majorCoord / float(m_patternSide), 0.0f, 1.0f);
1733                         data[(ndx * 2 + 0) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = green;
1734                         data[(ndx * 2 + 1) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4(minorCoord / float(m_patternSide), (majorCoord + 1) / float(m_patternSide), 0.0f, 1.0f);
1735                         data[(ndx * 2 + 1) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = green;
1736                 }
1737                 else
1738                 {
1739                         data[(ndx * 2 + 0) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4(majorCoord / float(m_patternSide), minorCoord / float(m_patternSide), 0.0f, 1.0f);
1740                         data[(ndx * 2 + 0) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = blue;
1741                         data[(ndx * 2 + 1) * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((majorCoord + 1) / float(m_patternSide), minorCoord / float(m_patternSide), 0.0f, 1.0f);
1742                         data[(ndx * 2 + 1) * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = blue;
1743                 }
1744         }
1745 }
1746
1747 void LineRenderCase::renderTestPattern (const IterationConfig& config)
1748 {
1749         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1750
1751         setupRender(config);
1752
1753         if (m_hasTessellationStage)
1754         {
1755                 const glw::GLint        tessLevelPos    = gl.getUniformLocation(m_program->getProgram(), "u_tessellationLevel");
1756                 const glw::GLfloat      tessLevel               = 2.8f; // will be rounded up
1757
1758                 TCU_CHECK(tessLevelPos != -1);
1759
1760                 m_testCtx.getLog() << tcu::TestLog::Message << "u_tessellationLevel = " << tessLevel << tcu::TestLog::EndMessage;
1761
1762                 gl.uniform1f(tessLevelPos, tessLevel);
1763                 gl.patchParameteri(GL_PATCH_VERTICES, 2);
1764                 GLU_EXPECT_NO_ERROR(gl.getError(), "patch param");
1765         }
1766
1767         if (m_isWideLineCase)
1768                 gl.lineWidth((float)m_wideLineLineWidth);
1769
1770         gl.uniform1f(gl.getUniformLocation(m_program->getProgram(), "u_lineWidth"), (m_isWideLineCase) ? (m_wideLineLineWidth) : (1.0f));
1771
1772         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering pattern." << tcu::TestLog::EndMessage;
1773
1774         gl.enable(GL_BLEND);
1775         gl.blendFunc(GL_ONE, GL_ONE);
1776         gl.blendEquation(GL_FUNC_ADD);
1777
1778         gl.drawArrays((m_hasTessellationStage) ? (GL_PATCHES) : (GL_LINES), 0, m_patternSide * m_patternSide * 2 * 2);
1779         GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1780 }
1781
1782 void LineRenderCase::verifyRenderResult (const IterationConfig& config)
1783 {
1784         const glw::Functions&   gl                                              = m_context.getRenderContext().getFunctions();
1785         const ProjectedBBox             projectedBBox                   = projectBoundingBox(config.bbox);
1786         const float                             lineWidth                               = (m_isWideLineCase) ? (m_wideLineLineWidth) : (1.0f);
1787         const tcu::IVec4                viewportBBoxArea                = getViewportBoundingBoxArea(projectedBBox, config.viewportSize, lineWidth);
1788         const tcu::IVec4                viewportPatternArea             = getViewportPatternArea(config.patternPos, config.patternSize, config.viewportSize, ROUND_INWARDS);
1789         const tcu::IVec2                expectedHorizontalLines = getNumberOfLinesRange(viewportBBoxArea.y(), viewportBBoxArea.w(), config.patternPos.y(), config.patternSize.y(), config.viewportSize.y(), DIRECTION_VERTICAL);
1790         const tcu::IVec2                expectedVerticalLines   = getNumberOfLinesRange(viewportBBoxArea.x(), viewportBBoxArea.z(), config.patternPos.x(), config.patternSize.x(), config.viewportSize.x(), DIRECTION_HORIZONTAL);
1791         const tcu::IVec4                verificationArea                = tcu::IVec4(de::max(viewportBBoxArea.x(), 0),
1792                                                                                                                                  de::max(viewportBBoxArea.y(), 0),
1793                                                                                                                                  de::min(viewportBBoxArea.z(), config.viewportSize.x()),
1794                                                                                                                                  de::min(viewportBBoxArea.w(), config.viewportSize.y()));
1795
1796         tcu::Surface                    viewportSurface                 (config.viewportSize.x(), config.viewportSize.y());
1797         bool                                    anyError                                = false;
1798         int                                             messageLimitCounter             = 8;
1799
1800         if (!m_calcPerPrimitiveBBox)
1801                 m_testCtx.getLog()
1802                         << tcu::TestLog::Message
1803                         << "Projected bounding box: (clip space)\n"
1804                                 << "\tx: [" << projectedBBox.min.x() << "," << projectedBBox.max.x() << "]\n"
1805                                 << "\ty: [" << projectedBBox.min.y() << "," << projectedBBox.max.y() << "]\n"
1806                                 << "\tz: [" << projectedBBox.min.z() << "," << projectedBBox.max.z() << "]\n"
1807                         << "In viewport coordinates:\n"
1808                                 << "\tx: [" << viewportBBoxArea.x() << ", " << viewportBBoxArea.z() << "]\n"
1809                                 << "\ty: [" << viewportBBoxArea.y() << ", " << viewportBBoxArea.w() << "]\n"
1810                         << "Verifying render results within the bounding box:\n"
1811                         << tcu::TestLog::EndMessage;
1812         else
1813                 m_testCtx.getLog()
1814                         << tcu::TestLog::Message
1815                         << "Verifying render result:"
1816                         << tcu::TestLog::EndMessage;
1817
1818         m_testCtx.getLog()
1819                 << tcu::TestLog::Message
1820                         << "\tCalculating number of horizontal and vertical lines within the bounding box, expecting:\n"
1821                         << "\t[" << expectedHorizontalLines.x() << ", " << expectedHorizontalLines.y() << "] horizontal lines.\n"
1822                         << "\t[" << expectedVerticalLines.x() << ", " << expectedVerticalLines.y() << "] vertical lines.\n"
1823                 << tcu::TestLog::EndMessage;
1824
1825         if (m_fbo)
1826                 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
1827         glu::readPixels(m_context.getRenderContext(), config.viewportPos.x(), config.viewportPos.y(), viewportSurface.getAccess());
1828
1829         // scan rows
1830         for (int y = de::max(verificationArea.y(), viewportPatternArea.y()); y < de::min(verificationArea.w(), viewportPatternArea.w()); ++y)
1831                 anyError |= !scanRow(viewportSurface.getAccess(),
1832                                                          y,
1833                                                          verificationArea.x(),
1834                                                          verificationArea.z(),
1835                                                          expectedVerticalLines,
1836                                                          messageLimitCounter);
1837
1838         // scan columns
1839         for (int x = de::max(verificationArea.x(), viewportPatternArea.x()); x < de::min(verificationArea.z(), viewportPatternArea.z()); ++x)
1840                 anyError |= !scanColumn(viewportSurface.getAccess(),
1841                                                                 x,
1842                                                                 verificationArea.y(),
1843                                                                 verificationArea.w(),
1844                                                                 expectedHorizontalLines,
1845                                                                 messageLimitCounter);
1846
1847         if (anyError)
1848         {
1849                 if (messageLimitCounter < 0)
1850                         m_testCtx.getLog() << tcu::TestLog::Message << "Omitted " << (-messageLimitCounter) << " row/column error descriptions." << tcu::TestLog::EndMessage;
1851
1852                 m_testCtx.getLog()
1853                         << tcu::TestLog::Message
1854                         << "Image verification failed."
1855                         << tcu::TestLog::EndMessage
1856                         << tcu::TestLog::ImageSet("Images", "Image verification")
1857                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewportSurface.getAccess())
1858                         << tcu::TestLog::EndImageSet;
1859
1860                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1861         }
1862         else
1863         {
1864                 m_testCtx.getLog()
1865                         << tcu::TestLog::Message
1866                         << "Result image ok."
1867                         << tcu::TestLog::EndMessage
1868                         << tcu::TestLog::ImageSet("Images", "Image verification")
1869                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewportSurface.getAccess())
1870                         << tcu::TestLog::EndImageSet;
1871         }
1872 }
1873
1874 tcu::IVec2 LineRenderCase::getNumberOfLinesRange (int queryAreaBegin, int queryAreaEnd, float patternStart, float patternSize, int viewportArea, QueryDirection queryDir) const
1875 {
1876         // pattern is not symmetric due to mirroring
1877         const int       patternStartNdx = (queryDir == DIRECTION_HORIZONTAL) ? ((m_hasGeometryStage) ? (1) : (0)) : ((m_hasTessellationStage) ? (1) : (0));
1878         const int       patternEndNdx   = patternStartNdx + m_patternSide;
1879
1880         int                     numLinesMin             = 0;
1881         int                     numLinesMax             = 0;
1882
1883         for (int lineNdx = patternStartNdx; lineNdx < patternEndNdx; ++lineNdx)
1884         {
1885                 const float linePos             = (patternStart + (lineNdx / float(m_patternSide)) * patternSize) * 0.5f + 0.5f;
1886                 const float lineWidth   = (m_isWideLineCase) ? (m_wideLineLineWidth) : (1.0f);
1887
1888                 if (linePos * viewportArea > queryAreaBegin + 1.0f &&
1889                         linePos * viewportArea < queryAreaEnd   - 1.0f)
1890                 {
1891                         // line center is within the area
1892                         ++numLinesMin;
1893                         ++numLinesMax;
1894                 }
1895                 else if (linePos * viewportArea > queryAreaBegin - lineWidth*0.5f - 1.0f &&
1896                          linePos * viewportArea < queryAreaEnd   + lineWidth*0.5f + 1.0f)
1897                 {
1898                         // line could leak into area
1899                         ++numLinesMax;
1900                 }
1901         }
1902
1903         return tcu::IVec2(numLinesMin, numLinesMax);
1904 }
1905
1906 bool LineRenderCase::scanRow (const tcu::ConstPixelBufferAccess& access, int row, int rowBegin, int rowEnd, const tcu::IVec2& numLines, int& messageLimitCounter) const
1907 {
1908         const bool numLinesOk   = checkAreaNumLines(access, tcu::IVec4(rowBegin, row, rowEnd - rowBegin, 1), messageLimitCounter, SCAN_ROW_COMPONENT_NDX, numLines);
1909         const bool lineWidthOk  = checkLineWidths(access, tcu::IVec2(rowBegin, row), tcu::IVec2(rowEnd, row), SCAN_ROW_COMPONENT_NDX, messageLimitCounter);
1910         return numLinesOk && lineWidthOk;
1911 }
1912
1913 bool LineRenderCase::scanColumn (const tcu::ConstPixelBufferAccess& access, int column, int columnBegin, int columnEnd, const tcu::IVec2& numLines, int& messageLimitCounter) const
1914 {
1915         const bool numLinesOk   = checkAreaNumLines(access, tcu::IVec4(column, columnBegin, 1, columnEnd - columnBegin), messageLimitCounter, SCAN_COL_COMPONENT_NDX, numLines);
1916         const bool lineWidthOk  = checkLineWidths(access, tcu::IVec2(column, columnBegin), tcu::IVec2(column, columnEnd), SCAN_COL_COMPONENT_NDX, messageLimitCounter);
1917         return numLinesOk && lineWidthOk;
1918 }
1919
1920 bool LineRenderCase::checkAreaNumLines (const tcu::ConstPixelBufferAccess& access, const tcu::IVec4& area, int& messageLimitCounter, int componentNdx, const tcu::IVec2& numLines) const
1921 {
1922         // Num maxima == num lines
1923         const tcu::ConstPixelBufferAccess       subAccess               = tcu::getSubregion(access, area.x(), area.y(), 0, area.z(), area.w(), 1);
1924         const tcu::IVec2                                        numMinimaMaxima = getNumMinimaMaxima(subAccess, componentNdx);
1925         const int                                                       numMaxima               = numMinimaMaxima.y();
1926
1927         // In valid range
1928         if (numMaxima >= numLines.x() && numMaxima <= numLines.y())
1929                 return true;
1930
1931         if (--messageLimitCounter < 0)
1932                 return false;
1933
1934         if (area.z() == 1)
1935                 m_testCtx.getLog()
1936                         << tcu::TestLog::Message
1937                         << "On column " << area.x() << ", y: [" << area.y() << "," << (area.y()+area.w()) << "):\n"
1938                                 << "\tExpected [" << numLines.x() << ", " << numLines.y() << "] lines but the number of lines in the area is " << numMaxima
1939                         << tcu::TestLog::EndMessage;
1940         else
1941                 m_testCtx.getLog()
1942                         << tcu::TestLog::Message
1943                         << "On row " << area.y() << ", x: [" << area.x() << "," << (area.x()+area.z()) << "):\n"
1944                                 << "\tExpected [" << numLines.x() << ", " << numLines.y() << "] lines but the number of lines in the area is " << numMaxima
1945                         << tcu::TestLog::EndMessage;
1946
1947         return false;
1948 }
1949
1950 tcu::IVec2 LineRenderCase::getNumMinimaMaxima (const tcu::ConstPixelBufferAccess& access, int componentNdx) const
1951 {
1952         DE_ASSERT(access.getWidth() == 1 || access.getHeight() == 1);
1953
1954         int previousValue       = -1;
1955         int previousSign        = 0;
1956         int numMinima           = 0;
1957         int numMaxima           = 0;
1958
1959         for (int y = 0; y < access.getHeight(); ++y)
1960         for (int x = 0; x < access.getWidth(); ++x)
1961         {
1962                 const int componentValue = access.getPixelInt(x, y)[componentNdx];
1963
1964                 if (previousValue != -1)
1965                 {
1966                         const int sign = (componentValue > previousValue) ? (+1) : (componentValue < previousValue) ? (-1) : (0);
1967
1968                         // local minima/maxima in sign changes (zero signless)
1969                         if (sign != 0 && sign == -previousSign)
1970                         {
1971                                 previousSign = sign;
1972
1973                                 if (sign > 0)
1974                                         ++numMinima;
1975                                 else
1976                                         ++numMaxima;
1977                         }
1978                         else if (sign != 0 && previousSign == 0)
1979                         {
1980                                 previousSign = sign;
1981
1982                                 // local extreme at the start boundary
1983                                 if (sign > 0)
1984                                         ++numMinima;
1985                                 else
1986                                         ++numMaxima;
1987                         }
1988                 }
1989
1990                 previousValue = componentValue;
1991         }
1992
1993         // local extreme at the end boundary
1994         if (previousSign > 0)
1995                 ++numMaxima;
1996         else if (previousSign < 0)
1997                 ++numMinima;
1998         else
1999         {
2000                 ++numMaxima;
2001                 ++numMinima;
2002         }
2003
2004         return tcu::IVec2(numMinima, numMaxima);
2005 }
2006
2007 bool LineRenderCase::checkLineWidths (const tcu::ConstPixelBufferAccess& access, const tcu::IVec2& begin, const tcu::IVec2& end, int componentNdx, int& messageLimitCounter) const
2008 {
2009         const bool                      multisample             = m_context.getRenderTarget().getNumSamples() > 1;
2010         const int                       lineRenderWidth = (m_isWideLineCase) ? (m_wideLineLineWidth) : 1;
2011         const tcu::IVec2        lineWidthRange  = (multisample)
2012                                                                                         ? (tcu::IVec2(lineRenderWidth, lineRenderWidth+1))      // multisampled "smooth" lines may spread to neighboring pixel
2013                                                                                         : (tcu::IVec2(lineRenderWidth, lineRenderWidth));
2014
2015         int                                     lineWidth               = 0;
2016         bool                            bboxLimitedLine = false;
2017         bool                            anyError                = false;
2018
2019         const tcu::IVec2        advance                 = (begin.x() == end.x()) ? (tcu::IVec2(0, 1)) : (tcu::IVec2(1, 0));
2020
2021         // fragments before begin?
2022         if (access.getPixelInt(begin.x(), begin.y())[componentNdx] != 0)
2023         {
2024                 bboxLimitedLine = true;
2025
2026                 for (tcu::IVec2 cursor = begin - advance;; cursor -= advance)
2027                 {
2028                         if (cursor.x() < 0 || cursor.y() < 0)
2029                         {
2030                                 break;
2031                         }
2032                         else if (access.getPixelInt(cursor.x(), cursor.y())[componentNdx] != 0)
2033                         {
2034                                 ++lineWidth;
2035                         }
2036                         else
2037                                 break;
2038                 }
2039         }
2040
2041         for (tcu::IVec2 cursor = begin; cursor != end; cursor += advance)
2042         {
2043                 const bool hit = (access.getPixelInt(cursor.x(), cursor.y())[componentNdx] != 0);
2044
2045                 if (hit)
2046                         ++lineWidth;
2047                 else if (lineWidth)
2048                 {
2049                         // Line is allowed to be be thinner if it borders the bbox boundary (since part of the line might have been discarded).
2050                         const bool incorrectLineWidth = (lineWidth < lineWidthRange.x() && !bboxLimitedLine) || (lineWidth > lineWidthRange.y());
2051
2052                         if (incorrectLineWidth)
2053                         {
2054                                 anyError = true;
2055                                 printLineWidthError(cursor, lineWidth, lineWidthRange, advance.x() == 0, messageLimitCounter);
2056                         }
2057
2058                         lineWidth = 0;
2059                         bboxLimitedLine = false;
2060                 }
2061         }
2062
2063         // fragments after end?
2064         if (lineWidth)
2065         {
2066                 for (tcu::IVec2 cursor = end;; cursor += advance)
2067                 {
2068                         if (cursor.x() >= access.getWidth() || cursor.y() >= access.getHeight())
2069                         {
2070                                 if (lineWidth > lineWidthRange.y())
2071                                 {
2072                                         anyError = true;
2073                                         printLineWidthError(cursor, lineWidth, lineWidthRange, advance.x() == 0, messageLimitCounter);
2074                                 }
2075
2076                                 break;
2077                         }
2078                         else if (access.getPixelInt(cursor.x(), cursor.y())[componentNdx] != 0)
2079                         {
2080                                 ++lineWidth;
2081                         }
2082                         else if (lineWidth)
2083                         {
2084                                 // only check that line width is not larger than expected. Line width may be smaller
2085                                 // since the scanning 'cursor' is now outside the bounding box.
2086                                 const bool incorrectLineWidth = (lineWidth > lineWidthRange.y());
2087
2088                                 if (incorrectLineWidth)
2089                                 {
2090                                         anyError = true;
2091                                         printLineWidthError(cursor, lineWidth, lineWidthRange, advance.x() == 0, messageLimitCounter);
2092                                 }
2093
2094                                 lineWidth = 0;
2095                         }
2096                 }
2097         }
2098
2099         return !anyError;
2100 }
2101
2102 void LineRenderCase::printLineWidthError (const tcu::IVec2& pos, int detectedLineWidth, const tcu::IVec2& lineWidthRange, bool isHorizontal, int& messageLimitCounter) const
2103 {
2104         if (--messageLimitCounter < 0)
2105                 return;
2106
2107         m_testCtx.getLog()
2108                 << tcu::TestLog::Message
2109                 << "Found incorrect line width near " << pos << ": (" << ((isHorizontal) ? ("horizontal") : ("vertical")) << " line)\n"
2110                         << "\tExpected line width in range [" << lineWidthRange.x() << ", " << lineWidthRange.y() << "] but found " << detectedLineWidth
2111                 << tcu::TestLog::EndMessage;
2112 }
2113
2114 class PointRenderCase : public BBoxRenderCase
2115 {
2116 public:
2117         enum
2118         {
2119                 POINTFLAG_WIDE = 1u << FLAGBIT_USER_BIT,        //!< use wide points
2120         };
2121         struct GeneratedPoint
2122         {
2123                 tcu::Vec2       center;
2124                 int                     size;
2125                 bool            even;
2126         };
2127
2128                                                         PointRenderCase                                 (Context& context, const char* name, const char* description, deUint32 flags);
2129                                                         ~PointRenderCase                                (void);
2130
2131 private:
2132         enum ResultPointType
2133         {
2134                 POINT_FULL = 0,
2135                 POINT_PARTIAL
2136         };
2137
2138         void                                    init                                                    (void);
2139         void                                    deinit                                                  (void);
2140
2141         std::string                             genVertexSource                                 (void) const;
2142         std::string                             genFragmentSource                               (void) const;
2143         std::string                             genTessellationControlSource    (void) const;
2144         std::string                             genTessellationEvaluationSource (void) const;
2145         std::string                             genGeometrySource                               (void) const;
2146
2147         IterationConfig                 generateConfig                                  (int iteration, const tcu::IVec2& renderTargetSize) const;
2148         void                                    generateAttributeData                   (void);
2149         void                                    getAttributeData                                (std::vector<tcu::Vec4>& data) const;
2150         void                                    renderTestPattern                               (const IterationConfig& config);
2151         void                                    verifyRenderResult                              (const IterationConfig& config);
2152
2153         void                                    genReferencePointData                   (const IterationConfig& config, std::vector<GeneratedPoint>& data) const;
2154         bool                                    verifyNarrowPointPattern                (const tcu::Surface& viewport, const std::vector<GeneratedPoint>& refPoints, const ProjectedBBox& bbox, int& logFloodCounter);
2155         bool                                    verifyWidePointPattern                  (const tcu::Surface& viewport, const std::vector<GeneratedPoint>& refPoints, const ProjectedBBox& bbox, int& logFloodCounter);
2156         bool                                    verifyWidePoint                                 (const tcu::Surface& viewport, const GeneratedPoint& refPoint, const ProjectedBBox& bbox, ResultPointType pointType, int& logFloodCounter);
2157         bool                                    verifyWidePointAt                               (const tcu::IVec2& pointPos, const tcu::Surface& viewport, const GeneratedPoint& refPoint, const tcu::IVec4& bbox, ResultPointType pointType, int componentNdx, int& logFloodCounter);
2158         tcu::IVec2                              scanPointWidthAt                                (const tcu::IVec2& pointPos, const tcu::Surface& viewport, int expectedPointSize, int componentNdx) const;
2159
2160         const int                               m_numStripes;
2161         const bool                              m_isWidePointCase;
2162         std::vector<tcu::Vec4>  m_attribData;
2163 };
2164
2165 PointRenderCase::PointRenderCase (Context& context, const char* name, const char* description, deUint32 flags)
2166         : BBoxRenderCase        (context, name, description, 12, flags)
2167         , m_numStripes          (4)
2168         , m_isWidePointCase     ((flags & POINTFLAG_WIDE) != 0)
2169 {
2170 }
2171
2172 PointRenderCase::~PointRenderCase (void)
2173 {
2174 }
2175
2176 void PointRenderCase::init (void)
2177 {
2178         if (m_isWidePointCase)
2179         {
2180                 // extensions
2181                 if (m_hasGeometryStage && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_point_size"))
2182                         throw tcu::NotSupportedError("Test requires GL_EXT_geometry_point_size extension");
2183                 if (m_hasTessellationStage && !m_hasGeometryStage && !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_point_size"))
2184                         throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_point_size extension");
2185
2186                 // point size range
2187                 {
2188                         glw::GLfloat pointSizeRange[2] = {0.0f, 0.0f};
2189                         m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
2190
2191                         if (pointSizeRange[1] < 5.0f)
2192                                 throw tcu::NotSupportedError("Test requires point size 5.0");
2193                 }
2194         }
2195
2196         m_testCtx.getLog()
2197                 << tcu::TestLog::Message
2198                 << "Rendering point pattern to " << ((m_renderTarget == RENDERTARGET_DEFAULT) ? ("default frame buffer") : ("fbo")) << ".\n"
2199                 << "Half of the points are green, half blue. Using additive blending.\n"
2200                 << "Points are in random order, varying pattern size and location for each iteration.\n"
2201                 << "Marking all discardable fragments (fragments outside the bounding box) with a fully saturated red channel."
2202                 << tcu::TestLog::EndMessage;
2203
2204         generateAttributeData();
2205
2206         BBoxRenderCase::init();
2207 }
2208
2209 void PointRenderCase::deinit (void)
2210 {
2211         // clear data
2212         m_attribData = std::vector<tcu::Vec4>();
2213
2214         // deinit parent
2215         BBoxRenderCase::deinit();
2216 }
2217
2218 std::string PointRenderCase::genVertexSource (void) const
2219 {
2220         std::ostringstream      buf;
2221
2222         buf <<  "#version 310 es\n"
2223                         "in highp vec4 a_position;\n"
2224                         "in highp vec4 a_color;\n"
2225                         "out highp vec4 vtx_color;\n"
2226                         "uniform highp vec4 u_posScale;\n"
2227                         "\n";
2228         if (!m_hasTessellationStage)
2229         {
2230                 DE_ASSERT(m_useGlobalState);
2231                 buf <<  "uniform highp vec4 u_primitiveBBoxMin;\n"
2232                                 "uniform highp vec4 u_primitiveBBoxMax;\n"
2233                                 "\n"
2234                                 "flat out highp float v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize;\n"
2235                                 "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin;\n"
2236                                 "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax;\n"
2237                                 "\n";
2238         }
2239
2240         buf <<  "void main()\n"
2241                         "{\n"
2242                         "       highp vec2 patternOffset = u_posScale.xy;\n"
2243                         "       highp vec2 patternScale = u_posScale.zw;\n"
2244                         "       highp float pointSize = "
2245                                         << ((m_isWidePointCase && !m_hasTessellationStage && !m_hasGeometryStage) ? ("(a_color.g > 0.0) ? (5.0) : (3.0)") : ("1.0"))
2246                                         << ";\n"
2247                 <<      "       gl_Position = vec4(a_position.xy * patternScale + patternOffset, a_position.z, a_position.w);\n"
2248                         "       gl_PointSize = pointSize;\n"
2249                         "       vtx_color = a_color;\n";
2250
2251         if (!m_hasTessellationStage)
2252         {
2253                 DE_ASSERT(m_useGlobalState);
2254                 buf <<  "\n"
2255                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_expansionSize = pointSize;\n"
2256                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin =\n"
2257                                 "           min(vec3(u_primitiveBBoxMin.x, u_primitiveBBoxMin.y, u_primitiveBBoxMin.z) / u_primitiveBBoxMin.w,\n"
2258                                 "               vec3(u_primitiveBBoxMin.x, u_primitiveBBoxMin.y, u_primitiveBBoxMin.z) / u_primitiveBBoxMax.w);\n"
2259                                 "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax =\n"
2260                                 "           min(vec3(u_primitiveBBoxMax.x, u_primitiveBBoxMax.y, u_primitiveBBoxMax.z) / u_primitiveBBoxMin.w,\n"
2261                                 "               vec3(u_primitiveBBoxMax.x, u_primitiveBBoxMax.y, u_primitiveBBoxMax.z) / u_primitiveBBoxMax.w);\n";
2262         }
2263
2264         buf <<  "}\n";
2265         return buf.str();
2266 }
2267
2268 std::string PointRenderCase::genFragmentSource (void) const
2269 {
2270         const char* const       colorInputName = (m_hasGeometryStage) ? ("geo_color") : (m_hasTessellationStage) ? ("tess_color") : ("vtx_color");
2271         std::ostringstream      buf;
2272
2273         buf <<  "#version 310 es\n"
2274                         "in mediump vec4 " << colorInputName << ";\n"
2275                         "layout(location = 0) out mediump vec4 o_color;\n"
2276                 <<      genShaderFunction(SHADER_FUNC_INSIDE_BBOX)
2277                 <<      "\n"
2278                         "void main()\n"
2279                         "{\n"
2280                         "       mediump vec4 baseColor = " << colorInputName << ";\n"
2281                         "       mediump float redChannel;\n"
2282                         "       if (fragmentInsideTheBBox(gl_FragCoord.z))\n"
2283                         "               redChannel = 0.0;\n"
2284                         "       else\n"
2285                         "               redChannel = 1.0;\n"
2286                         "       o_color = vec4(redChannel, baseColor.g, baseColor.b, baseColor.a);\n"
2287                         "}\n";
2288
2289         return buf.str();
2290 }
2291
2292 std::string PointRenderCase::genTessellationControlSource (void) const
2293 {
2294         const bool                      tessellationWidePoints = (m_isWidePointCase) && (!m_hasGeometryStage);
2295         std::ostringstream      buf;
2296
2297         buf <<  "#version 310 es\n"
2298                         "#extension GL_EXT_tessellation_shader : require\n"
2299                         "#extension GL_EXT_primitive_bounding_box : require\n"
2300                 <<      ((tessellationWidePoints) ? ("#extension GL_EXT_tessellation_point_size : require\n") : (""))
2301                 <<      "layout(vertices=1) out;"
2302                         "\n"
2303                         "in highp vec4 vtx_color[];\n"
2304                         "out highp vec4 tess_ctrl_color[];\n"
2305                         "uniform highp float u_tessellationLevel;\n"
2306                         "uniform highp vec4 u_posScale;\n";
2307
2308         if (!m_calcPerPrimitiveBBox)
2309         {
2310                 buf <<  "uniform highp vec4 u_primitiveBBoxMin;\n"
2311                                 "uniform highp vec4 u_primitiveBBoxMax;\n";
2312         }
2313
2314         buf <<  "patch out highp vec3 vp_bbox_clipMin;\n"
2315                         "patch out highp vec3 vp_bbox_clipMax;\n";
2316
2317         if (m_calcPerPrimitiveBBox)
2318         {
2319                 buf <<  "\n";
2320                 if (m_hasGeometryStage)
2321                         buf << genShaderFunction(SHADER_FUNC_MIRROR_X);
2322                 buf << genShaderFunction(SHADER_FUNC_MIRROR_Y);
2323
2324                 buf <<  "vec4 transformVec(in highp vec4 p)\n"
2325                                 "{\n"
2326                                 "       return " << ((m_hasGeometryStage) ? ("mirrorX(mirrorY(p))") : ("mirrorY(p)")) << ";\n"
2327                                 "}\n";
2328         }
2329
2330         buf <<  "\n"
2331                         "void main()\n"
2332                         "{\n"
2333                         "       // convert to nonsensical coordinates, just in case\n"
2334                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position.wzxy;\n"
2335                         "       tess_ctrl_color[gl_InvocationID] = vtx_color[gl_InvocationID];\n"
2336                         "\n"
2337                         "       gl_TessLevelOuter[0] = u_tessellationLevel;\n"
2338                         "       gl_TessLevelOuter[1] = u_tessellationLevel;\n"
2339                         "       gl_TessLevelOuter[2] = u_tessellationLevel;\n"
2340                         "       gl_TessLevelOuter[3] = u_tessellationLevel;\n"
2341                         "       gl_TessLevelInner[0] = 0.8; // will be rounded up to 1\n"
2342                         "       gl_TessLevelInner[1] = 0.8; // will be rounded up to 1\n";
2343
2344         if (m_calcPerPrimitiveBBox)
2345         {
2346                 buf <<  "\n";
2347
2348                 if (m_hasGeometryStage)
2349                         buf <<  "       const vec2 minExpansion = vec2(0.07 + 0.05, 0.07 + 0.02); // eval and geometry shader\n"
2350                                         "       const vec2 maxExpansion = vec2(0.07 + 0.05, 0.07 + 0.03); // eval and geometry shader\n";
2351                 else
2352                         buf <<  "       const vec2 minExpansion = vec2(0.07, 0.07); // eval shader\n"
2353                                         "       const vec2 maxExpansion = vec2(0.07, 0.07); // eval shader\n";
2354
2355                 buf <<  "       highp vec2 patternScale = u_posScale.zw;\n"
2356                                 "       highp vec4 bboxMin = transformVec(gl_in[0].gl_Position) - vec4(minExpansion * patternScale, 0.0, 0.0);\n"
2357                                 "       highp vec4 bboxMax = transformVec(gl_in[0].gl_Position) + vec4(maxExpansion * patternScale, 0.0, 0.0);\n";
2358         }
2359         else
2360         {
2361                 buf <<  "\n"
2362                                 "       highp vec4 bboxMin = u_primitiveBBoxMin;\n"
2363                                 "       highp vec4 bboxMax = u_primitiveBBoxMax;\n";
2364         }
2365         if (!m_useGlobalState)
2366                 buf <<  "\n"
2367                                 "       gl_BoundingBoxEXT[0] = bboxMin;\n"
2368                                 "       gl_BoundingBoxEXT[1] = bboxMax;\n";
2369
2370         buf <<  "       vp_bbox_clipMin = min(vec3(bboxMin.x, bboxMin.y, bboxMin.z) / bboxMin.w,\n"
2371                         "                             vec3(bboxMin.x, bboxMin.y, bboxMin.z) / bboxMax.w);\n"
2372                         "       vp_bbox_clipMax = max(vec3(bboxMax.x, bboxMax.y, bboxMax.z) / bboxMin.w,\n"
2373                         "                             vec3(bboxMax.x, bboxMax.y, bboxMax.z) / bboxMax.w);\n"
2374                         "}\n";
2375
2376         return buf.str();
2377 }
2378
2379 std::string PointRenderCase::genTessellationEvaluationSource (void) const
2380 {
2381         const bool                      tessellationWidePoints = (m_isWidePointCase) && (!m_hasGeometryStage);
2382         std::ostringstream      buf;
2383
2384         buf <<  "#version 310 es\n"
2385                         "#extension GL_EXT_tessellation_shader : require\n"
2386                 <<      ((tessellationWidePoints) ? ("#extension GL_EXT_tessellation_point_size : require\n") : (""))
2387                 <<      "layout(quads, point_mode) in;"
2388                         "\n"
2389                         "in highp vec4 tess_ctrl_color[];\n"
2390                         "out highp vec4 tess_color;\n"
2391                         "uniform highp vec4 u_posScale;\n"
2392                         "\n"
2393                         "patch in highp vec3 vp_bbox_clipMin;\n"
2394                         "patch in highp vec3 vp_bbox_clipMax;\n"
2395                 <<      ((!m_hasGeometryStage) ? ("flat out highp float v_bbox_expansionSize;\n") : (""))
2396                 <<      "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin;\n"
2397                         "flat out highp vec3 v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax;\n"
2398                         "\n"
2399                 <<      genShaderFunction(SHADER_FUNC_MIRROR_Y)
2400                 <<      "void main()\n"
2401                         "{\n"
2402                         "       // non-trivial tessellation evaluation shader, convert from nonsensical coords, flip vertically\n"
2403                         "       highp vec2 patternScale = u_posScale.zw;\n"
2404                         "       highp vec4 offset = vec4((gl_TessCoord.xy * 2.0 - vec2(1.0)) * 0.07 * patternScale, 0.0, 0.0);\n"
2405                         "       highp float pointSize = " << ((tessellationWidePoints) ? ("(tess_ctrl_color[0].g > 0.0) ? (5.0) : (3.0)") : ("1.0")) << ";\n"
2406                         "       gl_Position = mirrorY(gl_in[0].gl_Position.zwyx + offset);\n";
2407
2408         if (tessellationWidePoints)
2409                 buf << "        gl_PointSize = pointSize;\n";
2410
2411         buf <<  "       tess_color = tess_ctrl_color[0];\n"
2412                 <<      ((!m_hasGeometryStage) ? ("v_bbox_expansionSize = pointSize;\n") : (""))
2413                 <<      "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMin = vp_bbox_clipMin;\n"
2414                         "       v_" << (m_hasGeometryStage ? "geo_" : "") << "bbox_clipMax = vp_bbox_clipMax;\n"
2415                         "}\n";
2416
2417         return buf.str();
2418 }
2419
2420 std::string PointRenderCase::genGeometrySource (void) const
2421 {
2422         const char* const       colorInputName = (m_hasTessellationStage) ? ("tess_color") : ("vtx_color");
2423         std::ostringstream      buf;
2424
2425         buf <<  "#version 310 es\n"
2426                         "#extension GL_EXT_geometry_shader : require\n"
2427                 <<      ((m_isWidePointCase) ? ("#extension GL_EXT_geometry_point_size : require\n") : (""))
2428                 <<      "layout(points) in;\n"
2429                         "layout(max_vertices=3, points) out;\n"
2430                         "\n"
2431                         "in highp vec4 " << colorInputName << "[1];\n"
2432                         "out highp vec4 geo_color;\n"
2433                         "uniform highp vec4 u_posScale;\n"
2434                         "\n"
2435                         "flat in highp vec3 v_geo_bbox_clipMin[1];\n"
2436                         "flat in highp vec3 v_geo_bbox_clipMax[1];\n"
2437                         "flat out highp vec3 v_bbox_clipMin;\n"
2438                         "flat out highp vec3 v_bbox_clipMax;\n"
2439                         "flat out highp float v_bbox_expansionSize;\n"
2440                         "\n"
2441                 <<      genShaderFunction(SHADER_FUNC_MIRROR_X)
2442                 <<      "\n"
2443                         "void main()\n"
2444                         "{\n"
2445                         "       // Non-trivial geometry shader: 1-to-3 amplification, mirror horizontally\n"
2446                         "       highp vec4 p0 = mirrorX(gl_in[0].gl_Position);\n"
2447                         "       highp vec4 pointColor = " << colorInputName << "[0];\n"
2448                         "       highp vec2 patternScale = u_posScale.zw;\n"
2449                         "       highp float pointSize = "
2450                                 << (m_isWidePointCase ? ("(pointColor.g > 0.0) ? (5.0) : (3.0)") : ("1.0"))
2451                                 << ";\n"
2452                         "\n"
2453                         "       highp vec4 offsets[3] =\n"
2454                         "               vec4[3](\n"
2455                         "                       vec4( 0.05 * patternScale.x, 0.03 * patternScale.y, 0.0, 0.0),\n"
2456                         "                       vec4(-0.01 * patternScale.x,-0.02 * patternScale.y, 0.0, 0.0),\n"
2457                         "                       vec4(-0.05 * patternScale.x, 0.02 * patternScale.y, 0.0, 0.0)\n"
2458                         "               );\n"
2459                         "       for (int ndx = 0; ndx < 3; ++ndx)\n"
2460                         "       {\n"
2461                         "               gl_Position = p0 + offsets[ndx];\n";
2462
2463         if (m_isWidePointCase)
2464                 buf <<  "               gl_PointSize = pointSize;\n";
2465
2466         buf <<  "               v_bbox_clipMin = v_geo_bbox_clipMin[0];\n"
2467                         "               v_bbox_clipMax = v_geo_bbox_clipMax[0];\n"
2468                         "               v_bbox_expansionSize = pointSize;\n"
2469                         "               geo_color = pointColor;\n"
2470                         "               EmitVertex();\n"
2471                         "       }\n"
2472                         "}\n";
2473
2474         return buf.str();
2475 }
2476
2477 PointRenderCase::IterationConfig PointRenderCase::generateConfig (int iteration, const tcu::IVec2& renderTargetSize) const
2478 {
2479         IterationConfig config = generateRandomConfig(0xDEDEDEu * (deUint32)iteration, renderTargetSize);
2480
2481         // equal or larger -> expand according to shader expansion
2482         if (m_bboxSize == BBOXSIZE_EQUAL || m_bboxSize == BBOXSIZE_LARGER)
2483         {
2484                 const tcu::Vec2 patternScale = config.patternSize;
2485
2486                 if (m_hasTessellationStage)
2487                 {
2488                         config.bbox.min -= tcu::Vec4(0.07f * patternScale.x(), 0.07f * patternScale.y(), 0.0f, 0.0f);
2489                         config.bbox.max += tcu::Vec4(0.07f * patternScale.x(), 0.07f * patternScale.y(), 0.0f, 0.0f);
2490                 }
2491                 if (m_hasGeometryStage)
2492                 {
2493                         config.bbox.min -= tcu::Vec4(0.05f * patternScale.x(), 0.02f * patternScale.y(), 0.0f, 0.0f);
2494                         config.bbox.max += tcu::Vec4(0.05f * patternScale.x(), 0.03f * patternScale.y(), 0.0f, 0.0f);
2495                 }
2496         }
2497
2498         return config;
2499 }
2500
2501 void PointRenderCase::generateAttributeData (void)
2502 {
2503         const tcu::Vec4         green           (0.0f, 1.0f, 0.0f, 1.0f);
2504         const tcu::Vec4         blue            (0.0f, 0.0f, 1.0f, 1.0f);
2505         std::vector<int>        cellOrder       (m_numStripes * m_numStripes * 2);
2506         de::Random                      rnd                     (0xDE22446);
2507
2508         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
2509                 cellOrder[ndx] = ndx;
2510         rnd.shuffle(cellOrder.begin(), cellOrder.end());
2511
2512         m_attribData.resize(cellOrder.size() * 2);
2513         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
2514         {
2515                 const int pointID               = cellOrder[ndx];
2516                 const int direction             = pointID & 0x01;
2517                 const int majorCoord    = (pointID >> 1) / m_numStripes;
2518                 const int minorCoord    = (pointID >> 1) % m_numStripes;
2519
2520                 if (direction)
2521                 {
2522                         m_attribData[ndx * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4(minorCoord / float(m_numStripes), majorCoord / float(m_numStripes), 0.0f, 1.0f);
2523                         m_attribData[ndx * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = green;
2524                 }
2525                 else
2526                 {
2527                         m_attribData[ndx * VA_NUM_ATTRIB_VECS + VA_POS_VEC_NDX] = tcu::Vec4((majorCoord + 0.5f) / float(m_numStripes), (minorCoord + 0.5f) / float(m_numStripes), 0.0f, 1.0f);
2528                         m_attribData[ndx * VA_NUM_ATTRIB_VECS + VA_COL_VEC_NDX] = blue;
2529                 }
2530         }
2531 }
2532
2533 void PointRenderCase::getAttributeData (std::vector<tcu::Vec4>& data) const
2534 {
2535         data = m_attribData;
2536 }
2537
2538 void PointRenderCase::renderTestPattern (const IterationConfig& config)
2539 {
2540         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2541
2542         setupRender(config);
2543
2544         if (m_hasTessellationStage)
2545         {
2546                 const glw::GLint        tessLevelPos    = gl.getUniformLocation(m_program->getProgram(), "u_tessellationLevel");
2547                 const glw::GLfloat      tessLevel               = 0.8f; // will be rounded up
2548
2549                 TCU_CHECK(tessLevelPos != -1);
2550
2551                 m_testCtx.getLog() << tcu::TestLog::Message << "u_tessellationLevel = " << tessLevel << tcu::TestLog::EndMessage;
2552
2553                 gl.uniform1f(tessLevelPos, tessLevel);
2554                 gl.patchParameteri(GL_PATCH_VERTICES, 1);
2555                 GLU_EXPECT_NO_ERROR(gl.getError(), "patch param");
2556         }
2557
2558         m_testCtx.getLog() << tcu::TestLog::Message << "Rendering pattern." << tcu::TestLog::EndMessage;
2559
2560         gl.enable(GL_BLEND);
2561         gl.blendFunc(GL_ONE, GL_ONE);
2562         gl.blendEquation(GL_FUNC_ADD);
2563
2564         gl.drawArrays((m_hasTessellationStage) ? (GL_PATCHES) : (GL_POINTS), 0, m_numStripes * m_numStripes * 2);
2565         GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
2566 }
2567
2568 void PointRenderCase::verifyRenderResult (const IterationConfig& config)
2569 {
2570         const glw::Functions&           gl                                              = m_context.getRenderContext().getFunctions();
2571         const ProjectedBBox                     projectedBBox                   = projectBoundingBox(config.bbox);
2572         const tcu::IVec4                        viewportBBoxArea                = getViewportBoundingBoxArea(projectedBBox, config.viewportSize);
2573
2574         tcu::Surface                            viewportSurface                 (config.viewportSize.x(), config.viewportSize.y());
2575         int                                                     logFloodCounter                 = 8;
2576         bool                                            anyError;
2577         std::vector<GeneratedPoint>     refPoints;
2578
2579         if (!m_calcPerPrimitiveBBox)
2580                 m_testCtx.getLog()
2581                         << tcu::TestLog::Message
2582                         << "Projected bounding box: (clip space)\n"
2583                                 << "\tx: [" << projectedBBox.min.x() << "," << projectedBBox.max.x() << "]\n"
2584                                 << "\ty: [" << projectedBBox.min.y() << "," << projectedBBox.max.y() << "]\n"
2585                                 << "\tz: [" << projectedBBox.min.z() << "," << projectedBBox.max.z() << "]\n"
2586                         << "In viewport coordinates:\n"
2587                                 << "\tx: [" << viewportBBoxArea.x() << ", " << viewportBBoxArea.z() << "]\n"
2588                                 << "\ty: [" << viewportBBoxArea.y() << ", " << viewportBBoxArea.w() << "]\n"
2589                         << "Verifying render results within the bounding box:\n"
2590                         << tcu::TestLog::EndMessage;
2591         else
2592                 m_testCtx.getLog()
2593                         << tcu::TestLog::Message
2594                         << "Verifying render result:"
2595                         << tcu::TestLog::EndMessage;
2596
2597         if (m_fbo)
2598                 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
2599         glu::readPixels(m_context.getRenderContext(), config.viewportPos.x(), config.viewportPos.y(), viewportSurface.getAccess());
2600
2601         genReferencePointData(config, refPoints);
2602
2603         if (m_isWidePointCase)
2604                 anyError = verifyWidePointPattern(viewportSurface, refPoints, projectedBBox, logFloodCounter);
2605         else
2606                 anyError = verifyNarrowPointPattern(viewportSurface, refPoints, projectedBBox, logFloodCounter);
2607
2608         if (anyError)
2609         {
2610                 if (logFloodCounter < 0)
2611                         m_testCtx.getLog() << tcu::TestLog::Message << "Omitted " << (-logFloodCounter) << " error descriptions." << tcu::TestLog::EndMessage;
2612
2613                 m_testCtx.getLog()
2614                         << tcu::TestLog::Message
2615                         << "Image verification failed."
2616                         << tcu::TestLog::EndMessage
2617                         << tcu::TestLog::ImageSet("Images", "Image verification")
2618                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewportSurface.getAccess())
2619                         << tcu::TestLog::EndImageSet;
2620
2621                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
2622         }
2623         else
2624         {
2625                 m_testCtx.getLog()
2626                         << tcu::TestLog::Message
2627                         << "Result image ok."
2628                         << tcu::TestLog::EndMessage
2629                         << tcu::TestLog::ImageSet("Images", "Image verification")
2630                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewportSurface.getAccess())
2631                         << tcu::TestLog::EndImageSet;
2632         }
2633 }
2634
2635 struct PointSorter
2636 {
2637         bool operator() (const PointRenderCase::GeneratedPoint& a, const PointRenderCase::GeneratedPoint& b) const
2638         {
2639                 if (a.center.y() < b.center.y())
2640                         return true;
2641                 else if (a.center.y() > b.center.y())
2642                         return false;
2643                 else
2644                         return (a.center.x() < b.center.x());
2645         }
2646 };
2647
2648 void PointRenderCase::genReferencePointData (const IterationConfig& config, std::vector<GeneratedPoint>& data) const
2649 {
2650         std::vector<GeneratedPoint> currentPoints;
2651
2652         // vertex shader
2653         currentPoints.resize(m_attribData.size() / 2);
2654         for (int ndx = 0; ndx < (int)currentPoints.size(); ++ndx)
2655         {
2656                 currentPoints[ndx].center       = m_attribData[ndx*2].swizzle(0, 1);
2657                 currentPoints[ndx].even         = (m_attribData[ndx*2 + 1].y() == 1.0f); // is green
2658                 currentPoints[ndx].size         = ((m_isWidePointCase) ? ((currentPoints[ndx].even) ? 5 : 3) : 1);
2659         }
2660
2661         // tessellation
2662         if (m_hasTessellationStage)
2663         {
2664                 std::vector<GeneratedPoint> tessellatedPoints;
2665
2666                 tessellatedPoints.resize(currentPoints.size() * 4);
2667                 for (int ndx = 0; ndx < (int)currentPoints.size(); ++ndx)
2668                 {
2669                         const tcu::Vec2 position = tcu::Vec2(currentPoints[ndx].center.x(), 1.0f - currentPoints[ndx].center.y()); // mirror Y
2670
2671                         tessellatedPoints[4 * ndx + 0].center   = position + tcu::Vec2(-0.07f, -0.07f);
2672                         tessellatedPoints[4 * ndx + 0].size             = currentPoints[ndx].size;
2673                         tessellatedPoints[4 * ndx + 0].even             = currentPoints[ndx].even;
2674
2675                         tessellatedPoints[4 * ndx + 1].center   = position + tcu::Vec2( 0.07f, -0.07f);
2676                         tessellatedPoints[4 * ndx + 1].size             = currentPoints[ndx].size;
2677                         tessellatedPoints[4 * ndx + 1].even             = currentPoints[ndx].even;
2678
2679                         tessellatedPoints[4 * ndx + 2].center   = position + tcu::Vec2( 0.07f,  0.07f);
2680                         tessellatedPoints[4 * ndx + 2].size             = currentPoints[ndx].size;
2681                         tessellatedPoints[4 * ndx + 2].even             = currentPoints[ndx].even;
2682
2683                         tessellatedPoints[4 * ndx + 3].center   = position + tcu::Vec2(-0.07f,  0.07f);
2684                         tessellatedPoints[4 * ndx + 3].size             = currentPoints[ndx].size;
2685                         tessellatedPoints[4 * ndx + 3].even             = currentPoints[ndx].even;
2686                 }
2687
2688                 currentPoints.swap(tessellatedPoints);
2689         }
2690
2691         // geometry
2692         if (m_hasGeometryStage)
2693         {
2694                 std::vector<GeneratedPoint> geometryShadedPoints;
2695
2696                 geometryShadedPoints.resize(currentPoints.size() * 3);
2697                 for (int ndx = 0; ndx < (int)currentPoints.size(); ++ndx)
2698                 {
2699                         const tcu::Vec2 position = tcu::Vec2(1.0f - currentPoints[ndx].center.x(), currentPoints[ndx].center.y()); // mirror X
2700
2701                         geometryShadedPoints[3 * ndx + 0].center        = position + tcu::Vec2( 0.05f,  0.03f);
2702                         geometryShadedPoints[3 * ndx + 0].size          = currentPoints[ndx].size;
2703                         geometryShadedPoints[3 * ndx + 0].even          = currentPoints[ndx].even;
2704
2705                         geometryShadedPoints[3 * ndx + 1].center        = position + tcu::Vec2(-0.01f, -0.02f);
2706                         geometryShadedPoints[3 * ndx + 1].size          = currentPoints[ndx].size;
2707                         geometryShadedPoints[3 * ndx + 1].even          = currentPoints[ndx].even;
2708
2709                         geometryShadedPoints[3 * ndx + 2].center        = position + tcu::Vec2(-0.05f,  0.02f);
2710                         geometryShadedPoints[3 * ndx + 2].size          = currentPoints[ndx].size;
2711                         geometryShadedPoints[3 * ndx + 2].even          = currentPoints[ndx].even;
2712                 }
2713
2714                 currentPoints.swap(geometryShadedPoints);
2715         }
2716
2717         // sort from left to right, top to bottom
2718         std::sort(currentPoints.begin(), currentPoints.end(), PointSorter());
2719
2720         // map to pattern space
2721         for (int ndx = 0; ndx < (int)currentPoints.size(); ++ndx)
2722                 currentPoints[ndx].center = currentPoints[ndx].center * config.patternSize + config.patternPos;
2723
2724         currentPoints.swap(data);
2725 }
2726
2727 bool PointRenderCase::verifyNarrowPointPattern (const tcu::Surface& viewport, const std::vector<GeneratedPoint>& refPoints, const ProjectedBBox& bbox, int& logFloodCounter)
2728 {
2729         bool anyError = false;
2730
2731         // check that there is something near each sample
2732         for (int pointNdx = 0; pointNdx < (int)refPoints.size(); ++pointNdx)
2733         {
2734                 const float                             epsilon         = 1.0e-6f;
2735                 const GeneratedPoint&   refPoint        = refPoints[pointNdx];
2736
2737                 // skip points not in the the bbox, treat boundary as "in"
2738                 if (refPoint.center.x() < bbox.min.x() - epsilon ||
2739                         refPoint.center.y() < bbox.min.y() - epsilon ||
2740                         refPoint.center.x() > bbox.max.x() + epsilon ||
2741                         refPoint.center.y() > bbox.max.y() + epsilon)
2742                         continue;
2743                 else
2744                 {
2745                         // transform to viewport coords
2746                         const tcu::IVec2 pixelCenter(deRoundFloatToInt32((refPoint.center.x() * 0.5f + 0.5f) * viewport.getWidth()), deRoundFloatToInt32((refPoint.center.y() * 0.5f + 0.5f) * viewport.getHeight()));
2747
2748                         // find rasterized point in the result
2749                         if (pixelCenter.x() < 1 || pixelCenter.y() < 1 || pixelCenter.x() >= viewport.getWidth()-1 || pixelCenter.y() >= viewport.getHeight()-1)
2750                         {
2751                                 // viewport boundary, assume point is fine
2752                         }
2753                         else
2754                         {
2755                                 const int       componentNdx    = (refPoint.even) ? (1) : (2); // analyze either green or blue channel
2756                                 bool            foundResult             = false;
2757
2758                                 // check neighborhood
2759                                 for (int dy = -1; dy < 2 && !foundResult; ++dy)
2760                                 for (int dx = -1; dx < 2 && !foundResult; ++dx)
2761                                 {
2762                                         const tcu::IVec2        testPos (pixelCenter.x() + dx, pixelCenter.y() + dy);
2763                                         const tcu::RGBA         color   = viewport.getPixel(testPos.x(), testPos.y());
2764
2765                                         if (color.toIVec()[componentNdx] > 0)
2766                                                 foundResult = true;
2767                                 }
2768
2769                                 if (!foundResult)
2770                                 {
2771                                         anyError = true;
2772
2773                                         if (--logFloodCounter >= 0)
2774                                         {
2775                                                 m_testCtx.getLog()
2776                                                         << tcu::TestLog::Message
2777                                                         << "Missing point near " << pixelCenter << ", vertex coordinates=" << refPoint.center.swizzle(0, 1) << "."
2778                                                         << tcu::TestLog::EndMessage;
2779                                         }
2780                                 }
2781                         }
2782                 }
2783         }
2784
2785         return anyError;
2786 }
2787
2788 bool PointRenderCase::verifyWidePointPattern (const tcu::Surface& viewport, const std::vector<GeneratedPoint>& refPoints, const ProjectedBBox& bbox, int& logFloodCounter)
2789 {
2790         bool anyError = false;
2791
2792         // check that there is something near each sample
2793         for (int pointNdx = 0; pointNdx < (int)refPoints.size(); ++pointNdx)
2794         {
2795                 const GeneratedPoint& refPoint = refPoints[pointNdx];
2796
2797                 if (refPoint.center.x() >= bbox.min.x() &&
2798                         refPoint.center.y() >= bbox.min.y() &&
2799                         refPoint.center.x() <= bbox.max.x() &&
2800                         refPoint.center.y() <= bbox.max.y())
2801                 {
2802                         // point fully in the bounding box
2803                         anyError |= !verifyWidePoint(viewport, refPoint, bbox, POINT_FULL, logFloodCounter);
2804                 }
2805                 else if (refPoint.center.x() >= bbox.min.x() + refPoint.size / 2.0f &&
2806                                  refPoint.center.y() >= bbox.min.y() - refPoint.size / 2.0f &&
2807                                  refPoint.center.x() <= bbox.max.x() + refPoint.size / 2.0f &&
2808                                  refPoint.center.y() <= bbox.max.y() - refPoint.size / 2.0f)
2809                 {
2810                         // point leaks into bounding box
2811                         anyError |= !verifyWidePoint(viewport, refPoint, bbox, POINT_PARTIAL, logFloodCounter);
2812                 }
2813         }
2814
2815         return anyError;
2816 }
2817
2818 bool PointRenderCase::verifyWidePoint (const tcu::Surface& viewport, const GeneratedPoint& refPoint, const ProjectedBBox& bbox, ResultPointType pointType, int& logFloodCounter)
2819 {
2820         const int                       componentNdx            = (refPoint.even) ? (1) : (2);
2821         const int                       halfPointSizeCeil       = (refPoint.size + 1) / 2;
2822         const int                       halfPointSizeFloor      = (refPoint.size + 1) / 2;
2823         const tcu::IVec4        viewportBBoxArea        = getViewportBoundingBoxArea(bbox, tcu::IVec2(viewport.getWidth(), viewport.getHeight()), (float)refPoint.size);
2824         const tcu::IVec4        verificationArea        = tcu::IVec4(de::max(viewportBBoxArea.x(), 0),
2825                                                                                                                  de::max(viewportBBoxArea.y(), 0),
2826                                                                                                                  de::min(viewportBBoxArea.z(), viewport.getWidth()),
2827                                                                                                                  de::min(viewportBBoxArea.w(), viewport.getHeight()));
2828         const tcu::IVec2        pointPos                        = tcu::IVec2(deRoundFloatToInt32((refPoint.center.x()*0.5f + 0.5f) * viewport.getWidth()),
2829                                                                                                                  deRoundFloatToInt32((refPoint.center.y()*0.5f + 0.5f) * viewport.getHeight()));
2830
2831         // find any fragment within the point that is inside the bbox, start search at the center
2832
2833         if (pointPos.x() >= verificationArea.x() &&
2834                 pointPos.y() >= verificationArea.y() &&
2835                 pointPos.x() < verificationArea.z() &&
2836                 pointPos.y() < verificationArea.w())
2837         {
2838                 if (viewport.getPixel(pointPos.x(), pointPos.y()).toIVec()[componentNdx])
2839                         return verifyWidePointAt(pointPos, viewport, refPoint, verificationArea, pointType, componentNdx, logFloodCounter);
2840         }
2841
2842         for (int dy = -halfPointSizeCeil; dy <= halfPointSizeCeil; ++dy)
2843         for (int dx = -halfPointSizeCeil; dx <= halfPointSizeCeil; ++dx)
2844         {
2845                 const tcu::IVec2 testPos = pointPos + tcu::IVec2(dx, dy);
2846
2847                 if (dx == 0 && dy == 0)
2848                         continue;
2849
2850                 if (testPos.x() >= verificationArea.x() &&
2851                         testPos.y() >= verificationArea.y() &&
2852                         testPos.x() < verificationArea.z() &&
2853                         testPos.y() < verificationArea.w())
2854                 {
2855                         if (viewport.getPixel(testPos.x(), testPos.y()).toIVec()[componentNdx])
2856                                 return verifyWidePointAt(testPos, viewport, refPoint, verificationArea, pointType, componentNdx, logFloodCounter);
2857                 }
2858         }
2859
2860         // could not find point, this is only ok near boundaries
2861         if (pointPos.x() + halfPointSizeFloor <  verificationArea.x() - 1 ||
2862                 pointPos.y() + halfPointSizeFloor <  verificationArea.y() - 1 ||
2863                 pointPos.x() - halfPointSizeFloor >= verificationArea.z() - 1 ||
2864                 pointPos.y() - halfPointSizeFloor >= verificationArea.w() - 1)
2865                 return true;
2866
2867         if (--logFloodCounter >= 0)
2868         {
2869                 m_testCtx.getLog()
2870                         << tcu::TestLog::Message
2871                         << "Missing wide point near " << pointPos << ", vertex coordinates=" << refPoint.center.swizzle(0, 1) << "."
2872                         << tcu::TestLog::EndMessage;
2873         }
2874
2875         return false;
2876 }
2877
2878 bool PointRenderCase::verifyWidePointAt (const tcu::IVec2& pointPos, const tcu::Surface& viewport, const GeneratedPoint& refPoint, const tcu::IVec4& bbox, ResultPointType pointType, int componentNdx, int& logFloodCounter)
2879 {
2880         const int                               expectedPointSize               = refPoint.size;
2881         bool                                    viewportClippedTop              = false;
2882         bool                                    viewportClippedBottom   = false;
2883         bool                                    primitiveClippedTop             = false;
2884         bool                                    primitiveClippedBottom  = false;
2885         std::vector<tcu::IVec2> widthsUpwards;
2886         std::vector<tcu::IVec2> widthsDownwards;
2887         std::vector<tcu::IVec2> widths;
2888
2889         // search upwards
2890         for (int y = pointPos.y();; --y)
2891         {
2892                 if (y < bbox.y() || y < 0)
2893                 {
2894                         if (y < bbox.y())
2895                                 primitiveClippedTop = true;
2896                         if (y < 0)
2897                                 viewportClippedTop = true;
2898                         break;
2899                 }
2900                 else if (pointPos.y() - y > expectedPointSize)
2901                 {
2902                         // no need to go further than point height
2903                         break;
2904                 }
2905                 else if (viewport.getPixel(pointPos.x(), y).toIVec()[componentNdx] == 0)
2906                 {
2907                         break;
2908                 }
2909                 else
2910                 {
2911                         widthsUpwards.push_back(scanPointWidthAt(tcu::IVec2(pointPos.x(), y), viewport, expectedPointSize, componentNdx));
2912                 }
2913         }
2914
2915         // top is clipped
2916         if ((viewportClippedTop || (pointType == POINT_PARTIAL && primitiveClippedTop)) && !widthsUpwards.empty())
2917         {
2918                 const tcu::IVec2&       range                   = widthsUpwards.back();
2919                 const bool                      squareFits              = (range.y() - range.x() + 1) >= expectedPointSize;
2920                 const bool                      widthClipped    = (pointType == POINT_PARTIAL) && (range.x() <= bbox.x() || range.y() >= bbox.z());
2921
2922                 if (squareFits || widthClipped)
2923                         return true;
2924         }
2925
2926         // and downwards
2927         for (int y = pointPos.y()+1;; ++y)
2928         {
2929                 if (y >= bbox.w() || y >= viewport.getHeight())
2930                 {
2931                         if (y >= bbox.w())
2932                                 primitiveClippedBottom = true;
2933                         if (y >= viewport.getHeight())
2934                                 viewportClippedBottom = true;
2935                         break;
2936                 }
2937                 else if (y - pointPos.y() > expectedPointSize)
2938                 {
2939                         // no need to go further than point height
2940                         break;
2941                 }
2942                 else if (viewport.getPixel(pointPos.x(), y).toIVec()[componentNdx] == 0)
2943                 {
2944                         break;
2945                 }
2946                 else
2947                 {
2948                         widthsDownwards.push_back(scanPointWidthAt(tcu::IVec2(pointPos.x(), y), viewport, expectedPointSize, componentNdx));
2949                 }
2950         }
2951
2952         // bottom is clipped
2953         if ((viewportClippedBottom || (pointType == POINT_PARTIAL && primitiveClippedBottom)) && !(widthsDownwards.empty() && widthsUpwards.empty()))
2954         {
2955                 const tcu::IVec2&       range                   = (widthsDownwards.empty()) ? (widthsUpwards.front()) : (widthsDownwards.back());
2956                 const bool                      squareFits              = (range.y() - range.x() + 1) >= expectedPointSize;
2957                 const bool                      bboxClipped             = (pointType == POINT_PARTIAL) && (range.x() <= bbox.x() || range.y() >= bbox.z()-1);
2958                 const bool                      viewportClipped = range.x() <= 0 || range.y() >= viewport.getWidth()-1;
2959
2960                 if (squareFits || bboxClipped || viewportClipped)
2961                         return true;
2962         }
2963
2964         // would square point would fit into the rasterized area
2965
2966         for (int ndx = 0; ndx < (int)widthsUpwards.size(); ++ndx)
2967                 widths.push_back(widthsUpwards[(int)widthsUpwards.size() - ndx - 1]);
2968         for (int ndx = 0; ndx < (int)widthsDownwards.size(); ++ndx)
2969                 widths.push_back(widthsDownwards[ndx]);
2970         DE_ASSERT(!widths.empty());
2971
2972         for (int y = 0; y < (int)widths.size() - expectedPointSize + 1; ++y)
2973         {
2974                 tcu::IVec2 unionRange = widths[y];
2975
2976                 for (int dy = 1; dy < expectedPointSize; ++dy)
2977                 {
2978                         unionRange.x() = de::max(unionRange.x(), widths[y+dy].x());
2979                         unionRange.y() = de::min(unionRange.y(), widths[y+dy].y());
2980                 }
2981
2982                 // would a N x N block fit here?
2983                 {
2984                         const bool squareFits           = (unionRange.y() - unionRange.x() + 1) >= expectedPointSize;
2985                         const bool bboxClipped          = (pointType == POINT_PARTIAL) && (unionRange.x() <= bbox.x() || unionRange.y() >= bbox.z()-1);
2986                         const bool viewportClipped      = unionRange.x() <= 0 || unionRange.y() >= viewport.getWidth()-1;
2987
2988                         if (squareFits || bboxClipped || viewportClipped)
2989                                 return true;
2990                 }
2991         }
2992
2993         if (--logFloodCounter >= 0)
2994         {
2995                 m_testCtx.getLog()
2996                         << tcu::TestLog::Message
2997                         << "Missing " << expectedPointSize << "x" << expectedPointSize << " point near " << pointPos << ", vertex coordinates=" << refPoint.center.swizzle(0, 1) << "."
2998                         << tcu::TestLog::EndMessage;
2999         }
3000         return false;
3001 }
3002
3003 tcu::IVec2 PointRenderCase::scanPointWidthAt (const tcu::IVec2& pointPos, const tcu::Surface& viewport, int expectedPointSize, int componentNdx) const
3004 {
3005         int minX = pointPos.x();
3006         int maxX = pointPos.x();
3007
3008         // search horizontally for a point edges
3009         for (int x = pointPos.x()-1; x >= 0; --x)
3010         {
3011                 if (viewport.getPixel(x, pointPos.y()).toIVec()[componentNdx] == 0)
3012                         break;
3013
3014                 // no need to go further than point width
3015                 if (pointPos.x() - x > expectedPointSize)
3016                         break;
3017
3018                 minX = x;
3019         }
3020         for (int x = pointPos.x()+1; x < viewport.getWidth(); ++x)
3021         {
3022                 if (viewport.getPixel(x, pointPos.y()).toIVec()[componentNdx] == 0)
3023                         break;
3024
3025                 // no need to go further than point width
3026                 if (x - pointPos.x() > expectedPointSize)
3027                         break;
3028
3029                 maxX = x;
3030         }
3031
3032         return tcu::IVec2(minX, maxX);
3033 }
3034
3035 class BlitFboCase : public TestCase
3036 {
3037 public:
3038         enum RenderTarget
3039         {
3040                 TARGET_DEFAULT = 0,
3041                 TARGET_FBO,
3042
3043                 TARGET_LAST
3044         };
3045
3046                                                         BlitFboCase                                             (Context& context, const char* name, const char* description, RenderTarget src, RenderTarget dst);
3047                                                         ~BlitFboCase                                    (void);
3048
3049 private:
3050         enum
3051         {
3052                 FBO_SIZE = 256,
3053         };
3054
3055         struct BlitArgs
3056         {
3057                 tcu::IVec4      src;
3058                 tcu::IVec4      dst;
3059                 tcu::Vec4       bboxMin;
3060                 tcu::Vec4       bboxMax;
3061                 bool            linear;
3062         };
3063
3064         void                                                    init                                    (void);
3065         void                                                    deinit                                  (void);
3066         IterateResult                                   iterate                                 (void);
3067
3068         void                                                    fillSourceWithPattern   (void);
3069         bool                                                    verifyImage                             (const BlitArgs& args);
3070
3071         const RenderTarget                              m_src;
3072         const RenderTarget                              m_dst;
3073
3074         std::vector<BlitArgs>                   m_iterations;
3075         int                                                             m_iteration;
3076         de::MovePtr<glu::Framebuffer>   m_srcFbo;
3077         de::MovePtr<glu::Framebuffer>   m_dstFbo;
3078         de::MovePtr<glu::Renderbuffer>  m_srcRbo;
3079         de::MovePtr<glu::Renderbuffer>  m_dstRbo;
3080         de::MovePtr<glu::ShaderProgram> m_program;
3081         de::MovePtr<glu::Buffer>                m_vbo;
3082 };
3083
3084 BlitFboCase::BlitFboCase (Context& context, const char* name, const char* description, RenderTarget src, RenderTarget dst)
3085         : TestCase              (context, name, description)
3086         , m_src                 (src)
3087         , m_dst                 (dst)
3088         , m_iteration   (0)
3089 {
3090         DE_ASSERT(src < TARGET_LAST);
3091         DE_ASSERT(dst < TARGET_LAST);
3092 }
3093
3094 BlitFboCase::~BlitFboCase (void)
3095 {
3096         deinit();
3097 }
3098
3099 void BlitFboCase::init (void)
3100 {
3101         const int                               numIterations                   = 12;
3102         const bool                              defaultFBMultisampled   = (m_context.getRenderTarget().getNumSamples() > 1);
3103         const glw::Functions&   gl                                              = m_context.getRenderContext().getFunctions();
3104         de::Random                              rnd                                             (0xABC123);
3105
3106         m_testCtx.getLog()
3107                 << tcu::TestLog::Message
3108                 << "Using BlitFramebuffer to blit area from "
3109                         << ((m_src == TARGET_DEFAULT) ? ("default fb") : ("fbo"))
3110                         << " to "
3111                         << ((m_dst == TARGET_DEFAULT) ? ("default fb") : ("fbo"))
3112                         << ".\n"
3113                 << "Varying blit arguments and primitive bounding box between iterations.\n"
3114                 << "Expecting bounding box to have no effect on blitting.\n"
3115                 << "Source framebuffer is filled with green-yellow grid.\n"
3116                 << tcu::TestLog::EndMessage;
3117
3118         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_primitive_bounding_box"))
3119                 throw tcu::NotSupportedError("Test requires GL_EXT_primitive_bounding_box extension");
3120         if (m_dst == TARGET_DEFAULT && defaultFBMultisampled)
3121                 throw tcu::NotSupportedError("Test requires non-multisampled default framebuffer");
3122
3123         // resources
3124
3125         if (m_src == TARGET_FBO)
3126         {
3127                 m_srcRbo = de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(m_context.getRenderContext()));
3128                 gl.bindRenderbuffer(GL_RENDERBUFFER, **m_srcRbo);
3129                 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, FBO_SIZE, FBO_SIZE);
3130                 GLU_EXPECT_NO_ERROR(gl.getError(), "src rbo");
3131
3132                 m_srcFbo = de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(m_context.getRenderContext()));
3133                 gl.bindFramebuffer(GL_FRAMEBUFFER, **m_srcFbo);
3134                 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **m_srcRbo);
3135                 GLU_EXPECT_NO_ERROR(gl.getError(), "src fbo");
3136         }
3137
3138         if (m_dst == TARGET_FBO)
3139         {
3140                 m_dstRbo = de::MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(m_context.getRenderContext()));
3141                 gl.bindRenderbuffer(GL_RENDERBUFFER, **m_dstRbo);
3142                 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, FBO_SIZE, FBO_SIZE);
3143                 GLU_EXPECT_NO_ERROR(gl.getError(), "dst rbo");
3144
3145                 m_dstFbo = de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(m_context.getRenderContext()));
3146                 gl.bindFramebuffer(GL_FRAMEBUFFER, **m_dstFbo);
3147                 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **m_dstRbo);
3148                 GLU_EXPECT_NO_ERROR(gl.getError(), "dst fbo");
3149         }
3150
3151         {
3152                 static const char* const s_vertexSource =       "#version 310 es\n"
3153                                                                                                         "in highp vec4 a_position;\n"
3154                                                                                                         "out highp vec4 v_position;\n"
3155                                                                                                         "void main()\n"
3156                                                                                                         "{\n"
3157                                                                                                         "       gl_Position = a_position;\n"
3158                                                                                                         "       v_position = a_position;\n"
3159                                                                                                         "}\n";
3160                 static const char* const s_fragmentSource =     "#version 310 es\n"
3161                                                                                                         "in mediump vec4 v_position;\n"
3162                                                                                                         "layout(location=0) out mediump vec4 dEQP_FragColor;\n"
3163                                                                                                         "void main()\n"
3164                                                                                                         "{\n"
3165                                                                                                         "       const mediump vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
3166                                                                                                         "       const mediump vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
3167                                                                                                         "       dEQP_FragColor = (step(0.1, mod(v_position.x, 0.2)) == step(0.1, mod(v_position.y, 0.2))) ? (green) : (yellow);\n"
3168                                                                                                         "}\n";
3169
3170                 m_program = de::MovePtr<glu::ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_vertexSource) << glu::FragmentSource(s_fragmentSource)));
3171
3172                 if (!m_program->isOk())
3173                 {
3174                         m_testCtx.getLog() << *m_program;
3175                         throw tcu::TestError("failed to build program");
3176                 }
3177         }
3178
3179         {
3180                 static const tcu::Vec4 s_quadCoords[] =
3181                 {
3182                         tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
3183                         tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
3184                         tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
3185                         tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
3186                 };
3187
3188                 m_vbo = de::MovePtr<glu::Buffer>(new glu::Buffer(m_context.getRenderContext()));
3189
3190                 gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
3191                 gl.bufferData(GL_ARRAY_BUFFER, sizeof(s_quadCoords), s_quadCoords, GL_STATIC_DRAW);
3192                 GLU_EXPECT_NO_ERROR(gl.getError(), "set buf");
3193         }
3194
3195         // gen iterations
3196
3197         {
3198                 const tcu::IVec2 srcSize = (m_src == TARGET_DEFAULT) ? (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight())) : (tcu::IVec2(FBO_SIZE, FBO_SIZE));
3199                 const tcu::IVec2 dstSize = (m_dst == TARGET_DEFAULT) ? (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight())) : (tcu::IVec2(FBO_SIZE, FBO_SIZE));
3200
3201                 m_testCtx.getLog()
3202                         << tcu::TestLog::Message
3203                         << "srcSize = " << srcSize << "\n"
3204                         << "dstSize = " << dstSize << "\n"
3205                         << tcu::TestLog::EndMessage;
3206
3207                 for (int ndx = 0; ndx < numIterations; ++ndx)
3208                 {
3209                         BlitArgs args;
3210
3211                         if (m_src == TARGET_DEFAULT && defaultFBMultisampled)
3212                         {
3213                                 const tcu::IVec2        unionSize       = tcu::IVec2(de::min(srcSize.x(), dstSize.x()), de::min(srcSize.y(), dstSize.y()));
3214                                 const int                       srcWidth        = rnd.getInt(1, unionSize.x());
3215                                 const int                       srcHeight       = rnd.getInt(1, unionSize.y());
3216                                 const int                       srcX            = rnd.getInt(0, unionSize.x() - srcWidth);
3217                                 const int                       srcY            = rnd.getInt(0, unionSize.y() - srcHeight);
3218
3219                                 args.src.x() = srcX;
3220                                 args.src.y() = srcY;
3221                                 args.src.z() = srcX + srcWidth;
3222                                 args.src.w() = srcY + srcHeight;
3223
3224                                 args.dst = args.src;
3225                         }
3226                         else
3227                         {
3228                                 const int       srcWidth        = rnd.getInt(1, srcSize.x());
3229                                 const int       srcHeight       = rnd.getInt(1, srcSize.y());
3230                                 const int       srcX            = rnd.getInt(0, srcSize.x() - srcWidth);
3231                                 const int       srcY            = rnd.getInt(0, srcSize.y() - srcHeight);
3232                                 const int       dstWidth        = rnd.getInt(1, dstSize.x());
3233                                 const int       dstHeight       = rnd.getInt(1, dstSize.y());
3234                                 const int       dstX            = rnd.getInt(-(dstWidth / 2), dstSize.x() - (dstWidth+1) / 2);          // allow dst go out of bounds
3235                                 const int       dstY            = rnd.getInt(-(dstHeight / 2), dstSize.y() - (dstHeight+1)  / 2);
3236
3237                                 args.src.x() = srcX;
3238                                 args.src.y() = srcY;
3239                                 args.src.z() = srcX + srcWidth;
3240                                 args.src.w() = srcY + srcHeight;
3241                                 args.dst.x() = dstX;
3242                                 args.dst.y() = dstY;
3243                                 args.dst.z() = dstX + dstWidth;
3244                                 args.dst.w() = dstY + dstHeight;
3245                         }
3246
3247                         args.bboxMin.x() = rnd.getFloat(-1.1f, 1.1f);
3248                         args.bboxMin.y() = rnd.getFloat(-1.1f, 1.1f);
3249                         args.bboxMin.z() = rnd.getFloat(-1.1f, 1.1f);
3250                         args.bboxMin.w() = rnd.getFloat( 0.9f, 1.1f);
3251
3252                         args.bboxMax.x() = rnd.getFloat(-1.1f, 1.1f);
3253                         args.bboxMax.y() = rnd.getFloat(-1.1f, 1.1f);
3254                         args.bboxMax.z() = rnd.getFloat(-1.1f, 1.1f);
3255                         args.bboxMax.w() = rnd.getFloat( 0.9f, 1.1f);
3256
3257                         if (args.bboxMin.x() / args.bboxMin.w() > args.bboxMax.x() / args.bboxMax.w())
3258                                 std::swap(args.bboxMin.x(), args.bboxMax.x());
3259                         if (args.bboxMin.y() / args.bboxMin.w() > args.bboxMax.y() / args.bboxMax.w())
3260                                 std::swap(args.bboxMin.y(), args.bboxMax.y());
3261                         if (args.bboxMin.z() / args.bboxMin.w() > args.bboxMax.z() / args.bboxMax.w())
3262                                 std::swap(args.bboxMin.z(), args.bboxMax.z());
3263
3264                         args.linear = rnd.getBool();
3265
3266                         m_iterations.push_back(args);
3267                 }
3268         }
3269 }
3270
3271 void BlitFboCase::deinit (void)
3272 {
3273         m_srcFbo.clear();
3274         m_srcRbo.clear();
3275         m_dstFbo.clear();
3276         m_dstRbo.clear();
3277         m_program.clear();
3278         m_vbo.clear();
3279 }
3280
3281 BlitFboCase::IterateResult BlitFboCase::iterate (void)
3282 {
3283         const tcu::ScopedLogSection     section         (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration), "Iteration " + de::toString(m_iteration+1) + " / " + de::toString((int)m_iterations.size()));
3284         const BlitArgs&                         blitCfg         = m_iterations[m_iteration];
3285         const glw::Functions&           gl                      = m_context.getRenderContext().getFunctions();
3286
3287         if (m_iteration == 0)
3288                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3289
3290         // fill source with test pattern. Default fb must be filled for each iteration because contents might not survive the swap
3291         if (m_src == TARGET_DEFAULT || m_iteration == 0)
3292                 fillSourceWithPattern();
3293
3294         m_testCtx.getLog()
3295                 << tcu::TestLog::Message
3296                 << "Set bounding box:\n"
3297                 << "\tmin:" << blitCfg.bboxMin << "\n"
3298                 << "\tmax:" << blitCfg.bboxMax << "\n"
3299                 << "Blit:\n"
3300                 <<      "\tsrc: " << blitCfg.src << "\n"
3301                 <<      "\tdst: " << blitCfg.dst << "\n"
3302                 <<      "\tfilter: " << ((blitCfg.linear) ? ("linear") : ("nearest"))
3303                 << tcu::TestLog::EndMessage;
3304
3305         gl.primitiveBoundingBoxEXT(blitCfg.bboxMin.x(), blitCfg.bboxMin.y(), blitCfg.bboxMin.z(), blitCfg.bboxMin.w(),
3306                                                            blitCfg.bboxMax.x(), blitCfg.bboxMax.y(), blitCfg.bboxMax.z(), blitCfg.bboxMax.w());
3307
3308         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, (m_dst == TARGET_FBO) ? (**m_dstFbo) : (m_context.getRenderContext().getDefaultFramebuffer()));
3309         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3310         gl.clear(GL_COLOR_BUFFER_BIT);
3311
3312         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, (m_src == TARGET_FBO) ? (**m_srcFbo) : (m_context.getRenderContext().getDefaultFramebuffer()));
3313         gl.blitFramebuffer(blitCfg.src.x(), blitCfg.src.y(), blitCfg.src.z(), blitCfg.src.w(),
3314                                            blitCfg.dst.x(), blitCfg.dst.y(), blitCfg.dst.z(), blitCfg.dst.w(),
3315                                            GL_COLOR_BUFFER_BIT,
3316                                            ((blitCfg.linear) ? (GL_LINEAR) : (GL_NEAREST)));
3317         GLU_EXPECT_NO_ERROR(gl.getError(), "blit");
3318
3319         if (!verifyImage(blitCfg))
3320                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected blit result");
3321
3322         return (++m_iteration == (int)m_iterations.size()) ? (STOP) : (CONTINUE);
3323 }
3324
3325 bool BlitFboCase::verifyImage (const BlitArgs& args)
3326 {
3327         const int                               colorThreshold  = 4; //!< this test case is not about how color is preserved, allow almost anything
3328         const tcu::IVec2                dstSize                 = (m_dst == TARGET_DEFAULT) ? (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight())) : (tcu::IVec2(FBO_SIZE, FBO_SIZE));
3329         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
3330         tcu::Surface                    viewport                (dstSize.x(), dstSize.y());
3331         tcu::Surface                    errorMask               (dstSize.x(), dstSize.y());
3332         bool                                    anyError                = false;
3333
3334         m_testCtx.getLog()
3335                 << tcu::TestLog::Message
3336                 << "Verifying blit result"
3337                 << tcu::TestLog::EndMessage;
3338
3339         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, (m_dst == TARGET_FBO) ? (**m_dstFbo) : (m_context.getRenderContext().getDefaultFramebuffer()));
3340         glu::readPixels(m_context.getRenderContext(), 0, 0, viewport.getAccess());
3341
3342         tcu::clear(errorMask.getAccess(), tcu::IVec4(0, 0, 0, 255));
3343
3344         for (int y = 0; y < dstSize.y(); ++y)
3345         for (int x = 0; x < dstSize.x(); ++x)
3346         {
3347                 const tcu::RGBA color   = viewport.getPixel(x, y);
3348                 const bool              inside  = (x >= args.dst.x() && x < args.dst.z() && y >= args.dst.y() && y < args.dst.w());
3349                 const bool              error   = (inside) ? (color.getGreen() < 255 - colorThreshold || color.getBlue() > colorThreshold)
3350                                                                                    : (color.getRed() > colorThreshold || color.getGreen() > colorThreshold || color.getBlue() > colorThreshold);
3351
3352                 if (error)
3353                 {
3354                         anyError = true;
3355                         errorMask.setPixel(x, y, tcu::RGBA::red);
3356                 }
3357         }
3358
3359         if (anyError)
3360         {
3361                 m_testCtx.getLog()
3362                         << tcu::TestLog::Message
3363                         << "Image verification failed."
3364                         << tcu::TestLog::EndMessage
3365                         << tcu::TestLog::ImageSet("Images", "Image verification")
3366                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewport.getAccess())
3367                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
3368                         << tcu::TestLog::EndImageSet;
3369                 return false;
3370         }
3371         else
3372         {
3373                 m_testCtx.getLog()
3374                         << tcu::TestLog::Message
3375                         << "Result image ok."
3376                         << tcu::TestLog::EndMessage
3377                         << tcu::TestLog::ImageSet("Images", "Image verification")
3378                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewport.getAccess())
3379                         << tcu::TestLog::EndImageSet;
3380                 return true;
3381         }
3382 }
3383
3384 void BlitFboCase::fillSourceWithPattern (void)
3385 {
3386         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
3387         const tcu::IVec2                srcSize         = (m_src == TARGET_DEFAULT) ? (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight())) : (tcu::IVec2(FBO_SIZE, FBO_SIZE));
3388         const int                               posLocation     = gl.getAttribLocation(m_program->getProgram(), "a_position");
3389
3390         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, (m_src == TARGET_FBO) ? (**m_srcFbo) : (m_context.getRenderContext().getDefaultFramebuffer()));
3391         gl.viewport(0, 0, srcSize.x(), srcSize.y());
3392         gl.useProgram(m_program->getProgram());
3393
3394         gl.clearColor(0.0f, 0.0f, 1.0f, 1.0f);
3395         gl.clear(GL_COLOR_BUFFER_BIT);
3396
3397         gl.enableVertexAttribArray(posLocation);
3398         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 4 * (int)sizeof(float), NULL);
3399         gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
3400         GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
3401 }
3402
3403 class DepthDrawCase : public TestCase
3404 {
3405 public:
3406         enum DepthType
3407         {
3408                 DEPTH_BUILTIN = 0,
3409                 DEPTH_USER_DEFINED,
3410
3411                 DEPTH_LAST
3412         };
3413         enum BBoxState
3414         {
3415                 STATE_GLOBAL = 0,
3416                 STATE_PER_PRIMITIVE,
3417
3418                 STATE_LAST
3419         };
3420         enum BBoxSize
3421         {
3422                 BBOX_EQUAL = 0,
3423                 BBOX_LARGER,
3424
3425                 BBOX_LAST
3426         };
3427
3428                                                                         DepthDrawCase                                   (Context& context, const char* name, const char* description, DepthType depthType, BBoxState state, BBoxSize bboxSize);
3429                                                                         ~DepthDrawCase                                  (void);
3430
3431 private:
3432         void                                                    init                                                    (void);
3433         void                                                    deinit                                                  (void);
3434         IterateResult                                   iterate                                                 (void);
3435
3436         std::string                                             genVertexSource                                 (void) const;
3437         std::string                                             genFragmentSource                               (void) const;
3438         std::string                                             genTessellationControlSource    (void) const;
3439         std::string                                             genTessellationEvaluationSource (void) const;
3440         void                                                    generateAttributeData                   (std::vector<tcu::Vec4>& data) const;
3441         bool                                                    verifyImage                                             (const tcu::Surface& viewport) const;
3442
3443         enum
3444         {
3445                 RENDER_AREA_SIZE = 256,
3446         };
3447
3448         struct LayerInfo
3449         {
3450                 float           zOffset;
3451                 float           zScale;
3452                 tcu::Vec4       color1;
3453                 tcu::Vec4       color2;
3454         };
3455
3456         const int                                               m_numLayers;
3457         const int                                               m_gridSize;
3458
3459         const DepthType                                 m_depthType;
3460         const BBoxState                                 m_state;
3461         const BBoxSize                                  m_bboxSize;
3462
3463         de::MovePtr<glu::ShaderProgram> m_program;
3464         de::MovePtr<glu::Buffer>                m_vbo;
3465         std::vector<LayerInfo>                  m_layers;
3466 };
3467
3468 DepthDrawCase::DepthDrawCase (Context& context, const char* name, const char* description, DepthType depthType, BBoxState state, BBoxSize bboxSize)
3469         : TestCase              (context, name, description)
3470         , m_numLayers   (14)
3471         , m_gridSize    (24)
3472         , m_depthType   (depthType)
3473         , m_state               (state)
3474         , m_bboxSize    (bboxSize)
3475 {
3476         DE_ASSERT(depthType < DEPTH_LAST);
3477         DE_ASSERT(state < STATE_LAST);
3478         DE_ASSERT(bboxSize < BBOX_LAST);
3479 }
3480
3481 DepthDrawCase::~DepthDrawCase (void)
3482 {
3483         deinit();
3484 }
3485
3486 void DepthDrawCase::init (void)
3487 {
3488         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3489
3490         // requirements
3491
3492         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_primitive_bounding_box"))
3493                 throw tcu::NotSupportedError("Test requires GL_EXT_primitive_bounding_box extension");
3494         if (m_state == STATE_PER_PRIMITIVE && !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
3495                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
3496         if (m_context.getRenderTarget().getDepthBits() == 0)
3497                 throw tcu::NotSupportedError("Test requires depth buffer");
3498         if (m_context.getRenderTarget().getWidth() < RENDER_AREA_SIZE || m_context.getRenderTarget().getHeight() < RENDER_AREA_SIZE)
3499                 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_AREA_SIZE) + "x" + de::toString<int>(RENDER_AREA_SIZE) + " viewport");
3500
3501         // log
3502         m_testCtx.getLog()
3503                 << tcu::TestLog::Message
3504                 << "Rendering multiple triangle grids with with different z coordinates.\n"
3505                 << "Topmost grid is green-yellow, other grids are blue-red.\n"
3506                 << "Expecting only the green-yellow grid to be visible.\n"
3507                 << "Setting primitive bounding box "
3508                         << ((m_bboxSize == BBOX_EQUAL) ? ("to exactly cover") : ("to cover"))
3509                         << ((m_state == STATE_GLOBAL) ? (" each grid") : (" each triangle"))
3510                         << ((m_bboxSize == BBOX_EQUAL) ? (".") : (" and include some padding."))
3511                         << "\n"
3512                 << "Set bounding box using "
3513                         << ((m_state == STATE_GLOBAL) ? ("PRIMITIVE_BOUNDING_BOX_EXT state") : ("gl_BoundingBoxEXT output"))
3514                         << "\n"
3515                 << ((m_depthType == DEPTH_USER_DEFINED) ? ("Fragment depth is set in the fragment shader") : (""))
3516                 << tcu::TestLog::EndMessage;
3517
3518         // resources
3519
3520         {
3521                 glu::ProgramSources sources;
3522                 sources << glu::VertexSource(genVertexSource());
3523                 sources << glu::FragmentSource(genFragmentSource());
3524
3525                 if (m_state == STATE_PER_PRIMITIVE)
3526                         sources << glu::TessellationControlSource(genTessellationControlSource())
3527                                         << glu::TessellationEvaluationSource(genTessellationEvaluationSource());
3528
3529                 m_program = de::MovePtr<glu::ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(), sources));
3530                 GLU_EXPECT_NO_ERROR(gl.getError(), "build program");
3531
3532                 {
3533                         const tcu::ScopedLogSection section(m_testCtx.getLog(), "ShaderProgram", "Shader program");
3534                         m_testCtx.getLog() << *m_program;
3535                 }
3536
3537                 if (!m_program->isOk())
3538                         throw tcu::TestError("failed to build program");
3539         }
3540
3541         {
3542                 std::vector<tcu::Vec4> data;
3543
3544                 generateAttributeData(data);
3545
3546                 m_vbo = de::MovePtr<glu::Buffer>(new glu::Buffer(m_context.getRenderContext()));
3547                 gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
3548                 gl.bufferData(GL_ARRAY_BUFFER, (int)(sizeof(tcu::Vec4) * data.size()), &data[0], GL_STATIC_DRAW);
3549                 GLU_EXPECT_NO_ERROR(gl.getError(), "buf upload");
3550         }
3551
3552         // gen layers
3553         {
3554                 de::Random rnd(0x12345);
3555
3556                 m_layers.resize(m_numLayers);
3557                 for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
3558                 {
3559                         m_layers[layerNdx].zOffset      = ((float)layerNdx / m_numLayers) * 2.0f - 1.0f;
3560                         m_layers[layerNdx].zScale       = (2.0f / m_numLayers);
3561                         m_layers[layerNdx].color1       = (layerNdx == 0) ? (tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)) : (tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
3562                         m_layers[layerNdx].color2       = (layerNdx == 0) ? (tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f)) : (tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f));
3563                 }
3564                 rnd.shuffle(m_layers.begin(), m_layers.end());
3565         }
3566 }
3567
3568 void DepthDrawCase::deinit (void)
3569 {
3570         m_program.clear();
3571         m_vbo.clear();
3572 }
3573
3574 DepthDrawCase::IterateResult DepthDrawCase::iterate (void)
3575 {
3576         const bool                              hasTessellation         = (m_state == STATE_PER_PRIMITIVE);
3577         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
3578         const glw::GLint                posLocation                     = gl.getAttribLocation(m_program->getProgram(), "a_position");
3579         const glw::GLint                colLocation                     = gl.getAttribLocation(m_program->getProgram(), "a_colorMix");
3580         const glw::GLint                depthBiasLocation       = gl.getUniformLocation(m_program->getProgram(), "u_depthBias");
3581         const glw::GLint                depthScaleLocation      = gl.getUniformLocation(m_program->getProgram(), "u_depthScale");
3582         const glw::GLint                color1Location          = gl.getUniformLocation(m_program->getProgram(), "u_color1");
3583         const glw::GLint                color2Location          = gl.getUniformLocation(m_program->getProgram(), "u_color2");
3584
3585         tcu::Surface                    viewport                        (RENDER_AREA_SIZE, RENDER_AREA_SIZE);
3586         de::Random                              rnd                                     (0x213237);
3587
3588         TCU_CHECK(posLocation != -1);
3589         TCU_CHECK(colLocation != -1);
3590         TCU_CHECK(depthBiasLocation != -1);
3591         TCU_CHECK(depthScaleLocation != -1);
3592         TCU_CHECK(color1Location != -1);
3593         TCU_CHECK(color2Location != -1);
3594
3595         gl.viewport(0, 0, RENDER_AREA_SIZE, RENDER_AREA_SIZE);
3596         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3597         gl.clearDepthf(1.0f);
3598         gl.depthFunc(GL_LESS);
3599         gl.enable(GL_DEPTH_TEST);
3600         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3601         GLU_EXPECT_NO_ERROR(gl.getError(), "setup viewport");
3602
3603         gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
3604         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, (int)(8 * sizeof(float)), (const float*)DE_NULL);
3605         gl.vertexAttribPointer(colLocation, 4, GL_FLOAT, GL_FALSE, (int)(8 * sizeof(float)), (const float*)DE_NULL + 4);
3606         gl.enableVertexAttribArray(posLocation);
3607         gl.enableVertexAttribArray(colLocation);
3608         gl.useProgram(m_program->getProgram());
3609         GLU_EXPECT_NO_ERROR(gl.getError(), "setup va");
3610
3611         if (hasTessellation)
3612                 gl.patchParameteri(GL_PATCH_VERTICES, 3);
3613
3614         for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
3615         {
3616                 gl.uniform1f(depthBiasLocation, m_layers[layerNdx].zOffset);
3617                 gl.uniform1f(depthScaleLocation, m_layers[layerNdx].zScale);
3618                 gl.uniform4fv(color1Location, 1, m_layers[layerNdx].color1.getPtr());
3619                 gl.uniform4fv(color2Location, 1, m_layers[layerNdx].color2.getPtr());
3620
3621                 if (m_state == STATE_GLOBAL)
3622                 {
3623                         const float negPadding = (m_bboxSize == BBOX_EQUAL) ? (0.0f) : (rnd.getFloat() * 0.3f);
3624                         const float posPadding = (m_bboxSize == BBOX_EQUAL) ? (0.0f) : (rnd.getFloat() * 0.3f);
3625
3626                         gl.primitiveBoundingBoxEXT(-1.0f, -1.0f, m_layers[layerNdx].zOffset - negPadding, 1.0f,
3627                                                                             1.0f,  1.0f, (m_layers[layerNdx].zOffset + m_layers[layerNdx].zScale + posPadding), 1.0f);
3628                 }
3629
3630                 gl.drawArrays((hasTessellation) ? (GL_PATCHES) : (GL_TRIANGLES), 0, m_gridSize * m_gridSize * 6);
3631         }
3632
3633         glu::readPixels(m_context.getRenderContext(), 0, 0, viewport.getAccess());
3634         GLU_EXPECT_NO_ERROR(gl.getError(), "render and read");
3635
3636         if (verifyImage(viewport))
3637                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3638         else
3639                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
3640
3641         return STOP;
3642 }
3643
3644 std::string DepthDrawCase::genVertexSource (void) const
3645 {
3646         const bool                      hasTessellation = (m_state == STATE_PER_PRIMITIVE);
3647         std::ostringstream      buf;
3648
3649         buf <<  "#version 310 es\n"
3650                         "in highp vec4 a_position;\n"
3651                         "in highp vec4 a_colorMix;\n"
3652                         "out highp vec4 vtx_colorMix;\n";
3653
3654         if (!hasTessellation && m_depthType == DEPTH_USER_DEFINED)
3655                 buf << "out highp float v_fragDepth;\n";
3656
3657         if (!hasTessellation)
3658                 buf <<  "uniform highp float u_depthBias;\n"
3659                                 "uniform highp float u_depthScale;\n";
3660
3661         buf <<  "\n"
3662                         "void main()\n"
3663                         "{\n";
3664
3665         if (hasTessellation)
3666                 buf << "        gl_Position = a_position;\n";
3667         else if (m_depthType == DEPTH_USER_DEFINED)
3668                 buf <<  "       highp float dummyZ = a_position.z;\n"
3669                                 "       highp float writtenZ = a_position.w;\n"
3670                                 "       gl_Position = vec4(a_position.xy, dummyZ, 1.0);\n"
3671                                 "       v_fragDepth = writtenZ * u_depthScale + u_depthBias;\n";
3672         else
3673                 buf <<  "       highp float writtenZ = a_position.w;\n"
3674                                 "       gl_Position = vec4(a_position.xy, writtenZ * u_depthScale + u_depthBias, 1.0);\n";
3675
3676         buf <<  "       vtx_colorMix = a_colorMix;\n"
3677                         "}\n";
3678
3679         return buf.str();
3680 }
3681
3682 std::string DepthDrawCase::genFragmentSource (void) const
3683 {
3684         const bool                      hasTessellation = (m_state == STATE_PER_PRIMITIVE);
3685         const char* const       colorMixName    = (hasTessellation) ? ("tess_eval_colorMix") : ("vtx_colorMix");
3686         std::ostringstream      buf;
3687
3688         buf <<  "#version 310 es\n"
3689                         "in mediump vec4 " << colorMixName << ";\n";
3690
3691         if (m_depthType == DEPTH_USER_DEFINED)
3692                 buf << "in mediump float v_fragDepth;\n";
3693
3694         buf <<  "layout(location = 0) out mediump vec4 o_color;\n"
3695                         "uniform highp vec4 u_color1;\n"
3696                         "uniform highp vec4 u_color2;\n"
3697                         "\n"
3698                         "void main()\n"
3699                         "{\n"
3700                         "       o_color = mix(u_color1, u_color2, " << colorMixName << ");\n";
3701
3702         if (m_depthType == DEPTH_USER_DEFINED)
3703                 buf << "        gl_FragDepth = v_fragDepth * 0.5 + 0.5;\n";
3704
3705         buf <<  "}\n";
3706
3707         return buf.str();
3708 }
3709
3710 std::string DepthDrawCase::genTessellationControlSource (void) const
3711 {
3712         std::ostringstream      buf;
3713
3714         buf <<  "#version 310 es\n"
3715                         "#extension GL_EXT_tessellation_shader : require\n"
3716                         "#extension GL_EXT_primitive_bounding_box : require\n"
3717                         "layout(vertices=3) out;\n"
3718                         "\n"
3719                         "uniform highp float u_depthBias;\n"
3720                         "uniform highp float u_depthScale;\n"
3721                         "\n"
3722                         "in highp vec4 vtx_colorMix[];\n"
3723                         "out highp vec4 tess_ctrl_colorMix[];\n"
3724                         "\n"
3725                         "void main()\n"
3726                         "{\n"
3727                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3728                         "       tess_ctrl_colorMix[gl_InvocationID] = vtx_colorMix[0];\n"
3729                         "\n"
3730                         "       gl_TessLevelOuter[0] = 2.8;\n"
3731                         "       gl_TessLevelOuter[1] = 2.8;\n"
3732                         "       gl_TessLevelOuter[2] = 2.8;\n"
3733                         "       gl_TessLevelInner[0] = 2.8;\n"
3734                         "\n"
3735                         "       // real Z stored in w component\n"
3736                         "       highp vec4 minBound = vec4(min(min(vec3(gl_in[0].gl_Position.xy, gl_in[0].gl_Position.w * u_depthScale + u_depthBias),\n"
3737                         "                                          vec3(gl_in[1].gl_Position.xy, gl_in[1].gl_Position.w * u_depthScale + u_depthBias)),\n"
3738                         "                                      vec3(gl_in[2].gl_Position.xy, gl_in[2].gl_Position.w * u_depthScale + u_depthBias)), 1.0);\n"
3739                         "       highp vec4 maxBound = vec4(max(max(vec3(gl_in[0].gl_Position.xy, gl_in[0].gl_Position.w * u_depthScale + u_depthBias),\n"
3740                         "                                          vec3(gl_in[1].gl_Position.xy, gl_in[1].gl_Position.w * u_depthScale + u_depthBias)),\n"
3741                         "                                      vec3(gl_in[2].gl_Position.xy, gl_in[2].gl_Position.w * u_depthScale + u_depthBias)), 1.0);\n";
3742
3743         if (m_bboxSize == BBOX_EQUAL)
3744                 buf <<  "       gl_BoundingBoxEXT[0] = minBound;\n"
3745                                 "       gl_BoundingBoxEXT[1] = maxBound;\n";
3746         else
3747                 buf <<  "       highp float nedPadding = mod(gl_in[0].gl_Position.z, 0.3);\n"
3748                                 "       highp float posPadding = mod(gl_in[1].gl_Position.z, 0.3);\n"
3749                                 "       gl_BoundingBoxEXT[0] = minBound - vec4(0.0, 0.0, nedPadding, 0.0);\n"
3750                                 "       gl_BoundingBoxEXT[1] = maxBound + vec4(0.0, 0.0, posPadding, 0.0);\n";
3751
3752         buf <<  "}\n";
3753
3754         return buf.str();
3755 }
3756
3757 std::string DepthDrawCase::genTessellationEvaluationSource (void) const
3758 {
3759         std::ostringstream      buf;
3760
3761         buf <<  "#version 310 es\n"
3762                         "#extension GL_EXT_tessellation_shader : require\n"
3763                         "#extension GL_EXT_gpu_shader5 : require\n"
3764                         "layout(triangles) in;\n"
3765                         "\n"
3766                         "in highp vec4 tess_ctrl_colorMix[];\n"
3767                         "out highp vec4 tess_eval_colorMix;\n";
3768
3769         if (m_depthType == DEPTH_USER_DEFINED)
3770                 buf << "out highp float v_fragDepth;\n";
3771
3772         buf <<  "uniform highp float u_depthBias;\n"
3773                         "uniform highp float u_depthScale;\n"
3774                         "\n"
3775                         "precise gl_Position;\n"
3776                         "\n"
3777                         "void main()\n"
3778                         "{\n"
3779                         "       highp vec4 tessellatedPos = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n";
3780
3781         if (m_depthType == DEPTH_USER_DEFINED)
3782                 buf <<  "       highp float dummyZ = tessellatedPos.z;\n"
3783                                 "       highp float writtenZ = tessellatedPos.w;\n"
3784                                 "       gl_Position = vec4(tessellatedPos.xy, dummyZ, 1.0);\n"
3785                                 "       v_fragDepth = writtenZ * u_depthScale + u_depthBias;\n";
3786         else
3787                 buf <<  "       highp float writtenZ = tessellatedPos.w;\n"
3788                                 "       gl_Position = vec4(tessellatedPos.xy, writtenZ * u_depthScale + u_depthBias, 1.0);\n";
3789
3790         buf <<  "       tess_eval_colorMix = tess_ctrl_colorMix[0];\n"
3791                         "}\n";
3792
3793         return buf.str();
3794 }
3795
3796 void DepthDrawCase::generateAttributeData (std::vector<tcu::Vec4>& data) const
3797 {
3798         const tcu::Vec4         color1                          (0.0f, 0.0f, 0.0f, 0.0f); // mix weights
3799         const tcu::Vec4         color2                          (1.0f, 1.0f, 1.0f, 1.0f);
3800         std::vector<int>        cellOrder                       (m_gridSize * m_gridSize);
3801         de::Random                      rnd                                     (0xAB54321);
3802
3803         // generate grid with cells in random order
3804         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
3805                 cellOrder[ndx] = ndx;
3806         rnd.shuffle(cellOrder.begin(), cellOrder.end());
3807
3808         data.resize(m_gridSize * m_gridSize * 6 * 2);
3809         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
3810         {
3811                 const int                       cellNdx         = cellOrder[ndx];
3812                 const int                       cellX           = cellNdx % m_gridSize;
3813                 const int                       cellY           = cellNdx / m_gridSize;
3814                 const tcu::Vec4&        cellColor       = ((cellX+cellY)%2 == 0) ? (color1) : (color2);
3815
3816                 data[ndx * 6 * 2 +  0] = tcu::Vec4((cellX+0) / float(m_gridSize) * 2.0f - 1.0f, (cellY+0) / float(m_gridSize) * 2.0f - 1.0f, 0.0f, 0.0f);       data[ndx * 6 * 2 +  1] = cellColor;
3817                 data[ndx * 6 * 2 +  2] = tcu::Vec4((cellX+1) / float(m_gridSize) * 2.0f - 1.0f, (cellY+1) / float(m_gridSize) * 2.0f - 1.0f, 0.0f, 0.0f);       data[ndx * 6 * 2 +  3] = cellColor;
3818                 data[ndx * 6 * 2 +  4] = tcu::Vec4((cellX+0) / float(m_gridSize) * 2.0f - 1.0f, (cellY+1) / float(m_gridSize) * 2.0f - 1.0f, 0.0f, 0.0f);       data[ndx * 6 * 2 +  5] = cellColor;
3819                 data[ndx * 6 * 2 +  6] = tcu::Vec4((cellX+0) / float(m_gridSize) * 2.0f - 1.0f, (cellY+0) / float(m_gridSize) * 2.0f - 1.0f, 0.0f, 0.0f);       data[ndx * 6 * 2 +  7] = cellColor;
3820                 data[ndx * 6 * 2 +  8] = tcu::Vec4((cellX+1) / float(m_gridSize) * 2.0f - 1.0f, (cellY+0) / float(m_gridSize) * 2.0f - 1.0f, 0.0f, 0.0f);       data[ndx * 6 * 2 +  9] = cellColor;
3821                 data[ndx * 6 * 2 + 10] = tcu::Vec4((cellX+1) / float(m_gridSize) * 2.0f - 1.0f, (cellY+1) / float(m_gridSize) * 2.0f - 1.0f, 0.0f, 0.0f);       data[ndx * 6 * 2 + 11] = cellColor;
3822
3823                 // Fill Z with random values (fake Z)
3824                 for (int vtxNdx = 0; vtxNdx < 6; ++vtxNdx)
3825                         data[ndx * 6 * 2 + 2*vtxNdx].z() = rnd.getFloat(0.0f, 1.0);
3826
3827                 // Fill W with other random values (written Z)
3828                 for (int vtxNdx = 0; vtxNdx < 6; ++vtxNdx)
3829                         data[ndx * 6 * 2 + 2*vtxNdx].w() = rnd.getFloat(0.0f, 1.0);
3830         }
3831 }
3832
3833 bool DepthDrawCase::verifyImage (const tcu::Surface& viewport) const
3834 {
3835         tcu::Surface    errorMask       (viewport.getWidth(), viewport.getHeight());
3836         bool                    anyError        = false;
3837
3838         tcu::clear(errorMask.getAccess(), tcu::IVec4(0,0,0,255));
3839
3840         for (int y = 0; y < viewport.getHeight(); ++y)
3841         for (int x = 0; x < viewport.getWidth(); ++x)
3842         {
3843                 const tcu::RGBA pixel           = viewport.getPixel(x, y);
3844                 bool                    error           = false;
3845
3846                 // expect green, yellow or a combination of these
3847                 if (pixel.getGreen() != 255 || pixel.getBlue() != 0)
3848                         error = true;
3849
3850                 if (error)
3851                 {
3852                         errorMask.setPixel(x, y, tcu::RGBA::red);
3853                         anyError = true;
3854                 }
3855         }
3856
3857         if (anyError)
3858                 m_testCtx.getLog()
3859                         << tcu::TestLog::Message
3860                         << "Image verification failed."
3861                         << tcu::TestLog::EndMessage
3862                         << tcu::TestLog::ImageSet("Images", "Image verification")
3863                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewport.getAccess())
3864                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
3865                         << tcu::TestLog::EndImageSet;
3866         else
3867                 m_testCtx.getLog()
3868                         << tcu::TestLog::Message
3869                         << "Result image ok."
3870                         << tcu::TestLog::EndMessage
3871                         << tcu::TestLog::ImageSet("Images", "Image verification")
3872                         << tcu::TestLog::Image("Viewport", "Viewport contents", viewport.getAccess())
3873                         << tcu::TestLog::EndImageSet;
3874
3875         return !anyError;
3876 }
3877
3878 class ClearCase : public TestCase
3879 {
3880 public:
3881         enum
3882         {
3883                 SCISSOR_CLEAR_BIT               = 1 << 0,
3884                 DRAW_TRIANGLE_BIT               = 1 << 1,
3885                 PER_PRIMITIVE_BBOX_BIT  = 1 << 2,
3886                 FULLSCREEN_SCISSOR_BIT  = 1 << 3,
3887         };
3888
3889                                                                         ClearCase                                               (Context& context, const char* name, const char* description, deUint32 flags);
3890                                                                         ~ClearCase                                              (void);
3891
3892 private:
3893         struct DrawObject
3894         {
3895                 int firstNdx;
3896                 int numVertices;
3897         };
3898
3899         void                                                    init                                                    (void);
3900         void                                                    deinit                                                  (void);
3901         IterateResult                                   iterate                                                 (void);
3902
3903         void                                                    createVbo                                               (void);
3904         void                                                    createProgram                                   (void);
3905         void                                                    renderTo                                                (tcu::Surface& dst, bool useBBox);
3906         bool                                                    verifyImagesEqual                               (const tcu::PixelBufferAccess& withoutBBox, const tcu::PixelBufferAccess& withBBox);
3907         bool                                                    verifyImageResultValid                  (const tcu::PixelBufferAccess& result);
3908
3909         std::string                                             genVertexSource                                 (void) const;
3910         std::string                                             genFragmentSource                               (void) const;
3911         std::string                                             genTessellationControlSource    (bool setBBox) const;
3912         std::string                                             genTessellationEvaluationSource (void) const;
3913
3914         const bool                                              m_scissoredClear;
3915         const bool                                              m_fullscreenScissor;
3916         const bool                                              m_drawTriangles;
3917         const bool                                              m_useGlobalState;
3918
3919         de::MovePtr<glu::Buffer>                m_vbo;
3920         de::MovePtr<glu::ShaderProgram> m_perPrimitiveProgram;
3921         de::MovePtr<glu::ShaderProgram> m_basicProgram;
3922         std::vector<DrawObject>                 m_drawObjects;
3923         std::vector<tcu::Vec4>                  m_objectVertices;
3924 };
3925
3926 ClearCase::ClearCase (Context& context, const char* name, const char* description, deUint32 flags)
3927         : TestCase                              (context, name, description)
3928         , m_scissoredClear              ((flags & SCISSOR_CLEAR_BIT) != 0)
3929         , m_fullscreenScissor   ((flags & FULLSCREEN_SCISSOR_BIT) != 0)
3930         , m_drawTriangles               ((flags & DRAW_TRIANGLE_BIT) != 0)
3931         , m_useGlobalState              ((flags & PER_PRIMITIVE_BBOX_BIT) == 0)
3932 {
3933         DE_ASSERT(m_useGlobalState || m_drawTriangles); // per-triangle bbox requires triangles
3934         DE_ASSERT(!m_fullscreenScissor || m_scissoredClear); // fullscreenScissor requires scissoredClear
3935 }
3936
3937 ClearCase::~ClearCase (void)
3938 {
3939         deinit();
3940 }
3941
3942 void ClearCase::init (void)
3943 {
3944         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_primitive_bounding_box"))
3945                 throw tcu::NotSupportedError("Test requires GL_EXT_primitive_bounding_box extension");
3946         if (m_drawTriangles && !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
3947                 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
3948
3949         m_testCtx.getLog()
3950                 << tcu::TestLog::Message
3951                 << "Doing multiple"
3952                         << ((m_scissoredClear) ? (" scissored") : (""))
3953                         << " color buffer clears"
3954                         << ((m_drawTriangles) ? (" and drawing some geometry between them") : (""))
3955                         << ".\n"
3956                 << ((m_scissoredClear && m_fullscreenScissor) ? ("Setting scissor area to cover entire viewport.\n") : (""))
3957                 << "Rendering with and without setting the bounding box.\n"
3958                 << "Expecting bounding box to have no effect on clears (i.e. results are constant).\n"
3959                 << "Set bounding box using "
3960                         << ((m_useGlobalState) ? ("PRIMITIVE_BOUNDING_BOX_EXT state") : ("gl_BoundingBoxEXT output"))
3961                         << ".\n"
3962                 << "Clear color is green with yellowish shades.\n"
3963                 << ((m_drawTriangles) ? ("Primitive color is yellow with greenish shades.\n") : (""))
3964                 << tcu::TestLog::EndMessage;
3965
3966         if (m_drawTriangles)
3967         {
3968                 createVbo();
3969                 createProgram();
3970         }
3971 }
3972
3973 void ClearCase::deinit (void)
3974 {
3975         m_vbo.clear();
3976         m_perPrimitiveProgram.clear();
3977         m_basicProgram.clear();
3978         m_drawObjects = std::vector<DrawObject>();
3979         m_objectVertices = std::vector<tcu::Vec4>();
3980 }
3981
3982 ClearCase::IterateResult ClearCase::iterate (void)
3983 {
3984         const tcu::IVec2        renderTargetSize        (m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight());
3985         tcu::Surface            resultWithoutBBox       (renderTargetSize.x(), renderTargetSize.y());
3986         tcu::Surface            resultWithBBox          (renderTargetSize.x(), renderTargetSize.y());
3987
3988         // render with and without bbox set
3989         for (int passNdx = 0; passNdx < 2; ++passNdx)
3990         {
3991                 const bool              useBBox                 = (passNdx == 1);
3992                 tcu::Surface&   destination             = (useBBox) ? (resultWithBBox) : (resultWithoutBBox);
3993
3994                 renderTo(destination, useBBox);
3995         }
3996
3997         // Verify images are equal and that the image does not contain (trivially detectable) garbage
3998
3999         if (!verifyImagesEqual(resultWithoutBBox.getAccess(), resultWithBBox.getAccess()))
4000         {
4001                 // verifyImagesEqual will print out the image and error mask
4002                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
4003         }
4004         else if (!verifyImageResultValid(resultWithBBox.getAccess()))
4005         {
4006                 // verifyImageResultValid will print out the image and error mask
4007                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed");
4008         }
4009         else
4010         {
4011                 m_testCtx.getLog()
4012                         << tcu::TestLog::Message
4013                         << "Image comparison passed."
4014                         << tcu::TestLog::EndMessage
4015                         << tcu::TestLog::ImageSet("Images", "Image verification")
4016                         << tcu::TestLog::Image("Result", "Result", resultWithBBox.getAccess())
4017                         << tcu::TestLog::EndImageSet;
4018
4019                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4020         }
4021
4022         return STOP;
4023 }
4024
4025 void ClearCase::createVbo (void)
4026 {
4027         const int                               numObjects      = 16;
4028         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
4029         de::Random                              rnd                     (deStringHash(getName()));
4030
4031         m_vbo = de::MovePtr<glu::Buffer>(new glu::Buffer(m_context.getRenderContext()));
4032
4033         for (int objectNdx = 0; objectNdx < numObjects; ++objectNdx)
4034         {
4035                 const int       numTriangles    = rnd.getInt(1, 4);
4036                 const float     minX                    = rnd.getFloat(-1.2f, 0.8f);
4037                 const float     minY                    = rnd.getFloat(-1.2f, 0.8f);
4038                 const float     maxX                    = minX + rnd.getFloat(0.2f, 1.0f);
4039                 const float     maxY                    = minY + rnd.getFloat(0.2f, 1.0f);
4040
4041                 DrawObject      drawObject;
4042                 drawObject.firstNdx = (int)m_objectVertices.size();
4043                 drawObject.numVertices = numTriangles * 3;
4044
4045                 m_drawObjects.push_back(drawObject);
4046
4047                 for (int triangleNdx = 0; triangleNdx < numTriangles; ++triangleNdx)
4048                 for (int vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
4049                 {
4050                         const float posX = rnd.getFloat(minX, maxX);
4051                         const float posY = rnd.getFloat(minY, maxY);
4052                         const float posZ = rnd.getFloat(-0.7f, 0.7f);
4053                         const float posW = rnd.getFloat(0.9f, 1.1f);
4054
4055                         m_objectVertices.push_back(tcu::Vec4(posX, posY, posZ, posW));
4056                 }
4057         }
4058
4059         gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
4060         gl.bufferData(GL_ARRAY_BUFFER, (int)(m_objectVertices.size() * sizeof(tcu::Vec4)), &m_objectVertices[0], GL_STATIC_DRAW);
4061         GLU_EXPECT_NO_ERROR(gl.getError(), "buffer upload");
4062 }
4063
4064 void ClearCase::createProgram (void)
4065 {
4066         m_basicProgram = de::MovePtr<glu::ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(),
4067                                                                                                                                                         glu::ProgramSources()
4068                                                                                                                                                                 << glu::VertexSource(genVertexSource())
4069                                                                                                                                                                 << glu::FragmentSource(genFragmentSource())
4070                                                                                                                                                                 << glu::TessellationControlSource(genTessellationControlSource(false))
4071                                                                                                                                                                 << glu::TessellationEvaluationSource(genTessellationEvaluationSource())));
4072
4073         m_testCtx.getLog()
4074                 << tcu::TestLog::Section("Program", "Shader program")
4075                 << *m_basicProgram
4076                 << tcu::TestLog::EndSection;
4077
4078         if (!m_basicProgram->isOk())
4079                 throw tcu::TestError("shader build failed");
4080
4081         if (!m_useGlobalState)
4082         {
4083                 m_perPrimitiveProgram = de::MovePtr<glu::ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(),
4084                                                                                                                                                                            glu::ProgramSources()
4085                                                                                                                                                                                         << glu::VertexSource(genVertexSource())
4086                                                                                                                                                                                         << glu::FragmentSource(genFragmentSource())
4087                                                                                                                                                                                         << glu::TessellationControlSource(genTessellationControlSource(true))
4088                                                                                                                                                                                         << glu::TessellationEvaluationSource(genTessellationEvaluationSource())));
4089
4090                 m_testCtx.getLog()
4091                         << tcu::TestLog::Section("PerPrimitiveProgram", "Shader program that sets the bounding box")
4092                         << *m_perPrimitiveProgram
4093                         << tcu::TestLog::EndSection;
4094
4095                 if (!m_perPrimitiveProgram->isOk())
4096                         throw tcu::TestError("shader build failed");
4097         }
4098 }
4099
4100 void ClearCase::renderTo (tcu::Surface& dst, bool useBBox)
4101 {
4102         const int                               numOps                          = 45;
4103         const tcu::Vec4                 yellow                          (1.0f, 1.0f, 0.0f, 1.0f);
4104         const tcu::Vec4                 green                           (0.0f, 1.0f, 0.0f, 1.0f);
4105         const tcu::IVec2                renderTargetSize        (m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight());
4106         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
4107         de::Random                              rnd                                     (deStringHash(getName()));
4108         glu::VertexArray                vao                                     (m_context.getRenderContext());
4109
4110         // always do the initial clear
4111         gl.disable(GL_SCISSOR_TEST);
4112         gl.viewport(0, 0, renderTargetSize.x(), renderTargetSize.y());
4113         gl.clearColor(yellow.x(), yellow.y(), yellow.z(), yellow.w());
4114         gl.clear(GL_COLOR_BUFFER_BIT);
4115         gl.finish();
4116
4117         // prepare draw
4118         if (m_scissoredClear)
4119                 gl.enable(GL_SCISSOR_TEST);
4120
4121         if (m_drawTriangles)
4122         {
4123                 const deUint32  programHandle           = (m_useGlobalState || !useBBox) ? (m_basicProgram->getProgram()) : (m_perPrimitiveProgram->getProgram());
4124                 const int               positionAttribLoc       = gl.getAttribLocation(programHandle, "a_position");
4125
4126                 TCU_CHECK(positionAttribLoc != -1);
4127
4128                 gl.useProgram(programHandle);
4129                 gl.bindVertexArray(*vao);
4130                 gl.enableVertexAttribArray(positionAttribLoc);
4131                 gl.vertexAttribPointer(positionAttribLoc, 4, GL_FLOAT, GL_FALSE, (int)sizeof(tcu::Vec4), DE_NULL);
4132                 gl.patchParameteri(GL_PATCH_VERTICES, 3);
4133         }
4134
4135         // do random scissor/clearldraw operations
4136         for (int opNdx = 0; opNdx < numOps; ++opNdx)
4137         {
4138                 const int       drawObjNdx                              = (m_drawTriangles) ? (rnd.getInt(0, (int)m_drawObjects.size() - 1)) : (0);
4139                 const int       objectVertexStartNdx    = (m_drawTriangles) ? (m_drawObjects[drawObjNdx].firstNdx) : (0);
4140                 const int       objectVertexLength              = (m_drawTriangles) ? (m_drawObjects[drawObjNdx].numVertices) : (0);
4141                 tcu::Vec4       bboxMin;
4142                 tcu::Vec4       bboxMax;
4143
4144                 if (m_drawTriangles)
4145                 {
4146                         bboxMin = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
4147                         bboxMax = tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f);
4148
4149                         // calc bbox
4150                         for (int vertexNdx = objectVertexStartNdx; vertexNdx < objectVertexStartNdx + objectVertexLength; ++vertexNdx)
4151                         for (int componentNdx = 0; componentNdx < 4; ++componentNdx)
4152                         {
4153                                 bboxMin[componentNdx] = de::min(bboxMin[componentNdx], m_objectVertices[vertexNdx][componentNdx]);
4154                                 bboxMax[componentNdx] = de::max(bboxMax[componentNdx], m_objectVertices[vertexNdx][componentNdx]);
4155                         }
4156                 }
4157                 else
4158                 {
4159                         // no geometry, just random something
4160                         bboxMin.x() = rnd.getFloat(-1.2f, 1.0f);
4161                         bboxMin.y() = rnd.getFloat(-1.2f, 1.0f);
4162                         bboxMin.z() = rnd.getFloat(-1.2f, 1.0f);
4163                         bboxMin.w() = 1.0f;
4164                         bboxMax.x() = bboxMin.x() + rnd.getFloat(0.2f, 1.0f);
4165                         bboxMax.y() = bboxMin.y() + rnd.getFloat(0.2f, 1.0f);
4166                         bboxMax.z() = bboxMin.z() + rnd.getFloat(0.2f, 1.0f);
4167                         bboxMax.w() = 1.0f;
4168                 }
4169
4170                 if (m_scissoredClear)
4171                 {
4172                         const int scissorX = (m_fullscreenScissor) ? (0)                                        : rnd.getInt(0, renderTargetSize.x()-1);
4173                         const int scissorY = (m_fullscreenScissor) ? (0)                                        : rnd.getInt(0, renderTargetSize.y()-1);
4174                         const int scissorW = (m_fullscreenScissor) ? (renderTargetSize.x())     : rnd.getInt(0, renderTargetSize.x()-scissorX);
4175                         const int scissorH = (m_fullscreenScissor) ? (renderTargetSize.y())     : rnd.getInt(0, renderTargetSize.y()-scissorY);
4176
4177                         gl.scissor(scissorX, scissorY, scissorW, scissorH);
4178                 }
4179
4180                 {
4181                         const tcu::Vec4 color = tcu::mix(green, yellow, rnd.getFloat() * 0.4f); // greenish
4182                         gl.clearColor(color.x(), color.y(), color.z(), color.w());
4183                         gl.clear(GL_COLOR_BUFFER_BIT);
4184                 }
4185
4186                 if (useBBox)
4187                 {
4188                         DE_ASSERT(m_useGlobalState || m_drawTriangles); // !m_useGlobalState -> m_drawTriangles
4189                         if (m_useGlobalState)
4190                                 gl.primitiveBoundingBoxEXT(bboxMin.x(), bboxMin.y(), bboxMin.z(), bboxMin.w(),
4191                                                                                    bboxMax.x(), bboxMax.y(), bboxMax.z(), bboxMax.w());
4192                 }
4193
4194                 if (m_drawTriangles)
4195                         gl.drawArrays(GL_PATCHES, objectVertexStartNdx, objectVertexLength);
4196         }
4197
4198         GLU_EXPECT_NO_ERROR(gl.getError(), "post draw");
4199         glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
4200 }
4201
4202 bool ClearCase::verifyImagesEqual (const tcu::PixelBufferAccess& withoutBBox, const tcu::PixelBufferAccess& withBBox)
4203 {
4204         DE_ASSERT(withoutBBox.getWidth() == withBBox.getWidth());
4205         DE_ASSERT(withoutBBox.getHeight() == withBBox.getHeight());
4206
4207         tcu::Surface    errorMask       (withoutBBox.getWidth(), withoutBBox.getHeight());
4208         bool                    anyError        = false;
4209
4210         tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toIVec());
4211
4212         for (int y = 0; y < withoutBBox.getHeight(); ++y)
4213         for (int x = 0; x < withoutBBox.getWidth(); ++x)
4214         {
4215                 if (withoutBBox.getPixelInt(x, y) != withBBox.getPixelInt(x, y))
4216                 {
4217                         errorMask.setPixel(x, y, tcu::RGBA::red);
4218                         anyError = true;
4219                 }
4220         }
4221
4222         if (anyError)
4223         {
4224                 m_testCtx.getLog()
4225                         << tcu::TestLog::Message
4226                         << "Image comparison failed."
4227                         << tcu::TestLog::EndMessage
4228                         << tcu::TestLog::ImageSet("Images", "Image comparison")
4229                         << tcu::TestLog::Image("WithoutBBox", "Result with bounding box not set", withoutBBox)
4230                         << tcu::TestLog::Image("WithBBox", "Result with bounding box set", withBBox)
4231                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
4232                         << tcu::TestLog::EndImageSet;
4233         }
4234
4235         return !anyError;
4236 }
4237
4238 bool ClearCase::verifyImageResultValid (const tcu::PixelBufferAccess& result)
4239 {
4240         tcu::Surface    errorMask       (result.getWidth(), result.getHeight());
4241         bool                    anyError        = false;
4242
4243         tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toIVec());
4244
4245         for (int y = 0; y < result.getHeight(); ++y)
4246         for (int x = 0; x < result.getWidth(); ++x)
4247         {
4248                 const tcu::IVec4 pixel = result.getPixelInt(x, y);
4249
4250                 // allow green, yellow and any shade between
4251                 if (pixel[1] != 255 || pixel[2] != 0)
4252                 {
4253                         errorMask.setPixel(x, y, tcu::RGBA::red);
4254                         anyError = true;
4255                 }
4256         }
4257
4258         if (anyError)
4259         {
4260                 m_testCtx.getLog()
4261                         << tcu::TestLog::Message
4262                         << "Image verification failed."
4263                         << tcu::TestLog::EndMessage
4264                         << tcu::TestLog::ImageSet("Images", "Image verification")
4265                         << tcu::TestLog::Image("ResultImage", "Result image", result)
4266                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask)
4267                         << tcu::TestLog::EndImageSet;
4268         }
4269
4270         return !anyError;
4271 }
4272
4273 static const char* const s_yellowishPosOnlyVertexSource =       "#version 310 es\n"
4274                                                                                                                         "in highp vec4 a_position;\n"
4275                                                                                                                         "out highp vec4 v_vertex_color;\n"
4276                                                                                                                         "void main()\n"
4277                                                                                                                         "{\n"
4278                                                                                                                         "       gl_Position = a_position;\n"
4279                                                                                                                         "       // yellowish shade\n"
4280                                                                                                                         "       highp float redComponent = 0.5 + float(gl_VertexID % 5) / 8.0;\n"
4281                                                                                                                         "       v_vertex_color = vec4(redComponent, 1.0, 0.0, 1.0);\n"
4282                                                                                                                         "}\n";
4283
4284 static const char* const s_basicColorFragmentSource =   "#version 310 es\n"
4285                                                                                                                 "in mediump vec4 v_color;\n"
4286                                                                                                                 "layout(location = 0) out mediump vec4 o_color;\n"
4287                                                                                                                 "void main()\n"
4288                                                                                                                 "{\n"
4289                                                                                                                 "       o_color = v_color;\n"
4290                                                                                                                 "}\n";
4291
4292
4293 static const char* const s_basicColorTessEvalSource =   "#version 310 es\n"
4294                                                                                                                 "#extension GL_EXT_tessellation_shader : require\n"
4295                                                                                                                 "#extension GL_EXT_gpu_shader5 : require\n"
4296                                                                                                                 "layout(triangles) in;\n"
4297                                                                                                                 "in highp vec4 v_tess_eval_color[];\n"
4298                                                                                                                 "out highp vec4 v_color;\n"
4299                                                                                                                 "precise gl_Position;\n"
4300                                                                                                                 "void main()\n"
4301                                                                                                                 "{\n"
4302                                                                                                                 "       gl_Position = gl_TessCoord.x * gl_in[0].gl_Position\n"
4303                                                                                                                 "                   + gl_TessCoord.y * gl_in[1].gl_Position\n"
4304                                                                                                                 "                   + gl_TessCoord.z * gl_in[2].gl_Position;\n"
4305                                                                                                                 "       v_color = gl_TessCoord.x * v_tess_eval_color[0]\n"
4306                                                                                                                 "               + gl_TessCoord.y * v_tess_eval_color[1]\n"
4307                                                                                                                 "               + gl_TessCoord.z * v_tess_eval_color[2];\n"
4308                                                                                                                 "}\n";
4309
4310 std::string ClearCase::genVertexSource (void) const
4311 {
4312         return  s_yellowishPosOnlyVertexSource;
4313 }
4314
4315 std::string ClearCase::genFragmentSource (void) const
4316 {
4317         return s_basicColorFragmentSource;
4318 }
4319
4320 std::string ClearCase::genTessellationControlSource (bool setBBox) const
4321 {
4322         std::ostringstream buf;
4323
4324         buf <<  "#version 310 es\n"
4325                         "#extension GL_EXT_tessellation_shader : require\n";
4326
4327         if (setBBox)
4328                 buf << "#extension GL_EXT_primitive_bounding_box : require\n";
4329
4330         buf <<  "layout(vertices=3) out;\n"
4331                         "in highp vec4 v_vertex_color[];\n"
4332                         "out highp vec4 v_tess_eval_color[];\n"
4333                         "void main()\n"
4334                         "{\n"
4335                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
4336                         "       v_tess_eval_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
4337                         "       gl_TessLevelOuter[0] = 2.8;\n"
4338                         "       gl_TessLevelOuter[1] = 2.8;\n"
4339                         "       gl_TessLevelOuter[2] = 2.8;\n"
4340                         "       gl_TessLevelInner[0] = 2.8;\n";
4341
4342         if (setBBox)
4343         {
4344                 buf <<  "\n"
4345                 "       gl_BoundingBoxEXT[0] = min(min(gl_in[0].gl_Position,\n"
4346                 "                                      gl_in[1].gl_Position),\n"
4347                 "                                  gl_in[2].gl_Position);\n"
4348                 "       gl_BoundingBoxEXT[1] = max(max(gl_in[0].gl_Position,\n"
4349                 "                                      gl_in[1].gl_Position),\n"
4350                 "                                  gl_in[2].gl_Position);\n";
4351         }
4352
4353         buf << "}\n";
4354         return buf.str();
4355 }
4356
4357 std::string ClearCase::genTessellationEvaluationSource (void) const
4358 {
4359         return s_basicColorTessEvalSource;
4360 }
4361
4362 class ViewportCallOrderCase : public TestCase
4363 {
4364 public:
4365         enum CallOrder
4366         {
4367                 VIEWPORT_FIRST = 0,
4368                 BBOX_FIRST,
4369
4370                 ORDER_LAST
4371         };
4372
4373                                                                         ViewportCallOrderCase                   (Context& context, const char* name, const char* description, CallOrder callOrder);
4374                                                                         ~ViewportCallOrderCase                  (void);
4375
4376 private:
4377         void                                                    init                                                    (void);
4378         void                                                    deinit                                                  (void);
4379         IterateResult                                   iterate                                                 (void);
4380
4381         void                                                    genVbo                                                  (void);
4382         void                                                    genProgram                                              (void);
4383         bool                                                    verifyImage                                             (const tcu::PixelBufferAccess& result);
4384
4385         std::string                                             genVertexSource                                 (void) const;
4386         std::string                                             genFragmentSource                               (void) const;
4387         std::string                                             genTessellationControlSource    (void) const;
4388         std::string                                             genTessellationEvaluationSource (void) const;
4389
4390         const CallOrder                                 m_callOrder;
4391
4392         de::MovePtr<glu::Buffer>                m_vbo;
4393         de::MovePtr<glu::ShaderProgram> m_program;
4394         int                                                             m_numVertices;
4395 };
4396
4397 ViewportCallOrderCase::ViewportCallOrderCase (Context& context, const char* name, const char* description, CallOrder callOrder)
4398         : TestCase              (context, name, description)
4399         , m_callOrder   (callOrder)
4400         , m_numVertices (-1)
4401 {
4402         DE_ASSERT(m_callOrder < ORDER_LAST);
4403 }
4404
4405 ViewportCallOrderCase::~ViewportCallOrderCase (void)
4406 {
4407         deinit();
4408 }
4409
4410 void ViewportCallOrderCase::init (void)
4411 {
4412         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_primitive_bounding_box"))
4413                 throw tcu::NotSupportedError("Test requires GL_EXT_primitive_bounding_box extension");
4414
4415         m_testCtx.getLog()
4416                 << tcu::TestLog::Message
4417                 << "Testing call order of state setting functions have no effect on the rendering.\n"
4418                 << "Setting viewport and bounding box in the following order:\n"
4419                         << ((m_callOrder == VIEWPORT_FIRST)
4420                                 ? ("\tFirst viewport with glViewport function.\n")
4421                                 : ("\tFirst bounding box with glPrimitiveBoundingBoxEXT function.\n"))
4422                         << ((m_callOrder == VIEWPORT_FIRST)
4423                                 ? ("\tThen bounding box with glPrimitiveBoundingBoxEXT function.\n")
4424                                 : ("\tThen viewport with glViewport function.\n"))
4425                 << "Verifying rendering result."
4426                 << tcu::TestLog::EndMessage;
4427
4428         // resources
4429         genVbo();
4430         genProgram();
4431 }
4432
4433 void ViewportCallOrderCase::deinit (void)
4434 {
4435         m_vbo.clear();
4436         m_program.clear();
4437 }
4438
4439 ViewportCallOrderCase::IterateResult ViewportCallOrderCase::iterate (void)
4440 {
4441         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
4442         const tcu::IVec2                viewportSize    = tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight());
4443         const glw::GLint                posLocation             = gl.getAttribLocation(m_program->getProgram(), "a_position");
4444         tcu::Surface                    resultSurface   (viewportSize.x(), viewportSize.y());
4445
4446         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
4447         gl.clear(GL_COLOR_BUFFER_BIT);
4448
4449         // set state
4450         for (int orderNdx = 0; orderNdx < 2; ++orderNdx)
4451         {
4452                 if ((orderNdx == 0 && m_callOrder == VIEWPORT_FIRST) ||
4453                         (orderNdx == 1 && m_callOrder == BBOX_FIRST))
4454                 {
4455                         m_testCtx.getLog()
4456                                 << tcu::TestLog::Message
4457                                 << "Setting viewport to cover the left half of the render target.\n"
4458                                 << "\t(0, 0, " << (viewportSize.x()/2) << ", " << viewportSize.y() << ")"
4459                                 << tcu::TestLog::EndMessage;
4460
4461                         gl.viewport(0, 0, viewportSize.x()/2, viewportSize.y());
4462                 }
4463                 else
4464                 {
4465                         m_testCtx.getLog()
4466                                 << tcu::TestLog::Message
4467                                 << "Setting bounding box to cover the right half of the clip space.\n"
4468                                 << "\t(0.0, -1.0, -1.0, 1.0) .. (1.0, 1.0, 1.0f, 1.0)"
4469                                 << tcu::TestLog::EndMessage;
4470
4471                         gl.primitiveBoundingBoxEXT(0.0f, -1.0f, -1.0f, 1.0f,
4472                                                                            1.0f,  1.0f,  1.0f, 1.0f);
4473                 }
4474         }
4475
4476         m_testCtx.getLog()
4477                 << tcu::TestLog::Message
4478                 << "Rendering mesh covering the right half of the clip space."
4479                 << tcu::TestLog::EndMessage;
4480
4481         gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
4482         gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float[4]), (const float*)DE_NULL);
4483         gl.enableVertexAttribArray(posLocation);
4484         gl.useProgram(m_program->getProgram());
4485         gl.patchParameteri(GL_PATCH_VERTICES, 3);
4486         gl.drawArrays(GL_PATCHES, 0, m_numVertices);
4487         GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw");
4488
4489         m_testCtx.getLog()
4490                 << tcu::TestLog::Message
4491                 << "Verifying image"
4492                 << tcu::TestLog::EndMessage;
4493         glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
4494
4495         if (!verifyImage(resultSurface.getAccess()))
4496                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
4497         else
4498         {
4499                 m_testCtx.getLog()
4500                         << tcu::TestLog::Message
4501                         << "Result ok."
4502                         << tcu::TestLog::EndMessage
4503                         << tcu::TestLog::ImageSet("Images", "Image verification")
4504                         << tcu::TestLog::Image("Result", "Result", resultSurface.getAccess())
4505                         << tcu::TestLog::EndImageSet;
4506
4507                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4508         }
4509         return STOP;
4510 }
4511
4512 void ViewportCallOrderCase::genVbo (void)
4513 {
4514         const int                               gridSize        = 6;
4515         const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
4516         std::vector<tcu::Vec4>  data            (gridSize * gridSize * 2 * 3);
4517         std::vector<int>                cellOrder       (gridSize * gridSize * 2);
4518         de::Random                              rnd                     (0x55443322);
4519
4520         // generate grid with triangles in random order
4521         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
4522                 cellOrder[ndx] = ndx;
4523         rnd.shuffle(cellOrder.begin(), cellOrder.end());
4524
4525         // generate grid filling the right half of the clip space: (x: 0.0, y: -1.0) .. (x: 1.0, y: 1.0)
4526         for (int ndx = 0; ndx < (int)cellOrder.size(); ++ndx)
4527         {
4528                 const int                       cellNdx         = cellOrder[ndx];
4529                 const bool                      cellSide        = ((cellNdx % 2) == 0);
4530                 const int                       cellX           = (cellNdx / 2) % gridSize;
4531                 const int                       cellY           = (cellNdx / 2) / gridSize;
4532
4533                 if (cellSide)
4534                 {
4535                         data[ndx * 3 + 0] = tcu::Vec4((cellX+0) / float(gridSize), ((cellY+0) / float(gridSize)) * 2.0f - 1.0f, 0.0f, 1.0f);
4536                         data[ndx * 3 + 1] = tcu::Vec4((cellX+1) / float(gridSize), ((cellY+1) / float(gridSize)) * 2.0f - 1.0f, 0.0f, 1.0f);
4537                         data[ndx * 3 + 2] = tcu::Vec4((cellX+0) / float(gridSize), ((cellY+1) / float(gridSize)) * 2.0f - 1.0f, 0.0f, 1.0f);
4538                 }
4539                 else
4540                 {
4541                         data[ndx * 3 + 0] = tcu::Vec4((cellX+0) / float(gridSize), ((cellY+0) / float(gridSize)) * 2.0f - 1.0f, 0.0f, 1.0f);
4542                         data[ndx * 3 + 1] = tcu::Vec4((cellX+1) / float(gridSize), ((cellY+0) / float(gridSize)) * 2.0f - 1.0f, 0.0f, 1.0f);
4543                         data[ndx * 3 + 2] = tcu::Vec4((cellX+1) / float(gridSize), ((cellY+1) / float(gridSize)) * 2.0f - 1.0f, 0.0f, 1.0f);
4544                 }
4545         }
4546
4547         m_vbo = de::MovePtr<glu::Buffer>(new glu::Buffer(m_context.getRenderContext()));
4548         gl.bindBuffer(GL_ARRAY_BUFFER, **m_vbo);
4549         gl.bufferData(GL_ARRAY_BUFFER, (int)(data.size() * sizeof(tcu::Vec4)), &data[0], GL_STATIC_DRAW);
4550         GLU_EXPECT_NO_ERROR(gl.getError(), "create vbo");
4551
4552         m_numVertices = (int)data.size();
4553 }
4554
4555 void ViewportCallOrderCase::genProgram (void)
4556 {
4557         m_program = de::MovePtr<glu::ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(),
4558                                                                                                                                            glu::ProgramSources()
4559                                                                                                                                                         << glu::VertexSource(genVertexSource())
4560                                                                                                                                                         << glu::FragmentSource(genFragmentSource())
4561                                                                                                                                                         << glu::TessellationControlSource(genTessellationControlSource())
4562                                                                                                                                                         << glu::TessellationEvaluationSource(genTessellationEvaluationSource())));
4563
4564         m_testCtx.getLog()
4565                 << tcu::TestLog::Section("Program", "Shader program")
4566                 << *m_program
4567                 << tcu::TestLog::EndSection;
4568
4569         if (!m_program->isOk())
4570                 throw tcu::TestError("shader build failed");
4571 }
4572
4573 bool ViewportCallOrderCase::verifyImage (const tcu::PixelBufferAccess& result)
4574 {
4575         const tcu::IVec2        insideBorder    (deCeilFloatToInt32(0.25f * result.getWidth()) + 1, deFloorFloatToInt32(0.5f * result.getWidth()) - 1);
4576         const tcu::IVec2        outsideBorder   (deFloorFloatToInt32(0.25f * result.getWidth()) - 1, deCeilFloatToInt32(0.5f * result.getWidth()) + 1);
4577         tcu::Surface            errorMask               (result.getWidth(), result.getHeight());
4578         bool                            anyError                = false;
4579
4580         tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toIVec());
4581
4582         for (int y = 0; y < result.getHeight(); ++y)
4583         for (int x = 0; x < result.getWidth(); ++x)
4584         {
4585                 const tcu::IVec4        pixel                   = result.getPixelInt(x, y);
4586                 const bool                      insideMeshArea  = x >= insideBorder.x() && x <= insideBorder.x();
4587                 const bool                      outsideMeshArea = x <= outsideBorder.x() && x >= outsideBorder.x();
4588
4589                 // inside mesh, allow green, yellow and any shade between
4590                 // outside mesh, allow background (black) only
4591                 // in the border area, allow anything
4592                 if ((insideMeshArea && (pixel[1] != 255 || pixel[2] != 0)) ||
4593                         (outsideMeshArea && (pixel[0] != 0 || pixel[1] != 0 || pixel[2] != 0)))
4594                 {
4595                         errorMask.setPixel(x, y, tcu::RGBA::red);
4596                         anyError = true;
4597                 }
4598         }
4599
4600         if (anyError)
4601         {
4602                 m_testCtx.getLog()
4603                         << tcu::TestLog::Message
4604                         << "Image verification failed."
4605                         << tcu::TestLog::EndMessage
4606                         << tcu::TestLog::ImageSet("Images", "Image verification")
4607                         << tcu::TestLog::Image("ResultImage", "Result image", result)
4608                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask)
4609                         << tcu::TestLog::EndImageSet;
4610         }
4611
4612         return !anyError;
4613 }
4614
4615 std::string ViewportCallOrderCase::genVertexSource (void) const
4616 {
4617         return  s_yellowishPosOnlyVertexSource;
4618 }
4619
4620 std::string ViewportCallOrderCase::genFragmentSource (void) const
4621 {
4622         return s_basicColorFragmentSource;
4623 }
4624
4625 std::string ViewportCallOrderCase::genTessellationControlSource (void) const
4626 {
4627         return  "#version 310 es\n"
4628                         "#extension GL_EXT_tessellation_shader : require\n"
4629                         "layout(vertices=3) out;\n"
4630                         "in highp vec4 v_vertex_color[];\n"
4631                         "out highp vec4 v_tess_eval_color[];\n"
4632                         "void main()\n"
4633                         "{\n"
4634                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
4635                         "       v_tess_eval_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
4636                         "       gl_TessLevelOuter[0] = 2.8;\n"
4637                         "       gl_TessLevelOuter[1] = 2.8;\n"
4638                         "       gl_TessLevelOuter[2] = 2.8;\n"
4639                         "       gl_TessLevelInner[0] = 2.8;\n"
4640                         "}\n";
4641 }
4642
4643 std::string ViewportCallOrderCase::genTessellationEvaluationSource (void) const
4644 {
4645         return s_basicColorTessEvalSource;
4646 }
4647
4648 } // anonymous
4649
4650 PrimitiveBoundingBoxTests::PrimitiveBoundingBoxTests (Context& context)
4651         : TestCaseGroup(context, "primitive_bounding_box", "Tests for EXT_primitive_bounding_box")
4652 {
4653 }
4654
4655 PrimitiveBoundingBoxTests::~PrimitiveBoundingBoxTests (void)
4656 {
4657 }
4658
4659 void PrimitiveBoundingBoxTests::init (void)
4660 {
4661         static const struct
4662         {
4663                 const char*     name;
4664                 const char*     description;
4665                 deUint32        methodFlags;
4666         } stateSetMethods[] =
4667         {
4668                 {
4669                         "global_state",
4670                         "Set bounding box using PRIMITIVE_BOUNDING_BOX_EXT state",
4671                         BBoxRenderCase::FLAG_SET_BBOX_STATE,
4672                 },
4673                 {
4674                         "tessellation_set_per_draw",
4675                         "Set bounding box using gl_BoundingBoxEXT, use same value for all primitives",
4676                         BBoxRenderCase::FLAG_SET_BBOX_OUTPUT,
4677                 },
4678                 {
4679                         "tessellation_set_per_primitive",
4680                         "Set bounding box using gl_BoundingBoxEXT, use per-primitive bounding box",
4681                         BBoxRenderCase::FLAG_SET_BBOX_OUTPUT | BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX,
4682                 },
4683         };
4684         static const struct
4685         {
4686                 const char*     name;
4687                 const char*     description;
4688                 deUint32        stageFlags;
4689         } pipelineConfigs[] =
4690         {
4691                 {
4692                         "vertex_fragment",
4693                         "Render with vertex-fragment program",
4694                         0u
4695                 },
4696                 {
4697                         "vertex_tessellation_fragment",
4698                         "Render with vertex-tessellation{ctrl,eval}-fragment program",
4699                         BBoxRenderCase::FLAG_TESSELLATION
4700                 },
4701                 {
4702                         "vertex_geometry_fragment",
4703                         "Render with vertex-tessellation{ctrl,eval}-geometry-fragment program",
4704                         BBoxRenderCase::FLAG_GEOMETRY
4705                 },
4706                 {
4707                         "vertex_tessellation_geometry_fragment",
4708                         "Render with vertex-geometry-fragment program",
4709                         BBoxRenderCase::FLAG_TESSELLATION | BBoxRenderCase::FLAG_GEOMETRY
4710                 },
4711         };
4712         static const struct
4713         {
4714                 const char*     name;
4715                 const char*     description;
4716                 deUint32        flags;
4717                 deUint32        invalidFlags;
4718                 deUint32        requiredFlags;
4719         } usageConfigs[] =
4720         {
4721                 {
4722                         "default_framebuffer_bbox_equal",
4723                         "Render to default framebuffer, set tight bounding box",
4724                         BBoxRenderCase::FLAG_RENDERTARGET_DEFAULT | BBoxRenderCase::FLAG_BBOXSIZE_EQUAL,
4725                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX,
4726                         0
4727                 },
4728                 {
4729                         "default_framebuffer_bbox_larger",
4730                         "Render to default framebuffer, set padded bounding box",
4731                         BBoxRenderCase::FLAG_RENDERTARGET_DEFAULT | BBoxRenderCase::FLAG_BBOXSIZE_LARGER,
4732                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX,
4733                         0
4734                 },
4735                 {
4736                         "default_framebuffer_bbox_smaller",
4737                         "Render to default framebuffer, set too small bounding box",
4738                         BBoxRenderCase::FLAG_RENDERTARGET_DEFAULT | BBoxRenderCase::FLAG_BBOXSIZE_SMALLER,
4739                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX,
4740                         0
4741                 },
4742                 {
4743                         "fbo_bbox_equal",
4744                         "Render to texture, set tight bounding box",
4745                         BBoxRenderCase::FLAG_RENDERTARGET_FBO | BBoxRenderCase::FLAG_BBOXSIZE_EQUAL,
4746                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX,
4747                         0
4748                 },
4749                 {
4750                         "fbo_bbox_larger",
4751                         "Render to texture, set padded bounding box",
4752                         BBoxRenderCase::FLAG_RENDERTARGET_FBO | BBoxRenderCase::FLAG_BBOXSIZE_LARGER,
4753                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX,
4754                         0
4755                 },
4756                 {
4757                         "fbo_bbox_smaller",
4758                         "Render to texture, set too small bounding box",
4759                         BBoxRenderCase::FLAG_RENDERTARGET_FBO | BBoxRenderCase::FLAG_BBOXSIZE_SMALLER,
4760                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX,
4761                         0
4762                 },
4763                 {
4764                         "default_framebuffer",
4765                         "Render to default framebuffer, set tight bounding box",
4766                         BBoxRenderCase::FLAG_RENDERTARGET_DEFAULT | BBoxRenderCase::FLAG_BBOXSIZE_EQUAL,
4767                         0,
4768                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX
4769                 },
4770                 {
4771                         "fbo",
4772                         "Render to texture, set tight bounding box",
4773                         BBoxRenderCase::FLAG_RENDERTARGET_FBO | BBoxRenderCase::FLAG_BBOXSIZE_EQUAL,
4774                         0,
4775                         BBoxRenderCase::FLAG_PER_PRIMITIVE_BBOX
4776                 },
4777         };
4778         enum PrimitiveRenderType
4779         {
4780                 TYPE_TRIANGLE,
4781                 TYPE_LINE,
4782                 TYPE_POINT,
4783         };
4784         const struct
4785         {
4786                 const char*                     name;
4787                 const char*                     description;
4788                 PrimitiveRenderType     type;
4789                 deUint32                        flags;
4790         } primitiveTypes[] =
4791         {
4792                 {
4793                         "triangles",
4794                         "Triangle render tests",
4795                         TYPE_TRIANGLE,
4796                         0
4797                 },
4798                 {
4799                         "lines",
4800                         "Line render tests",
4801                         TYPE_LINE,
4802                         0
4803                 },
4804                 {
4805                         "points",
4806                         "Point render tests",
4807                         TYPE_POINT,
4808                         0
4809                 },
4810                 {
4811                         "wide_lines",
4812                         "Wide line render tests",
4813                         TYPE_LINE,
4814                         LineRenderCase::LINEFLAG_WIDE
4815                 },
4816                 {
4817                         "wide_points",
4818                         "Wide point render tests",
4819                         TYPE_POINT,
4820                         PointRenderCase::POINTFLAG_WIDE
4821                 },
4822         };
4823
4824         // .state_query
4825         {
4826                 tcu::TestCaseGroup* const stateQueryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "State queries");
4827                 addChild(stateQueryGroup);
4828
4829                 stateQueryGroup->addChild(new InitialValueCase  (m_context,     "initial_value",        "Initial value case"));
4830                 stateQueryGroup->addChild(new QueryCase                 (m_context,     "getfloat",                     "getFloatv",                    QueryCase::QUERY_FLOAT));
4831                 stateQueryGroup->addChild(new QueryCase                 (m_context,     "getboolean",           "getBooleanv",                  QueryCase::QUERY_BOOLEAN));
4832                 stateQueryGroup->addChild(new QueryCase                 (m_context,     "getinteger",           "getIntegerv",                  QueryCase::QUERY_INT));
4833                 stateQueryGroup->addChild(new QueryCase                 (m_context,     "getinteger64",         "getInteger64v",                QueryCase::QUERY_INT64));
4834         }
4835
4836         // .triangles
4837         // .(wide_)lines
4838         // .(wide_)points
4839         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
4840         {
4841                 tcu::TestCaseGroup* const primitiveGroup = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, primitiveTypes[primitiveTypeNdx].description);
4842                 addChild(primitiveGroup);
4843
4844                 for (int stateSetMethodNdx = 0; stateSetMethodNdx < DE_LENGTH_OF_ARRAY(stateSetMethods); ++stateSetMethodNdx)
4845                 {
4846                         tcu::TestCaseGroup* const methodGroup = new tcu::TestCaseGroup(m_testCtx, stateSetMethods[stateSetMethodNdx].name, stateSetMethods[stateSetMethodNdx].description);
4847                         primitiveGroup->addChild(methodGroup);
4848
4849                         for (int pipelineConfigNdx = 0; pipelineConfigNdx < DE_LENGTH_OF_ARRAY(pipelineConfigs); ++pipelineConfigNdx)
4850                         {
4851                                 if ((stateSetMethods[stateSetMethodNdx].methodFlags & BBoxRenderCase::FLAG_SET_BBOX_OUTPUT) != 0 &&
4852                                         (pipelineConfigs[pipelineConfigNdx].stageFlags  & BBoxRenderCase::FLAG_TESSELLATION)    == 0)
4853                                 {
4854                                         // invalid config combination
4855                                 }
4856                                 else
4857                                 {
4858                                         tcu::TestCaseGroup* const pipelineGroup = new tcu::TestCaseGroup(m_testCtx, pipelineConfigs[pipelineConfigNdx].name, pipelineConfigs[pipelineConfigNdx].description);
4859                                         methodGroup->addChild(pipelineGroup);
4860
4861                                         for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usageConfigs); ++usageNdx)
4862                                         {
4863                                                 const deUint32 flags = primitiveTypes[primitiveTypeNdx].flags         |
4864                                                                                            stateSetMethods[stateSetMethodNdx].methodFlags |
4865                                                                                            pipelineConfigs[pipelineConfigNdx].stageFlags  |
4866                                                                                            usageConfigs[usageNdx].flags;
4867
4868                                                 if (usageConfigs[usageNdx].invalidFlags && (flags & usageConfigs[usageNdx].invalidFlags) != 0)
4869                                                         continue;
4870                                                 if (usageConfigs[usageNdx].requiredFlags && (flags & usageConfigs[usageNdx].requiredFlags) == 0)
4871                                                         continue;
4872
4873                                                 switch (primitiveTypes[primitiveTypeNdx].type)
4874                                                 {
4875                                                         case TYPE_TRIANGLE:
4876                                                                 pipelineGroup->addChild(new GridRenderCase(m_context, usageConfigs[usageNdx].name, usageConfigs[usageNdx].description, flags));
4877                                                                 break;
4878                                                         case TYPE_LINE:
4879                                                                 pipelineGroup->addChild(new LineRenderCase(m_context, usageConfigs[usageNdx].name, usageConfigs[usageNdx].description, flags));
4880                                                                 break;
4881                                                         case TYPE_POINT:
4882                                                                 pipelineGroup->addChild(new PointRenderCase(m_context, usageConfigs[usageNdx].name, usageConfigs[usageNdx].description, flags));
4883                                                                 break;
4884                                                         default:
4885                                                                 DE_ASSERT(false);
4886                                                 }
4887                                         }
4888                                 }
4889                         }
4890                 }
4891         }
4892
4893         // .depth
4894         {
4895                 static const struct
4896                 {
4897                         const char*                                     name;
4898                         const char*                                     description;
4899                         DepthDrawCase::DepthType        depthMethod;
4900                 } depthMethods[] =
4901                 {
4902                         {
4903                                 "builtin_depth",
4904                                 "Fragment depth not modified in fragment shader",
4905                                 DepthDrawCase::DEPTH_BUILTIN
4906                         },
4907                         {
4908                                 "user_defined_depth",
4909                                 "Fragment depth is defined in the fragment shader",
4910                                 DepthDrawCase::DEPTH_USER_DEFINED
4911                         },
4912                 };
4913                 static const struct
4914                 {
4915                         const char*                                     name;
4916                         const char*                                     description;
4917                         DepthDrawCase::BBoxState        bboxState;
4918                         DepthDrawCase::BBoxSize         bboxSize;
4919                 } depthCases[] =
4920                 {
4921                         {
4922                                 "global_state_bbox_equal",
4923                                 "Test tight bounding box with global bbox state",
4924                                 DepthDrawCase::STATE_GLOBAL,
4925                                 DepthDrawCase::BBOX_EQUAL,
4926                         },
4927                         {
4928                                 "global_state_bbox_larger",
4929                                 "Test padded bounding box with global bbox state",
4930                                 DepthDrawCase::STATE_GLOBAL,
4931                                 DepthDrawCase::BBOX_LARGER,
4932                         },
4933                         {
4934                                 "per_primitive_bbox_equal",
4935                                 "Test tight bounding box with tessellation output bbox",
4936                                 DepthDrawCase::STATE_PER_PRIMITIVE,
4937                                 DepthDrawCase::BBOX_EQUAL,
4938                         },
4939                         {
4940                                 "per_primitive_bbox_larger",
4941                                 "Test padded bounding box with tessellation output bbox",
4942                                 DepthDrawCase::STATE_PER_PRIMITIVE,
4943                                 DepthDrawCase::BBOX_LARGER,
4944                         },
4945                 };
4946
4947                 tcu::TestCaseGroup* const depthGroup = new tcu::TestCaseGroup(m_testCtx, "depth", "Test bounding box depth component");
4948                 addChild(depthGroup);
4949
4950                 // .builtin_depth
4951                 // .user_defined_depth
4952                 for (int depthNdx = 0; depthNdx < DE_LENGTH_OF_ARRAY(depthMethods); ++depthNdx)
4953                 {
4954                         tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, depthMethods[depthNdx].name, depthMethods[depthNdx].description);
4955                         depthGroup->addChild(group);
4956
4957                         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(depthCases); ++caseNdx)
4958                                 group->addChild(new DepthDrawCase(m_context, depthCases[caseNdx].name, depthCases[caseNdx].description, depthMethods[depthNdx].depthMethod, depthCases[caseNdx].bboxState, depthCases[caseNdx].bboxSize));
4959                 }
4960         }
4961
4962         // .blit_fbo
4963         {
4964                 tcu::TestCaseGroup* const blitFboGroup = new tcu::TestCaseGroup(m_testCtx, "blit_fbo", "Test bounding box does not affect blitting");
4965                 addChild(blitFboGroup);
4966
4967                 blitFboGroup->addChild(new BlitFboCase(m_context, "blit_default_to_fbo", "Blit from default fb to fbo", BlitFboCase::TARGET_DEFAULT, BlitFboCase::TARGET_FBO));
4968                 blitFboGroup->addChild(new BlitFboCase(m_context, "blit_fbo_to_default", "Blit from fbo to default fb", BlitFboCase::TARGET_FBO,     BlitFboCase::TARGET_DEFAULT));
4969                 blitFboGroup->addChild(new BlitFboCase(m_context, "blit_fbo_to_fbo",     "Blit from fbo to fbo",        BlitFboCase::TARGET_FBO,     BlitFboCase::TARGET_FBO));
4970         }
4971
4972         // .clear
4973         {
4974                 tcu::TestCaseGroup* const clearGroup = new tcu::TestCaseGroup(m_testCtx, "clear", "Test bounding box does not clears");
4975                 addChild(clearGroup);
4976
4977                 clearGroup->addChild(new ClearCase(m_context, "full_clear",                                             "Do full clears",                                               0));
4978                 clearGroup->addChild(new ClearCase(m_context, "full_clear_with_triangles",                              "Do full clears and render some geometry",                      ClearCase::DRAW_TRIANGLE_BIT));
4979                 clearGroup->addChild(new ClearCase(m_context, "full_clear_with_triangles_per_primitive_bbox",           "Do full clears and render some geometry",                      ClearCase::DRAW_TRIANGLE_BIT | ClearCase::PER_PRIMITIVE_BBOX_BIT));
4980                 clearGroup->addChild(new ClearCase(m_context, "scissored_clear",                                        "Do scissored clears",                                          ClearCase::SCISSOR_CLEAR_BIT));
4981                 clearGroup->addChild(new ClearCase(m_context, "scissored_clear_with_triangles",                         "Do scissored clears and render some geometry",                 ClearCase::SCISSOR_CLEAR_BIT | ClearCase::DRAW_TRIANGLE_BIT));
4982                 clearGroup->addChild(new ClearCase(m_context, "scissored_clear_with_triangles_per_primitive_bbox",      "Do scissored clears and render some geometry",                 ClearCase::SCISSOR_CLEAR_BIT | ClearCase::DRAW_TRIANGLE_BIT | ClearCase::PER_PRIMITIVE_BBOX_BIT));
4983                 clearGroup->addChild(new ClearCase(m_context, "scissored_full_clear",                                   "Do full clears with enabled scissor",                          ClearCase::FULLSCREEN_SCISSOR_BIT | ClearCase::SCISSOR_CLEAR_BIT));
4984                 clearGroup->addChild(new ClearCase(m_context, "scissored_full_clear_with_triangles",                    "Do full clears with enabled scissor and render some geometry", ClearCase::FULLSCREEN_SCISSOR_BIT | ClearCase::SCISSOR_CLEAR_BIT | ClearCase::DRAW_TRIANGLE_BIT));
4985                 clearGroup->addChild(new ClearCase(m_context, "scissored_full_clear_with_triangles_per_primitive_bbox", "Do full clears with enabled scissor and render some geometry", ClearCase::FULLSCREEN_SCISSOR_BIT | ClearCase::SCISSOR_CLEAR_BIT | ClearCase::DRAW_TRIANGLE_BIT | ClearCase::PER_PRIMITIVE_BBOX_BIT));
4986         }
4987
4988         // .call_order (Khronos bug #13262)
4989         {
4990                 tcu::TestCaseGroup* const callOrderGroup = new tcu::TestCaseGroup(m_testCtx, "call_order", "Test viewport and bounding box calls have no effect");
4991                 addChild(callOrderGroup);
4992
4993                 callOrderGroup->addChild(new ViewportCallOrderCase(m_context, "viewport_first_bbox_second", "Set up viewport first and bbox after", ViewportCallOrderCase::VIEWPORT_FIRST));
4994                 callOrderGroup->addChild(new ViewportCallOrderCase(m_context, "bbox_first_viewport_second", "Set up bbox first and viewport after", ViewportCallOrderCase::BBOX_FIRST));
4995         }
4996 }
4997
4998 } // Functional
4999 } // gles31
5000 } // deqp