Lower correlation threshold in flush-finish tests again am: 6455e6f987 am: 2e18b48b04...
[platform/upstream/VK-GL-CTS.git] / modules / egl / teglRenderTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program EGL Module
3  * ---------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Rendering tests for different config and api combinations.
22  * \todo [2013-03-19 pyry] GLES1 and VG support.
23  *//*--------------------------------------------------------------------*/
24
25 #include "teglRenderTests.hpp"
26 #include "teglRenderCase.hpp"
27
28 #include "tcuRenderTarget.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuImageCompare.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuSurface.hpp"
33
34 #include "egluDefs.hpp"
35 #include "egluUtil.hpp"
36
37 #include "eglwLibrary.hpp"
38 #include "eglwEnums.hpp"
39
40 #include "gluShaderProgram.hpp"
41
42 #include "glwFunctions.hpp"
43 #include "glwEnums.hpp"
44
45 #include "deRandom.hpp"
46 #include "deSharedPtr.hpp"
47 #include "deSemaphore.hpp"
48 #include "deThread.hpp"
49 #include "deString.h"
50
51 #include "rrRenderer.hpp"
52 #include "rrFragmentOperations.hpp"
53
54 #include <algorithm>
55 #include <iterator>
56 #include <memory>
57 #include <set>
58
59 namespace deqp
60 {
61 namespace egl
62 {
63
64 using std::string;
65 using std::vector;
66 using std::set;
67
68 using tcu::Vec4;
69
70 using tcu::TestLog;
71
72 using namespace glw;
73 using namespace eglw;
74
75 static const tcu::Vec4  CLEAR_COLOR             = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
76 static const float              CLEAR_DEPTH             = 1.0f;
77 static const int                CLEAR_STENCIL   = 0;
78
79 namespace
80 {
81
82 enum PrimitiveType
83 {
84         PRIMITIVETYPE_TRIANGLE = 0,     //!< Triangles, requires 3 coordinates per primitive
85 //      PRIMITIVETYPE_POINT,            //!< Points, requires 1 coordinate per primitive (w is used as size)
86 //      PRIMITIVETYPE_LINE,                     //!< Lines, requires 2 coordinates per primitive
87
88         PRIMITIVETYPE_LAST
89 };
90
91 enum BlendMode
92 {
93         BLENDMODE_NONE = 0,                     //!< No blending
94         BLENDMODE_ADDITIVE,                     //!< Blending with ONE, ONE
95         BLENDMODE_SRC_OVER,                     //!< Blending with SRC_ALPHA, ONE_MINUS_SRC_ALPHA
96
97         BLENDMODE_LAST
98 };
99
100 enum DepthMode
101 {
102         DEPTHMODE_NONE = 0,                     //!< No depth test or depth writes
103         DEPTHMODE_LESS,                         //!< Depth test with less & depth write
104
105         DEPTHMODE_LAST
106 };
107
108 enum StencilMode
109 {
110         STENCILMODE_NONE = 0,           //!< No stencil test or write
111         STENCILMODE_LEQUAL_INC,         //!< Stencil test with LEQUAL, increment on pass
112
113         STENCILMODE_LAST
114 };
115
116 struct DrawPrimitiveOp
117 {
118         PrimitiveType   type;
119         int                             count;
120         vector<Vec4>    positions;
121         vector<Vec4>    colors;
122         BlendMode               blend;
123         DepthMode               depth;
124         StencilMode             stencil;
125         int                             stencilRef;
126 };
127
128 static bool isANarrowScreenSpaceTriangle (const tcu::Vec4& p0, const tcu::Vec4& p1, const tcu::Vec4& p2)
129 {
130         // to clip space
131         const tcu::Vec2 csp0                            = p0.swizzle(0, 1) / p0.w();
132         const tcu::Vec2 csp1                            = p1.swizzle(0, 1) / p1.w();
133         const tcu::Vec2 csp2                            = p2.swizzle(0, 1) / p2.w();
134
135         const tcu::Vec2 e01                                     = (csp1 - csp0);
136         const tcu::Vec2 e02                                     = (csp2 - csp0);
137
138         const float             minimumVisibleArea      = 0.4f; // must cover at least 10% of the surface
139         const float             visibleArea                     = de::abs(e01.x() * e02.y() - e02.x() * e01.y()) * 0.5f;
140
141         return visibleArea < minimumVisibleArea;
142 }
143
144 void randomizeDrawOp (de::Random& rnd, DrawPrimitiveOp& drawOp)
145 {
146         const int       minStencilRef   = 0;
147         const int       maxStencilRef   = 8;
148         const int       minPrimitives   = 2;
149         const int       maxPrimitives   = 4;
150
151         const float     maxTriOffset    = 1.0f;
152         const float     minDepth                = -1.0f; // \todo [pyry] Reference doesn't support Z clipping yet
153         const float     maxDepth                = 1.0f;
154
155         const float     minRGB                  = 0.2f;
156         const float     maxRGB                  = 0.9f;
157         const float     minAlpha                = 0.3f;
158         const float     maxAlpha                = 1.0f;
159
160         drawOp.type                     = (PrimitiveType)rnd.getInt(0, PRIMITIVETYPE_LAST-1);
161         drawOp.count            = rnd.getInt(minPrimitives, maxPrimitives);
162         drawOp.blend            = (BlendMode)rnd.getInt(0, BLENDMODE_LAST-1);
163         drawOp.depth            = (DepthMode)rnd.getInt(0, DEPTHMODE_LAST-1);
164         drawOp.stencil          = (StencilMode)rnd.getInt(0, STENCILMODE_LAST-1);
165         drawOp.stencilRef       = rnd.getInt(minStencilRef, maxStencilRef);
166
167         if (drawOp.type == PRIMITIVETYPE_TRIANGLE)
168         {
169                 drawOp.positions.resize(drawOp.count*3);
170                 drawOp.colors.resize(drawOp.count*3);
171
172                 for (int triNdx = 0; triNdx < drawOp.count; triNdx++)
173                 {
174                         const float             cx              = rnd.getFloat(-1.0f, 1.0f);
175                         const float             cy              = rnd.getFloat(-1.0f, 1.0f);
176
177                         for (int coordNdx = 0; coordNdx < 3; coordNdx++)
178                         {
179                                 tcu::Vec4&      position        = drawOp.positions[triNdx*3 + coordNdx];
180                                 tcu::Vec4&      color           = drawOp.colors[triNdx*3 + coordNdx];
181
182                                 position.x()    = cx + rnd.getFloat(-maxTriOffset, maxTriOffset);
183                                 position.y()    = cy + rnd.getFloat(-maxTriOffset, maxTriOffset);
184                                 position.z()    = rnd.getFloat(minDepth, maxDepth);
185                                 position.w()    = 1.0f;
186
187                                 color.x()               = rnd.getFloat(minRGB, maxRGB);
188                                 color.y()               = rnd.getFloat(minRGB, maxRGB);
189                                 color.z()               = rnd.getFloat(minRGB, maxRGB);
190                                 color.w()               = rnd.getFloat(minAlpha, maxAlpha);
191                         }
192
193                         // avoid generating narrow triangles
194                         {
195                                 const int       maxAttempts     = 40;
196                                 int                     numAttempts     = 0;
197                                 tcu::Vec4&      p0                      = drawOp.positions[triNdx*3 + 0];
198                                 tcu::Vec4&      p1                      = drawOp.positions[triNdx*3 + 1];
199                                 tcu::Vec4&      p2                      = drawOp.positions[triNdx*3 + 2];
200
201                                 while (isANarrowScreenSpaceTriangle(p0, p1, p2))
202                                 {
203                                         p1.x()  = cx + rnd.getFloat(-maxTriOffset, maxTriOffset);
204                                         p1.y()  = cy + rnd.getFloat(-maxTriOffset, maxTriOffset);
205                                         p1.z()  = rnd.getFloat(minDepth, maxDepth);
206                                         p1.w()  = 1.0f;
207
208                                         p2.x()  = cx + rnd.getFloat(-maxTriOffset, maxTriOffset);
209                                         p2.y()  = cy + rnd.getFloat(-maxTriOffset, maxTriOffset);
210                                         p2.z()  = rnd.getFloat(minDepth, maxDepth);
211                                         p2.w()  = 1.0f;
212
213                                         if (++numAttempts > maxAttempts)
214                                         {
215                                                 DE_ASSERT(false);
216                                                 break;
217                                         }
218                                 }
219                         }
220                 }
221         }
222         else
223                 DE_ASSERT(false);
224 }
225
226 // Reference rendering code
227
228 class ReferenceShader : public rr::VertexShader, public rr::FragmentShader
229 {
230 public:
231         enum
232         {
233                 VaryingLoc_Color = 0
234         };
235
236         ReferenceShader ()
237                 : rr::VertexShader      (2, 1)          // color and pos in => color out
238                 , rr::FragmentShader(1, 1)              // color in => color out
239         {
240                 this->rr::VertexShader::m_inputs[0].type                = rr::GENERICVECTYPE_FLOAT;
241                 this->rr::VertexShader::m_inputs[1].type                = rr::GENERICVECTYPE_FLOAT;
242
243                 this->rr::VertexShader::m_outputs[0].type               = rr::GENERICVECTYPE_FLOAT;
244                 this->rr::VertexShader::m_outputs[0].flatshade  = false;
245
246                 this->rr::FragmentShader::m_inputs[0].type              = rr::GENERICVECTYPE_FLOAT;
247                 this->rr::FragmentShader::m_inputs[0].flatshade = false;
248
249                 this->rr::FragmentShader::m_outputs[0].type             = rr::GENERICVECTYPE_FLOAT;
250         }
251
252         void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
253         {
254                 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
255                 {
256                         const int positionAttrLoc = 0;
257                         const int colorAttrLoc = 1;
258
259                         rr::VertexPacket& packet = *packets[packetNdx];
260
261                         // Transform to position
262                         packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
263
264                         // Pass color to FS
265                         packet.outputs[VaryingLoc_Color] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
266                 }
267         }
268
269         void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
270         {
271                 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
272                 {
273                         rr::FragmentPacket& packet = packets[packetNdx];
274
275                         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
276                                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VaryingLoc_Color, fragNdx));
277                 }
278         }
279 };
280
281 void toReferenceRenderState (rr::RenderState& state, const DrawPrimitiveOp& drawOp)
282 {
283         state.cullMode  = rr::CULLMODE_NONE;
284
285         if (drawOp.blend != BLENDMODE_NONE)
286         {
287                 state.fragOps.blendMode = rr::BLENDMODE_STANDARD;
288
289                 switch (drawOp.blend)
290                 {
291                         case BLENDMODE_ADDITIVE:
292                                 state.fragOps.blendRGBState.srcFunc             = rr::BLENDFUNC_ONE;
293                                 state.fragOps.blendRGBState.dstFunc             = rr::BLENDFUNC_ONE;
294                                 state.fragOps.blendRGBState.equation    = rr::BLENDEQUATION_ADD;
295                                 state.fragOps.blendAState                               = state.fragOps.blendRGBState;
296                                 break;
297
298                         case BLENDMODE_SRC_OVER:
299                                 state.fragOps.blendRGBState.srcFunc             = rr::BLENDFUNC_SRC_ALPHA;
300                                 state.fragOps.blendRGBState.dstFunc             = rr::BLENDFUNC_ONE_MINUS_SRC_ALPHA;
301                                 state.fragOps.blendRGBState.equation    = rr::BLENDEQUATION_ADD;
302                                 state.fragOps.blendAState                               = state.fragOps.blendRGBState;
303                                 break;
304
305                         default:
306                                 DE_ASSERT(false);
307                 }
308         }
309
310         if (drawOp.depth != DEPTHMODE_NONE)
311         {
312                 state.fragOps.depthTestEnabled = true;
313
314                 DE_ASSERT(drawOp.depth == DEPTHMODE_LESS);
315                 state.fragOps.depthFunc = rr::TESTFUNC_LESS;
316         }
317
318         if (drawOp.stencil != STENCILMODE_NONE)
319         {
320                 state.fragOps.stencilTestEnabled = true;
321
322                 DE_ASSERT(drawOp.stencil == STENCILMODE_LEQUAL_INC);
323                 state.fragOps.stencilStates[0].func             = rr::TESTFUNC_LEQUAL;
324                 state.fragOps.stencilStates[0].sFail    = rr::STENCILOP_KEEP;
325                 state.fragOps.stencilStates[0].dpFail   = rr::STENCILOP_INCR;
326                 state.fragOps.stencilStates[0].dpPass   = rr::STENCILOP_INCR;
327                 state.fragOps.stencilStates[0].ref              = drawOp.stencilRef;
328                 state.fragOps.stencilStates[1]                  = state.fragOps.stencilStates[0];
329         }
330 }
331
332 tcu::TextureFormat getColorFormat (const tcu::PixelFormat& colorBits)
333 {
334         using tcu::TextureFormat;
335
336         DE_ASSERT(de::inBounds(colorBits.redBits,       0, 0xff) &&
337                           de::inBounds(colorBits.greenBits,     0, 0xff) &&
338                           de::inBounds(colorBits.blueBits,      0, 0xff) &&
339                           de::inBounds(colorBits.alphaBits,     0, 0xff));
340
341 #define PACK_FMT(R, G, B, A) (((R) << 24) | ((G) << 16) | ((B) << 8) | (A))
342
343         // \note [pyry] This may not hold true on some implementations - best effort guess only.
344         switch (PACK_FMT(colorBits.redBits, colorBits.greenBits, colorBits.blueBits, colorBits.alphaBits))
345         {
346                 case PACK_FMT(8,8,8,8):         return TextureFormat(TextureFormat::RGBA,       TextureFormat::UNORM_INT8);
347                 case PACK_FMT(8,8,8,0):         return TextureFormat(TextureFormat::RGB,        TextureFormat::UNORM_INT8);
348                 case PACK_FMT(4,4,4,4):         return TextureFormat(TextureFormat::RGBA,       TextureFormat::UNORM_SHORT_4444);
349                 case PACK_FMT(5,5,5,1):         return TextureFormat(TextureFormat::RGBA,       TextureFormat::UNORM_SHORT_5551);
350                 case PACK_FMT(5,6,5,0):         return TextureFormat(TextureFormat::RGB,        TextureFormat::UNORM_SHORT_565);
351
352                 // \note Defaults to RGBA8
353                 default:                                        return TextureFormat(TextureFormat::RGBA,       TextureFormat::UNORM_INT8);
354         }
355
356 #undef PACK_FMT
357 }
358
359 /*
360 The getColorThreshold function is used to obtain a
361 threshold usable for the fuzzyCompare function.
362
363 For 8bit color depths a value of 0.02 should provide
364 a good metric for rejecting images above this level.
365 For other bit depths other thresholds should be selected.
366 Ideally this function would take advantage of the
367 getColorThreshold function provided by the PixelFormat class
368 as this would also allow setting per channel thresholds.
369 However using the PixelFormat provided function can result
370 in too strict thresholds for 8bit bit depths (compared to
371 the current default of 0.02) or too relaxed for lower bit
372 depths if scaled proportionally to the 8bit default.
373 */
374
375 float getColorThreshold (const tcu::PixelFormat& colorBits)
376 {
377         if ((colorBits.redBits > 0 && colorBits.redBits < 8) ||
378                 (colorBits.greenBits > 0 && colorBits.greenBits < 8) ||
379                 (colorBits.blueBits > 0 && colorBits.blueBits < 8) ||
380                 (colorBits.alphaBits > 0 && colorBits.alphaBits < 8))
381         {
382                 return 0.05f;
383         }
384         else
385         {
386                 return 0.02f;
387         }
388 }
389
390 tcu::TextureFormat getDepthFormat (const int depthBits)
391 {
392         switch (depthBits)
393         {
394                 case 0:         return tcu::TextureFormat();
395                 case 8:         return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8);
396                 case 16:        return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
397                 case 24:        return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT24);
398                 case 32:
399                 default:        return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT);
400         }
401 }
402
403 tcu::TextureFormat getStencilFormat (int stencilBits)
404 {
405         switch (stencilBits)
406         {
407                 case 0:         return tcu::TextureFormat();
408                 case 8:
409                 default:        return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
410         }
411 }
412
413 void renderReference (const tcu::PixelBufferAccess& dst, const vector<DrawPrimitiveOp>& drawOps, const tcu::PixelFormat& colorBits, const int depthBits, const int stencilBits, const int numSamples)
414 {
415         const int                                               width                   = dst.getWidth();
416         const int                                               height                  = dst.getHeight();
417
418         tcu::TextureLevel                               colorBuffer;
419         tcu::TextureLevel                               depthBuffer;
420         tcu::TextureLevel                               stencilBuffer;
421
422         rr::Renderer                                    referenceRenderer;
423         rr::VertexAttrib                                attributes[2];
424         const ReferenceShader                   shader;
425
426         attributes[0].type                              = rr::VERTEXATTRIBTYPE_FLOAT;
427         attributes[0].size                              = 4;
428         attributes[0].stride                    = 0;
429         attributes[0].instanceDivisor   = 0;
430
431         attributes[1].type                              = rr::VERTEXATTRIBTYPE_FLOAT;
432         attributes[1].size                              = 4;
433         attributes[1].stride                    = 0;
434         attributes[1].instanceDivisor   = 0;
435
436         // Initialize buffers.
437         colorBuffer.setStorage(getColorFormat(colorBits), numSamples, width, height);
438         rr::clearMultisampleColorBuffer(colorBuffer, CLEAR_COLOR, rr::WindowRectangle(0, 0, width, height));
439
440         if (depthBits > 0)
441         {
442                 depthBuffer.setStorage(getDepthFormat(depthBits), numSamples, width, height);
443                 rr::clearMultisampleDepthBuffer(depthBuffer, CLEAR_DEPTH, rr::WindowRectangle(0, 0, width, height));
444         }
445
446         if (stencilBits > 0)
447         {
448                 stencilBuffer.setStorage(getStencilFormat(stencilBits), numSamples, width, height);
449                 rr::clearMultisampleStencilBuffer(stencilBuffer, CLEAR_STENCIL, rr::WindowRectangle(0, 0, width, height));
450         }
451
452         const rr::RenderTarget renderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()),
453                                                                                 rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer.getAccess()),
454                                                                                 rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer.getAccess()));
455
456         for (vector<DrawPrimitiveOp>::const_iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); drawOp++)
457         {
458                 // Translate state
459                 rr::RenderState renderState((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess())));
460                 toReferenceRenderState(renderState, *drawOp);
461
462                 DE_ASSERT(drawOp->type == PRIMITIVETYPE_TRIANGLE);
463
464                 attributes[0].pointer = &drawOp->positions[0];
465                 attributes[1].pointer = &drawOp->colors[0];
466
467                 referenceRenderer.draw(
468                         rr::DrawCommand(
469                                 renderState,
470                                 renderTarget,
471                                 rr::Program(static_cast<const rr::VertexShader*>(&shader), static_cast<const rr::FragmentShader*>(&shader)),
472                                 2,
473                                 attributes,
474                                 rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, drawOp->count * 3, 0)));
475         }
476
477         rr::resolveMultisampleColorBuffer(dst, rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()));
478 }
479
480 // API rendering code
481
482 class Program
483 {
484 public:
485                                         Program                         (void) {}
486         virtual                 ~Program                        (void) {}
487
488         virtual void    setup                           (void) const = DE_NULL;
489 };
490
491 typedef de::SharedPtr<Program> ProgramSp;
492
493 static glu::ProgramSources getProgramSourcesES2 (void)
494 {
495         static const char* s_vertexSrc =
496                 "attribute highp vec4 a_position;\n"
497                 "attribute mediump vec4 a_color;\n"
498                 "varying mediump vec4 v_color;\n"
499                 "void main (void)\n"
500                 "{\n"
501                 "       gl_Position = a_position;\n"
502                 "       v_color = a_color;\n"
503                 "}\n";
504
505         static const char* s_fragmentSrc =
506                 "varying mediump vec4 v_color;\n"
507                 "void main (void)\n"
508                 "{\n"
509                 "       gl_FragColor = v_color;\n"
510                 "}\n";
511
512         return glu::ProgramSources() << glu::VertexSource(s_vertexSrc) << glu::FragmentSource(s_fragmentSrc);
513 }
514
515 class GLES2Program : public Program
516 {
517 public:
518         GLES2Program (const glw::Functions& gl)
519                 : m_gl                          (gl)
520                 , m_program                     (gl, getProgramSourcesES2())
521                 , m_positionLoc         (0)
522                 , m_colorLoc            (0)
523         {
524
525                 m_positionLoc   = m_gl.getAttribLocation(m_program.getProgram(), "a_position");
526                 m_colorLoc              = m_gl.getAttribLocation(m_program.getProgram(), "a_color");
527         }
528
529         ~GLES2Program (void)
530         {
531         }
532
533         void setup (void) const
534         {
535                 m_gl.useProgram(m_program.getProgram());
536                 m_gl.enableVertexAttribArray(m_positionLoc);
537                 m_gl.enableVertexAttribArray(m_colorLoc);
538                 GLU_CHECK_GLW_MSG(m_gl, "Program setup failed");
539         }
540
541         int                                             getPositionLoc          (void) const { return m_positionLoc;    }
542         int                                             getColorLoc                     (void) const { return m_colorLoc;               }
543
544 private:
545         const glw::Functions&   m_gl;
546         glu::ShaderProgram              m_program;
547         int                                             m_positionLoc;
548         int                                             m_colorLoc;
549 };
550
551 void clearGLES2 (const glw::Functions& gl, const tcu::Vec4& color, const float depth, const int stencil)
552 {
553         gl.clearColor(color.x(), color.y(), color.z(), color.w());
554         gl.clearDepthf(depth);
555         gl.clearStencil(stencil);
556         gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
557 }
558
559 void drawGLES2 (const glw::Functions& gl, const Program& program, const DrawPrimitiveOp& drawOp)
560 {
561         const GLES2Program& gles2Program = dynamic_cast<const GLES2Program&>(program);
562
563         switch (drawOp.blend)
564         {
565                 case BLENDMODE_NONE:
566                         gl.disable(GL_BLEND);
567                         break;
568
569                 case BLENDMODE_ADDITIVE:
570                         gl.enable(GL_BLEND);
571                         gl.blendFunc(GL_ONE, GL_ONE);
572                         break;
573
574                 case BLENDMODE_SRC_OVER:
575                         gl.enable(GL_BLEND);
576                         gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
577                         break;
578
579                 default:
580                         DE_ASSERT(false);
581         }
582
583         switch (drawOp.depth)
584         {
585                 case DEPTHMODE_NONE:
586                         gl.disable(GL_DEPTH_TEST);
587                         break;
588
589                 case DEPTHMODE_LESS:
590                         gl.enable(GL_DEPTH_TEST);
591                         break;
592
593                 default:
594                         DE_ASSERT(false);
595         }
596
597         switch (drawOp.stencil)
598         {
599                 case STENCILMODE_NONE:
600                         gl.disable(GL_STENCIL_TEST);
601                         break;
602
603                 case STENCILMODE_LEQUAL_INC:
604                         gl.enable(GL_STENCIL_TEST);
605                         gl.stencilFunc(GL_LEQUAL, drawOp.stencilRef, ~0u);
606                         gl.stencilOp(GL_KEEP, GL_INCR, GL_INCR);
607                         break;
608
609                 default:
610                         DE_ASSERT(false);
611         }
612
613         gl.disable(GL_DITHER);
614
615         gl.vertexAttribPointer(gles2Program.getPositionLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.positions[0]);
616         gl.vertexAttribPointer(gles2Program.getColorLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.colors[0]);
617
618         DE_ASSERT(drawOp.type == PRIMITIVETYPE_TRIANGLE);
619         gl.drawArrays(GL_TRIANGLES, 0, drawOp.count*3);
620 }
621
622 static void readPixelsGLES2 (const glw::Functions& gl, tcu::Surface& dst)
623 {
624         gl.readPixels(0, 0, dst.getWidth(), dst.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, dst.getAccess().getDataPtr());
625 }
626
627 Program* createProgram (const glw::Functions& gl, EGLint api)
628 {
629         switch (api)
630         {
631                 case EGL_OPENGL_ES2_BIT:                return new GLES2Program(gl);
632                 case EGL_OPENGL_ES3_BIT_KHR:    return new GLES2Program(gl);
633                 default:
634                         throw tcu::NotSupportedError("Unsupported API");
635         }
636 }
637
638 void draw (const glw::Functions& gl, EGLint api, const Program& program, const DrawPrimitiveOp& drawOp)
639 {
640         switch (api)
641         {
642                 case EGL_OPENGL_ES2_BIT:                drawGLES2(gl, program, drawOp);         break;
643                 case EGL_OPENGL_ES3_BIT_KHR:    drawGLES2(gl, program, drawOp);         break;
644                 default:
645                         throw tcu::NotSupportedError("Unsupported API");
646         }
647 }
648
649 void clear (const glw::Functions& gl, EGLint api, const tcu::Vec4& color, const float depth, const int stencil)
650 {
651         switch (api)
652         {
653                 case EGL_OPENGL_ES2_BIT:                clearGLES2(gl, color, depth, stencil);          break;
654                 case EGL_OPENGL_ES3_BIT_KHR:    clearGLES2(gl, color, depth, stencil);          break;
655                 default:
656                         throw tcu::NotSupportedError("Unsupported API");
657         }
658 }
659
660 static void readPixels (const glw::Functions& gl, EGLint api, tcu::Surface& dst)
661 {
662         switch (api)
663         {
664                 case EGL_OPENGL_ES2_BIT:                readPixelsGLES2(gl, dst);               break;
665                 case EGL_OPENGL_ES3_BIT_KHR:    readPixelsGLES2(gl, dst);               break;
666                 default:
667                         throw tcu::NotSupportedError("Unsupported API");
668         }
669 }
670
671 static void finish (const glw::Functions& gl, EGLint api)
672 {
673         switch (api)
674         {
675                 case EGL_OPENGL_ES2_BIT:
676                 case EGL_OPENGL_ES3_BIT_KHR:
677                         gl.finish();
678                         break;
679
680                 default:
681                         throw tcu::NotSupportedError("Unsupported API");
682         }
683 }
684
685 tcu::PixelFormat getPixelFormat (const Library& egl, EGLDisplay display, EGLConfig config)
686 {
687         tcu::PixelFormat fmt;
688         fmt.redBits             = eglu::getConfigAttribInt(egl, display, config, EGL_RED_SIZE);
689         fmt.greenBits   = eglu::getConfigAttribInt(egl, display, config, EGL_GREEN_SIZE);
690         fmt.blueBits    = eglu::getConfigAttribInt(egl, display, config, EGL_BLUE_SIZE);
691         fmt.alphaBits   = eglu::getConfigAttribInt(egl, display, config, EGL_ALPHA_SIZE);
692         return fmt;
693 }
694
695 } // anonymous
696
697 // SingleThreadRenderCase
698
699 class SingleThreadRenderCase : public MultiContextRenderCase
700 {
701 public:
702                                                 SingleThreadRenderCase          (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi);
703
704         void                            init                                            (void);
705
706 private:
707         virtual void            executeForContexts                      (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts);
708
709         glw::Functions          m_gl;
710 };
711
712 // SingleThreadColorClearCase
713
714 SingleThreadRenderCase::SingleThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
715         : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
716 {
717 }
718
719 void SingleThreadRenderCase::init (void)
720 {
721         MultiContextRenderCase::init();
722         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
723 }
724
725 void SingleThreadRenderCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
726 {
727         const Library&                  egl                     = m_eglTestCtx.getLibrary();
728         const int                               width           = eglu::querySurfaceInt(egl, display, surface, EGL_WIDTH);
729         const int                               height          = eglu::querySurfaceInt(egl, display, surface, EGL_HEIGHT);
730         const int                               numContexts     = (int)contexts.size();
731         const int                               drawsPerCtx     = 2;
732         const int                               numIters        = 2;
733         const tcu::PixelFormat  pixelFmt        = getPixelFormat(egl, display, config.config);
734         const float                             threshold       = getColorThreshold(pixelFmt);
735
736         const int                               depthBits       = eglu::getConfigAttribInt(egl, display, config.config, EGL_DEPTH_SIZE);
737         const int                               stencilBits     = eglu::getConfigAttribInt(egl, display, config.config, EGL_STENCIL_SIZE);
738         const int                               numSamples      = eglu::getConfigAttribInt(egl, display, config.config, EGL_SAMPLES);
739
740         TestLog&                                log                     = m_testCtx.getLog();
741
742         tcu::Surface                    refFrame        (width, height);
743         tcu::Surface                    frame           (width, height);
744
745         de::Random                              rnd                     (deStringHash(getName()) ^ deInt32Hash(numContexts));
746         vector<ProgramSp>               programs        (contexts.size());
747         vector<DrawPrimitiveOp> drawOps;
748
749         // Log basic information about config.
750         log << TestLog::Message << "EGL_RED_SIZE = "            << pixelFmt.redBits << TestLog::EndMessage;
751         log << TestLog::Message << "EGL_GREEN_SIZE = "          << pixelFmt.greenBits << TestLog::EndMessage;
752         log << TestLog::Message << "EGL_BLUE_SIZE = "           << pixelFmt.blueBits << TestLog::EndMessage;
753         log << TestLog::Message << "EGL_ALPHA_SIZE = "          << pixelFmt.alphaBits << TestLog::EndMessage;
754         log << TestLog::Message << "EGL_DEPTH_SIZE = "          << depthBits << TestLog::EndMessage;
755         log << TestLog::Message << "EGL_STENCIL_SIZE = "        << stencilBits << TestLog::EndMessage;
756         log << TestLog::Message << "EGL_SAMPLES = "                     << numSamples << TestLog::EndMessage;
757
758         // Generate draw ops.
759         drawOps.resize(numContexts*drawsPerCtx*numIters);
760         for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp)
761                 randomizeDrawOp(rnd, *drawOp);
762
763         // Create and setup programs per context
764         for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
765         {
766                 EGLint          api                     = contexts[ctxNdx].first;
767                 EGLContext      context         = contexts[ctxNdx].second;
768
769                 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
770
771                 programs[ctxNdx] = ProgramSp(createProgram(m_gl, api));
772                 programs[ctxNdx]->setup();
773         }
774
775         // Clear to black using first context.
776         {
777                 EGLint          api                     = contexts[0].first;
778                 EGLContext      context         = contexts[0].second;
779
780                 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
781
782                 clear(m_gl, api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL);
783                 finish(m_gl, api);
784         }
785
786         // Render.
787         for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
788         {
789                 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
790                 {
791                         EGLint          api                     = contexts[ctxNdx].first;
792                         EGLContext      context         = contexts[ctxNdx].second;
793
794                         EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
795
796                         for (int drawNdx = 0; drawNdx < drawsPerCtx; drawNdx++)
797                         {
798                                 const DrawPrimitiveOp& drawOp = drawOps[iterNdx*numContexts*drawsPerCtx + ctxNdx*drawsPerCtx + drawNdx];
799                                 draw(m_gl, api, *programs[ctxNdx], drawOp);
800                         }
801
802                         finish(m_gl, api);
803                 }
804         }
805
806         // Read pixels using first context. \todo [pyry] Randomize?
807         {
808                 EGLint          api             = contexts[0].first;
809                 EGLContext      context = contexts[0].second;
810
811                 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
812
813                 readPixels(m_gl, api, frame);
814         }
815
816         EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
817
818         // Render reference.
819         // \note Reference image is always generated using single-sampling.
820         renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1);
821
822         // Compare images
823         {
824                 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
825
826                 if (!imagesOk)
827                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
828         }
829 }
830
831 // MultiThreadRenderCase
832
833 class MultiThreadRenderCase : public MultiContextRenderCase
834 {
835 public:
836                                                 MultiThreadRenderCase           (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi);
837
838         void                            init                                            (void);
839
840 private:
841         virtual void            executeForContexts                      (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts);
842
843         glw::Functions          m_gl;
844 };
845
846 class RenderTestThread;
847
848 typedef de::SharedPtr<RenderTestThread> RenderTestThreadSp;
849 typedef de::SharedPtr<de::Semaphore>    SemaphoreSp;
850
851 struct DrawOpPacket
852 {
853         DrawOpPacket (void)
854                 : drawOps       (DE_NULL)
855                 , numOps        (0)
856         {
857         }
858
859         const DrawPrimitiveOp*  drawOps;
860         int                                             numOps;
861         SemaphoreSp                             wait;
862         SemaphoreSp                             signal;
863 };
864
865 class RenderTestThread : public de::Thread
866 {
867 public:
868         RenderTestThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const glw::Functions& gl, const Program& program, const std::vector<DrawOpPacket>& packets)
869                 : m_egl         (egl)
870                 , m_display     (display)
871                 , m_surface     (surface)
872                 , m_context     (context)
873                 , m_api         (api)
874                 , m_gl          (gl)
875                 , m_program     (program)
876                 , m_packets     (packets)
877         {
878         }
879
880         void run (void)
881         {
882                 for (std::vector<DrawOpPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
883                 {
884                         // Wait until it is our turn.
885                         packetIter->wait->decrement();
886
887                         // Acquire context.
888                         EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, m_surface, m_surface, m_context));
889
890                         // Execute rendering.
891                         for (int ndx = 0; ndx < packetIter->numOps; ndx++)
892                                 draw(m_gl, m_api, m_program, packetIter->drawOps[ndx]);
893
894                         finish(m_gl, m_api);
895
896                         // Release context.
897                         EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
898
899                         // Signal completion.
900                         packetIter->signal->increment();
901                 }
902                 m_egl.releaseThread();
903         }
904
905 private:
906         const Library&                                          m_egl;
907         EGLDisplay                                                      m_display;
908         EGLSurface                                                      m_surface;
909         EGLContext                                                      m_context;
910         EGLint                                                          m_api;
911         const glw::Functions&                           m_gl;
912         const Program&                                          m_program;
913         const std::vector<DrawOpPacket>&        m_packets;
914 };
915
916 MultiThreadRenderCase::MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
917         : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
918 {
919 }
920
921 void MultiThreadRenderCase::init (void)
922 {
923         MultiContextRenderCase::init();
924         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
925 }
926
927 void MultiThreadRenderCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
928 {
929         const Library&                  egl                                     = m_eglTestCtx.getLibrary();
930         const int                               width                           = eglu::querySurfaceInt(egl, display, surface, EGL_WIDTH);
931         const int                               height                          = eglu::querySurfaceInt(egl, display, surface, EGL_HEIGHT);
932         const int                               numContexts                     = (int)contexts.size();
933         const int                               opsPerPacket            = 2;
934         const int                               packetsPerThread        = 2;
935         const int                               numThreads                      = numContexts;
936         const int                               numPackets                      = numThreads * packetsPerThread;
937         const tcu::PixelFormat  pixelFmt                        = getPixelFormat(egl, display, config.config);
938         const float                             threshold                       = getColorThreshold(pixelFmt);
939
940         const int                               depthBits                       = eglu::getConfigAttribInt(egl, display, config.config, EGL_DEPTH_SIZE);
941         const int                               stencilBits                     = eglu::getConfigAttribInt(egl, display, config.config, EGL_STENCIL_SIZE);
942         const int                               numSamples                      = eglu::getConfigAttribInt(egl, display, config.config, EGL_SAMPLES);
943
944         TestLog&                                log                                     = m_testCtx.getLog();
945
946         tcu::Surface                    refFrame                        (width, height);
947         tcu::Surface                    frame                           (width, height);
948
949         de::Random                              rnd                                     (deStringHash(getName()) ^ deInt32Hash(numContexts));
950
951         // Resources that need cleanup
952         vector<ProgramSp>                               programs        (numContexts);
953         vector<SemaphoreSp>                             semaphores      (numPackets+1);
954         vector<DrawPrimitiveOp>                 drawOps         (numPackets*opsPerPacket);
955         vector<vector<DrawOpPacket> >   packets         (numThreads);
956         vector<RenderTestThreadSp>              threads         (numThreads);
957
958         // Log basic information about config.
959         log << TestLog::Message << "EGL_RED_SIZE = "            << pixelFmt.redBits << TestLog::EndMessage;
960         log << TestLog::Message << "EGL_GREEN_SIZE = "          << pixelFmt.greenBits << TestLog::EndMessage;
961         log << TestLog::Message << "EGL_BLUE_SIZE = "           << pixelFmt.blueBits << TestLog::EndMessage;
962         log << TestLog::Message << "EGL_ALPHA_SIZE = "          << pixelFmt.alphaBits << TestLog::EndMessage;
963         log << TestLog::Message << "EGL_DEPTH_SIZE = "          << depthBits << TestLog::EndMessage;
964         log << TestLog::Message << "EGL_STENCIL_SIZE = "        << stencilBits << TestLog::EndMessage;
965         log << TestLog::Message << "EGL_SAMPLES = "                     << numSamples << TestLog::EndMessage;
966
967         // Initialize semaphores.
968         for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
969                 *sem = SemaphoreSp(new de::Semaphore(0));
970
971         // Create draw ops.
972         for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp)
973                 randomizeDrawOp(rnd, *drawOp);
974
975         // Create packets.
976         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
977         {
978                 packets[threadNdx].resize(packetsPerThread);
979
980                 for (int packetNdx = 0; packetNdx < packetsPerThread; packetNdx++)
981                 {
982                         DrawOpPacket& packet = packets[threadNdx][packetNdx];
983
984                         // Threads take turns with packets.
985                         packet.wait             = semaphores[packetNdx*numThreads + threadNdx];
986                         packet.signal   = semaphores[packetNdx*numThreads + threadNdx + 1];
987                         packet.numOps   = opsPerPacket;
988                         packet.drawOps  = &drawOps[(packetNdx*numThreads + threadNdx)*opsPerPacket];
989                 }
990         }
991
992         // Create and setup programs per context
993         for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
994         {
995                 EGLint          api                     = contexts[ctxNdx].first;
996                 EGLContext      context         = contexts[ctxNdx].second;
997
998                 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
999
1000                 programs[ctxNdx] = ProgramSp(createProgram(m_gl, api));
1001                 programs[ctxNdx]->setup();
1002
1003                 // Release context
1004                 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1005         }
1006
1007         // Clear to black using first context.
1008         {
1009                 EGLint          api                     = contexts[0].first;
1010                 EGLContext      context         = contexts[0].second;
1011
1012                 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
1013
1014                 clear(m_gl, api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL);
1015                 finish(m_gl, api);
1016
1017                 // Release context
1018                 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1019         }
1020
1021         // Create and launch threads (actual rendering starts once first semaphore is signaled).
1022         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
1023         {
1024                 threads[threadNdx] = RenderTestThreadSp(new RenderTestThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, m_gl, *programs[threadNdx], packets[threadNdx]));
1025                 threads[threadNdx]->start();
1026         }
1027
1028         // Signal start and wait until complete.
1029         semaphores.front()->increment();
1030         semaphores.back()->decrement();
1031
1032         // Read pixels using first context. \todo [pyry] Randomize?
1033         {
1034                 EGLint          api             = contexts[0].first;
1035                 EGLContext      context = contexts[0].second;
1036
1037                 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
1038
1039                 readPixels(m_gl, api, frame);
1040         }
1041
1042         EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1043
1044         // Join threads.
1045         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
1046                 threads[threadNdx]->join();
1047
1048         // Render reference.
1049         renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1);
1050
1051         // Compare images
1052         {
1053                 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
1054
1055                 if (!imagesOk)
1056                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1057         }
1058 }
1059
1060 RenderTests::RenderTests (EglTestContext& eglTestCtx)
1061         : TestCaseGroup(eglTestCtx, "render", "Basic rendering with different client APIs")
1062 {
1063 }
1064
1065 RenderTests::~RenderTests (void)
1066 {
1067 }
1068
1069 struct RenderGroupSpec
1070 {
1071         const char*                     name;
1072         const char*                     desc;
1073         EGLint                          apiBits;
1074         eglu::ConfigFilter      baseFilter;
1075         int                                     numContextsPerApi;
1076 };
1077
1078 template <deUint32 Bits>
1079 static bool renderable (const eglu::CandidateConfig& c)
1080 {
1081         return (c.renderableType() & Bits) == Bits;
1082 }
1083
1084 template <class RenderClass>
1085 static void createRenderGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group, const RenderGroupSpec* first, const RenderGroupSpec* last)
1086 {
1087         for (const RenderGroupSpec* groupIter = first; groupIter != last; groupIter++)
1088         {
1089                 tcu::TestCaseGroup* configGroup = new tcu::TestCaseGroup(eglTestCtx.getTestContext(), groupIter->name, groupIter->desc);
1090                 group->addChild(configGroup);
1091
1092                 vector<RenderFilterList>        filterLists;
1093                 eglu::FilterList                        baseFilters;
1094                 baseFilters << groupIter->baseFilter;
1095                 getDefaultRenderFilterLists(filterLists, baseFilters);
1096
1097                 for (vector<RenderFilterList>::const_iterator listIter = filterLists.begin(); listIter != filterLists.end(); listIter++)
1098                         configGroup->addChild(new RenderClass(eglTestCtx, listIter->getName(), "", groupIter->apiBits, listIter->getSurfaceTypeMask(), *listIter, groupIter->numContextsPerApi));
1099         }
1100 }
1101
1102 void RenderTests::init (void)
1103 {
1104         static const RenderGroupSpec singleContextCases[] =
1105         {
1106                 {
1107                         "gles2",
1108                         "Primitive rendering using GLES2",
1109                         EGL_OPENGL_ES2_BIT,
1110                         renderable<EGL_OPENGL_ES2_BIT>,
1111                         1
1112                 },
1113                 {
1114                         "gles3",
1115                         "Primitive rendering using GLES3",
1116                         EGL_OPENGL_ES3_BIT,
1117                         renderable<EGL_OPENGL_ES3_BIT>,
1118                         1
1119                 },
1120         };
1121
1122         static const RenderGroupSpec multiContextCases[] =
1123         {
1124                 {
1125                         "gles2",
1126                         "Primitive rendering using multiple GLES2 contexts to shared surface",
1127                         EGL_OPENGL_ES2_BIT,
1128                         renderable<EGL_OPENGL_ES2_BIT>,
1129                         3
1130                 },
1131                 {
1132                         "gles3",
1133                         "Primitive rendering using multiple GLES3 contexts to shared surface",
1134                         EGL_OPENGL_ES3_BIT,
1135                         renderable<EGL_OPENGL_ES3_BIT>,
1136                         3
1137                 },
1138                 {
1139                         "gles2_gles3",
1140                         "Primitive rendering using multiple APIs to shared surface",
1141                         EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT,
1142                         renderable<EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT>,
1143                         1
1144                 },
1145         };
1146
1147         tcu::TestCaseGroup* singleContextGroup = new tcu::TestCaseGroup(m_testCtx, "single_context", "Single-context rendering");
1148         addChild(singleContextGroup);
1149         createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, singleContextGroup, &singleContextCases[0], &singleContextCases[DE_LENGTH_OF_ARRAY(singleContextCases)]);
1150
1151         tcu::TestCaseGroup* multiContextGroup = new tcu::TestCaseGroup(m_testCtx, "multi_context", "Multi-context rendering with shared surface");
1152         addChild(multiContextGroup);
1153         createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, multiContextGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
1154
1155         tcu::TestCaseGroup* multiThreadGroup = new tcu::TestCaseGroup(m_testCtx, "multi_thread", "Multi-thread rendering with shared surface");
1156         addChild(multiThreadGroup);
1157         createRenderGroups<MultiThreadRenderCase>(m_eglTestCtx, multiThreadGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
1158 }
1159
1160 } // egl
1161 } // deqp