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