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
isANarrowScreenSpaceTriangle(const tcu::Vec4 & p0,const tcu::Vec4 & p1,const tcu::Vec4 & p2)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
randomizeDrawOp(de::Random & rnd,DrawPrimitiveOp & drawOp)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
ReferenceShader()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
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const252 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
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const269 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
toReferenceRenderState(rr::RenderState & state,const DrawPrimitiveOp & drawOp)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
getColorFormat(const tcu::PixelFormat & colorBits)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
getDepthFormat(const int depthBits)359 tcu::TextureFormat getDepthFormat (const int depthBits)
360 {
361 switch (depthBits)
362 {
363 case 0: return tcu::TextureFormat();
364 case 8: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8);
365 case 16: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
366 case 24: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT24);
367 case 32:
368 default: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT);
369 }
370 }
371
getStencilFormat(int stencilBits)372 tcu::TextureFormat getStencilFormat (int stencilBits)
373 {
374 switch (stencilBits)
375 {
376 case 0: return tcu::TextureFormat();
377 case 8:
378 default: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
379 }
380 }
381
renderReference(const tcu::PixelBufferAccess & dst,const vector<DrawPrimitiveOp> & drawOps,const tcu::PixelFormat & colorBits,const int depthBits,const int stencilBits,const int numSamples)382 void renderReference (const tcu::PixelBufferAccess& dst, const vector<DrawPrimitiveOp>& drawOps, const tcu::PixelFormat& colorBits, const int depthBits, const int stencilBits, const int numSamples)
383 {
384 const int width = dst.getWidth();
385 const int height = dst.getHeight();
386
387 tcu::TextureLevel colorBuffer;
388 tcu::TextureLevel depthBuffer;
389 tcu::TextureLevel stencilBuffer;
390
391 rr::Renderer referenceRenderer;
392 rr::VertexAttrib attributes[2];
393 const ReferenceShader shader;
394
395 attributes[0].type = rr::VERTEXATTRIBTYPE_FLOAT;
396 attributes[0].size = 4;
397 attributes[0].stride = 0;
398 attributes[0].instanceDivisor = 0;
399
400 attributes[1].type = rr::VERTEXATTRIBTYPE_FLOAT;
401 attributes[1].size = 4;
402 attributes[1].stride = 0;
403 attributes[1].instanceDivisor = 0;
404
405 // Initialize buffers.
406 colorBuffer.setStorage(getColorFormat(colorBits), numSamples, width, height);
407 rr::clearMultisampleColorBuffer(colorBuffer, CLEAR_COLOR, rr::WindowRectangle(0, 0, width, height));
408
409 if (depthBits > 0)
410 {
411 depthBuffer.setStorage(getDepthFormat(depthBits), numSamples, width, height);
412 rr::clearMultisampleDepthBuffer(depthBuffer, CLEAR_DEPTH, rr::WindowRectangle(0, 0, width, height));
413 }
414
415 if (stencilBits > 0)
416 {
417 stencilBuffer.setStorage(getStencilFormat(stencilBits), numSamples, width, height);
418 rr::clearMultisampleStencilBuffer(stencilBuffer, CLEAR_STENCIL, rr::WindowRectangle(0, 0, width, height));
419 }
420
421 const rr::RenderTarget renderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()),
422 rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer.getAccess()),
423 rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer.getAccess()));
424
425 for (vector<DrawPrimitiveOp>::const_iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); drawOp++)
426 {
427 // Translate state
428 rr::RenderState renderState((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess())));
429 toReferenceRenderState(renderState, *drawOp);
430
431 DE_ASSERT(drawOp->type == PRIMITIVETYPE_TRIANGLE);
432
433 attributes[0].pointer = &drawOp->positions[0];
434 attributes[1].pointer = &drawOp->colors[0];
435
436 referenceRenderer.draw(
437 rr::DrawCommand(
438 renderState,
439 renderTarget,
440 rr::Program(static_cast<const rr::VertexShader*>(&shader), static_cast<const rr::FragmentShader*>(&shader)),
441 2,
442 attributes,
443 rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, drawOp->count * 3, 0)));
444 }
445
446 rr::resolveMultisampleColorBuffer(dst, rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()));
447 }
448
449 // API rendering code
450
451 class Program
452 {
453 public:
Program(void)454 Program (void) {}
~Program(void)455 virtual ~Program (void) {}
456
457 virtual void setup (void) const = DE_NULL;
458 };
459
460 typedef de::SharedPtr<Program> ProgramSp;
461
getProgramSourcesES2(void)462 static glu::ProgramSources getProgramSourcesES2 (void)
463 {
464 static const char* s_vertexSrc =
465 "attribute highp vec4 a_position;\n"
466 "attribute mediump vec4 a_color;\n"
467 "varying mediump vec4 v_color;\n"
468 "void main (void)\n"
469 "{\n"
470 " gl_Position = a_position;\n"
471 " v_color = a_color;\n"
472 "}\n";
473
474 static const char* s_fragmentSrc =
475 "varying mediump vec4 v_color;\n"
476 "void main (void)\n"
477 "{\n"
478 " gl_FragColor = v_color;\n"
479 "}\n";
480
481 return glu::ProgramSources() << glu::VertexSource(s_vertexSrc) << glu::FragmentSource(s_fragmentSrc);
482 }
483
484 class GLES2Program : public Program
485 {
486 public:
GLES2Program(const glw::Functions & gl)487 GLES2Program (const glw::Functions& gl)
488 : m_gl (gl)
489 , m_program (gl, getProgramSourcesES2())
490 , m_positionLoc (0)
491 , m_colorLoc (0)
492 {
493
494 m_positionLoc = m_gl.getAttribLocation(m_program.getProgram(), "a_position");
495 m_colorLoc = m_gl.getAttribLocation(m_program.getProgram(), "a_color");
496 }
497
~GLES2Program(void)498 ~GLES2Program (void)
499 {
500 }
501
setup(void) const502 void setup (void) const
503 {
504 m_gl.useProgram(m_program.getProgram());
505 m_gl.enableVertexAttribArray(m_positionLoc);
506 m_gl.enableVertexAttribArray(m_colorLoc);
507 GLU_CHECK_GLW_MSG(m_gl, "Program setup failed");
508 }
509
getPositionLoc(void) const510 int getPositionLoc (void) const { return m_positionLoc; }
getColorLoc(void) const511 int getColorLoc (void) const { return m_colorLoc; }
512
513 private:
514 const glw::Functions& m_gl;
515 glu::ShaderProgram m_program;
516 int m_positionLoc;
517 int m_colorLoc;
518 };
519
clearGLES2(const glw::Functions & gl,const tcu::Vec4 & color,const float depth,const int stencil)520 void clearGLES2 (const glw::Functions& gl, const tcu::Vec4& color, const float depth, const int stencil)
521 {
522 gl.clearColor(color.x(), color.y(), color.z(), color.w());
523 gl.clearDepthf(depth);
524 gl.clearStencil(stencil);
525 gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
526 }
527
drawGLES2(const glw::Functions & gl,const Program & program,const DrawPrimitiveOp & drawOp)528 void drawGLES2 (const glw::Functions& gl, const Program& program, const DrawPrimitiveOp& drawOp)
529 {
530 const GLES2Program& gles2Program = dynamic_cast<const GLES2Program&>(program);
531
532 switch (drawOp.blend)
533 {
534 case BLENDMODE_NONE:
535 gl.disable(GL_BLEND);
536 break;
537
538 case BLENDMODE_ADDITIVE:
539 gl.enable(GL_BLEND);
540 gl.blendFunc(GL_ONE, GL_ONE);
541 break;
542
543 case BLENDMODE_SRC_OVER:
544 gl.enable(GL_BLEND);
545 gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
546 break;
547
548 default:
549 DE_ASSERT(false);
550 }
551
552 switch (drawOp.depth)
553 {
554 case DEPTHMODE_NONE:
555 gl.disable(GL_DEPTH_TEST);
556 break;
557
558 case DEPTHMODE_LESS:
559 gl.enable(GL_DEPTH_TEST);
560 break;
561
562 default:
563 DE_ASSERT(false);
564 }
565
566 switch (drawOp.stencil)
567 {
568 case STENCILMODE_NONE:
569 gl.disable(GL_STENCIL_TEST);
570 break;
571
572 case STENCILMODE_LEQUAL_INC:
573 gl.enable(GL_STENCIL_TEST);
574 gl.stencilFunc(GL_LEQUAL, drawOp.stencilRef, ~0u);
575 gl.stencilOp(GL_KEEP, GL_INCR, GL_INCR);
576 break;
577
578 default:
579 DE_ASSERT(false);
580 }
581
582 gl.disable(GL_DITHER);
583
584 gl.vertexAttribPointer(gles2Program.getPositionLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.positions[0]);
585 gl.vertexAttribPointer(gles2Program.getColorLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.colors[0]);
586
587 DE_ASSERT(drawOp.type == PRIMITIVETYPE_TRIANGLE);
588 gl.drawArrays(GL_TRIANGLES, 0, drawOp.count*3);
589 }
590
readPixelsGLES2(const glw::Functions & gl,tcu::Surface & dst)591 static void readPixelsGLES2 (const glw::Functions& gl, tcu::Surface& dst)
592 {
593 gl.readPixels(0, 0, dst.getWidth(), dst.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, dst.getAccess().getDataPtr());
594 }
595
createProgram(const glw::Functions & gl,EGLint api)596 Program* createProgram (const glw::Functions& gl, EGLint api)
597 {
598 switch (api)
599 {
600 case EGL_OPENGL_ES2_BIT: return new GLES2Program(gl);
601 case EGL_OPENGL_ES3_BIT_KHR: return new GLES2Program(gl);
602 default:
603 throw tcu::NotSupportedError("Unsupported API");
604 }
605 }
606
draw(const glw::Functions & gl,EGLint api,const Program & program,const DrawPrimitiveOp & drawOp)607 void draw (const glw::Functions& gl, EGLint api, const Program& program, const DrawPrimitiveOp& drawOp)
608 {
609 switch (api)
610 {
611 case EGL_OPENGL_ES2_BIT: drawGLES2(gl, program, drawOp); break;
612 case EGL_OPENGL_ES3_BIT_KHR: drawGLES2(gl, program, drawOp); break;
613 default:
614 throw tcu::NotSupportedError("Unsupported API");
615 }
616 }
617
clear(const glw::Functions & gl,EGLint api,const tcu::Vec4 & color,const float depth,const int stencil)618 void clear (const glw::Functions& gl, EGLint api, const tcu::Vec4& color, const float depth, const int stencil)
619 {
620 switch (api)
621 {
622 case EGL_OPENGL_ES2_BIT: clearGLES2(gl, color, depth, stencil); break;
623 case EGL_OPENGL_ES3_BIT_KHR: clearGLES2(gl, color, depth, stencil); break;
624 default:
625 throw tcu::NotSupportedError("Unsupported API");
626 }
627 }
628
readPixels(const glw::Functions & gl,EGLint api,tcu::Surface & dst)629 static void readPixels (const glw::Functions& gl, EGLint api, tcu::Surface& dst)
630 {
631 switch (api)
632 {
633 case EGL_OPENGL_ES2_BIT: readPixelsGLES2(gl, dst); break;
634 case EGL_OPENGL_ES3_BIT_KHR: readPixelsGLES2(gl, dst); break;
635 default:
636 throw tcu::NotSupportedError("Unsupported API");
637 }
638 }
639
finish(const glw::Functions & gl,EGLint api)640 static void finish (const glw::Functions& gl, EGLint api)
641 {
642 switch (api)
643 {
644 case EGL_OPENGL_ES2_BIT:
645 case EGL_OPENGL_ES3_BIT_KHR:
646 gl.finish();
647 break;
648
649 default:
650 throw tcu::NotSupportedError("Unsupported API");
651 }
652 }
653
getPixelFormat(const Library & egl,EGLDisplay display,EGLConfig config)654 tcu::PixelFormat getPixelFormat (const Library& egl, EGLDisplay display, EGLConfig config)
655 {
656 tcu::PixelFormat fmt;
657 fmt.redBits = eglu::getConfigAttribInt(egl, display, config, EGL_RED_SIZE);
658 fmt.greenBits = eglu::getConfigAttribInt(egl, display, config, EGL_GREEN_SIZE);
659 fmt.blueBits = eglu::getConfigAttribInt(egl, display, config, EGL_BLUE_SIZE);
660 fmt.alphaBits = eglu::getConfigAttribInt(egl, display, config, EGL_ALPHA_SIZE);
661 return fmt;
662 }
663
664 } // anonymous
665
666 // SingleThreadRenderCase
667
668 class SingleThreadRenderCase : public MultiContextRenderCase
669 {
670 public:
671 SingleThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi);
672
673 void init (void);
674
675 private:
676 virtual void executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts);
677
678 glw::Functions m_gl;
679 };
680
681 // SingleThreadColorClearCase
682
SingleThreadRenderCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)683 SingleThreadRenderCase::SingleThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
684 : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
685 {
686 }
687
init(void)688 void SingleThreadRenderCase::init (void)
689 {
690 MultiContextRenderCase::init();
691 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
692 }
693
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)694 void SingleThreadRenderCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
695 {
696 const Library& egl = m_eglTestCtx.getLibrary();
697 const int width = eglu::querySurfaceInt(egl, display, surface, EGL_WIDTH);
698 const int height = eglu::querySurfaceInt(egl, display, surface, EGL_HEIGHT);
699 const int numContexts = (int)contexts.size();
700 const int drawsPerCtx = 2;
701 const int numIters = 2;
702 const float threshold = 0.02f;
703
704 const tcu::PixelFormat pixelFmt = getPixelFormat(egl, display, config.config);
705 const int depthBits = eglu::getConfigAttribInt(egl, display, config.config, EGL_DEPTH_SIZE);
706 const int stencilBits = eglu::getConfigAttribInt(egl, display, config.config, EGL_STENCIL_SIZE);
707 const int numSamples = eglu::getConfigAttribInt(egl, display, config.config, EGL_SAMPLES);
708
709 TestLog& log = m_testCtx.getLog();
710
711 tcu::Surface refFrame (width, height);
712 tcu::Surface frame (width, height);
713
714 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(numContexts));
715 vector<ProgramSp> programs (contexts.size());
716 vector<DrawPrimitiveOp> drawOps;
717
718 // Log basic information about config.
719 log << TestLog::Message << "EGL_RED_SIZE = " << pixelFmt.redBits << TestLog::EndMessage;
720 log << TestLog::Message << "EGL_GREEN_SIZE = " << pixelFmt.greenBits << TestLog::EndMessage;
721 log << TestLog::Message << "EGL_BLUE_SIZE = " << pixelFmt.blueBits << TestLog::EndMessage;
722 log << TestLog::Message << "EGL_ALPHA_SIZE = " << pixelFmt.alphaBits << TestLog::EndMessage;
723 log << TestLog::Message << "EGL_DEPTH_SIZE = " << depthBits << TestLog::EndMessage;
724 log << TestLog::Message << "EGL_STENCIL_SIZE = " << stencilBits << TestLog::EndMessage;
725 log << TestLog::Message << "EGL_SAMPLES = " << numSamples << TestLog::EndMessage;
726
727 // Generate draw ops.
728 drawOps.resize(numContexts*drawsPerCtx*numIters);
729 for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp)
730 randomizeDrawOp(rnd, *drawOp);
731
732 // Create and setup programs per context
733 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
734 {
735 EGLint api = contexts[ctxNdx].first;
736 EGLContext context = contexts[ctxNdx].second;
737
738 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
739
740 programs[ctxNdx] = ProgramSp(createProgram(m_gl, api));
741 programs[ctxNdx]->setup();
742 }
743
744 // Clear to black using first context.
745 {
746 EGLint api = contexts[0].first;
747 EGLContext context = contexts[0].second;
748
749 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
750
751 clear(m_gl, api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL);
752 finish(m_gl, api);
753 }
754
755 // Render.
756 for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
757 {
758 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
759 {
760 EGLint api = contexts[ctxNdx].first;
761 EGLContext context = contexts[ctxNdx].second;
762
763 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
764
765 for (int drawNdx = 0; drawNdx < drawsPerCtx; drawNdx++)
766 {
767 const DrawPrimitiveOp& drawOp = drawOps[iterNdx*numContexts*drawsPerCtx + ctxNdx*drawsPerCtx + drawNdx];
768 draw(m_gl, api, *programs[ctxNdx], drawOp);
769 }
770
771 finish(m_gl, api);
772 }
773 }
774
775 // Read pixels using first context. \todo [pyry] Randomize?
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 readPixels(m_gl, api, frame);
783 }
784
785 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
786
787 // Render reference.
788 // \note Reference image is always generated using single-sampling.
789 renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1);
790
791 // Compare images
792 {
793 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
794
795 if (!imagesOk)
796 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
797 }
798 }
799
800 // MultiThreadRenderCase
801
802 class MultiThreadRenderCase : public MultiContextRenderCase
803 {
804 public:
805 MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi);
806
807 void init (void);
808
809 private:
810 virtual void executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts);
811
812 glw::Functions m_gl;
813 };
814
815 class RenderTestThread;
816
817 typedef de::SharedPtr<RenderTestThread> RenderTestThreadSp;
818 typedef de::SharedPtr<de::Semaphore> SemaphoreSp;
819
820 struct DrawOpPacket
821 {
DrawOpPacketdeqp::egl::DrawOpPacket822 DrawOpPacket (void)
823 : drawOps (DE_NULL)
824 , numOps (0)
825 {
826 }
827
828 const DrawPrimitiveOp* drawOps;
829 int numOps;
830 SemaphoreSp wait;
831 SemaphoreSp signal;
832 };
833
834 class RenderTestThread : public de::Thread
835 {
836 public:
RenderTestThread(const Library & egl,EGLDisplay display,EGLSurface surface,EGLContext context,EGLint api,const glw::Functions & gl,const Program & program,const std::vector<DrawOpPacket> & packets)837 RenderTestThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const glw::Functions& gl, const Program& program, const std::vector<DrawOpPacket>& packets)
838 : m_egl (egl)
839 , m_display (display)
840 , m_surface (surface)
841 , m_context (context)
842 , m_api (api)
843 , m_gl (gl)
844 , m_program (program)
845 , m_packets (packets)
846 {
847 }
848
run(void)849 void run (void)
850 {
851 for (std::vector<DrawOpPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
852 {
853 // Wait until it is our turn.
854 packetIter->wait->decrement();
855
856 // Acquire context.
857 EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, m_surface, m_surface, m_context));
858
859 // Execute rendering.
860 for (int ndx = 0; ndx < packetIter->numOps; ndx++)
861 draw(m_gl, m_api, m_program, packetIter->drawOps[ndx]);
862
863 finish(m_gl, m_api);
864
865 // Release context.
866 EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
867
868 // Signal completion.
869 packetIter->signal->increment();
870 }
871 }
872
873 private:
874 const Library& m_egl;
875 EGLDisplay m_display;
876 EGLSurface m_surface;
877 EGLContext m_context;
878 EGLint m_api;
879 const glw::Functions& m_gl;
880 const Program& m_program;
881 const std::vector<DrawOpPacket>& m_packets;
882 };
883
MultiThreadRenderCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)884 MultiThreadRenderCase::MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
885 : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
886 {
887 }
888
init(void)889 void MultiThreadRenderCase::init (void)
890 {
891 MultiContextRenderCase::init();
892 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
893 }
894
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)895 void MultiThreadRenderCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
896 {
897 const Library& egl = m_eglTestCtx.getLibrary();
898 const int width = eglu::querySurfaceInt(egl, display, surface, EGL_WIDTH);
899 const int height = eglu::querySurfaceInt(egl, display, surface, EGL_HEIGHT);
900 const int numContexts = (int)contexts.size();
901 const int opsPerPacket = 2;
902 const int packetsPerThread = 2;
903 const int numThreads = numContexts;
904 const int numPackets = numThreads * packetsPerThread;
905 const float threshold = 0.02f;
906
907 const tcu::PixelFormat pixelFmt = getPixelFormat(egl, display, config.config);
908 const int depthBits = eglu::getConfigAttribInt(egl, display, config.config, EGL_DEPTH_SIZE);
909 const int stencilBits = eglu::getConfigAttribInt(egl, display, config.config, EGL_STENCIL_SIZE);
910 const int numSamples = eglu::getConfigAttribInt(egl, display, config.config, EGL_SAMPLES);
911
912 TestLog& log = m_testCtx.getLog();
913
914 tcu::Surface refFrame (width, height);
915 tcu::Surface frame (width, height);
916
917 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(numContexts));
918
919 // Resources that need cleanup
920 vector<ProgramSp> programs (numContexts);
921 vector<SemaphoreSp> semaphores (numPackets+1);
922 vector<DrawPrimitiveOp> drawOps (numPackets*opsPerPacket);
923 vector<vector<DrawOpPacket> > packets (numThreads);
924 vector<RenderTestThreadSp> threads (numThreads);
925
926 // Log basic information about config.
927 log << TestLog::Message << "EGL_RED_SIZE = " << pixelFmt.redBits << TestLog::EndMessage;
928 log << TestLog::Message << "EGL_GREEN_SIZE = " << pixelFmt.greenBits << TestLog::EndMessage;
929 log << TestLog::Message << "EGL_BLUE_SIZE = " << pixelFmt.blueBits << TestLog::EndMessage;
930 log << TestLog::Message << "EGL_ALPHA_SIZE = " << pixelFmt.alphaBits << TestLog::EndMessage;
931 log << TestLog::Message << "EGL_DEPTH_SIZE = " << depthBits << TestLog::EndMessage;
932 log << TestLog::Message << "EGL_STENCIL_SIZE = " << stencilBits << TestLog::EndMessage;
933 log << TestLog::Message << "EGL_SAMPLES = " << numSamples << TestLog::EndMessage;
934
935 // Initialize semaphores.
936 for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
937 *sem = SemaphoreSp(new de::Semaphore(0));
938
939 // Create draw ops.
940 for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp)
941 randomizeDrawOp(rnd, *drawOp);
942
943 // Create packets.
944 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
945 {
946 packets[threadNdx].resize(packetsPerThread);
947
948 for (int packetNdx = 0; packetNdx < packetsPerThread; packetNdx++)
949 {
950 DrawOpPacket& packet = packets[threadNdx][packetNdx];
951
952 // Threads take turns with packets.
953 packet.wait = semaphores[packetNdx*numThreads + threadNdx];
954 packet.signal = semaphores[packetNdx*numThreads + threadNdx + 1];
955 packet.numOps = opsPerPacket;
956 packet.drawOps = &drawOps[(packetNdx*numThreads + threadNdx)*opsPerPacket];
957 }
958 }
959
960 // Create and setup programs per context
961 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
962 {
963 EGLint api = contexts[ctxNdx].first;
964 EGLContext context = contexts[ctxNdx].second;
965
966 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
967
968 programs[ctxNdx] = ProgramSp(createProgram(m_gl, api));
969 programs[ctxNdx]->setup();
970
971 // Release context
972 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
973 }
974
975 // Clear to black using first context.
976 {
977 EGLint api = contexts[0].first;
978 EGLContext context = contexts[0].second;
979
980 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
981
982 clear(m_gl, api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL);
983 finish(m_gl, api);
984
985 // Release context
986 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
987 }
988
989 // Create and launch threads (actual rendering starts once first semaphore is signaled).
990 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
991 {
992 threads[threadNdx] = RenderTestThreadSp(new RenderTestThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, m_gl, *programs[threadNdx], packets[threadNdx]));
993 threads[threadNdx]->start();
994 }
995
996 // Signal start and wait until complete.
997 semaphores.front()->increment();
998 semaphores.back()->decrement();
999
1000 // Read pixels using first context. \todo [pyry] Randomize?
1001 {
1002 EGLint api = contexts[0].first;
1003 EGLContext context = contexts[0].second;
1004
1005 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
1006
1007 readPixels(m_gl, api, frame);
1008 }
1009
1010 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1011
1012 // Join threads.
1013 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
1014 threads[threadNdx]->join();
1015
1016 // Render reference.
1017 renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1);
1018
1019 // Compare images
1020 {
1021 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
1022
1023 if (!imagesOk)
1024 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1025 }
1026 }
1027
RenderTests(EglTestContext & eglTestCtx)1028 RenderTests::RenderTests (EglTestContext& eglTestCtx)
1029 : TestCaseGroup(eglTestCtx, "render", "Basic rendering with different client APIs")
1030 {
1031 }
1032
~RenderTests(void)1033 RenderTests::~RenderTests (void)
1034 {
1035 }
1036
1037 struct RenderGroupSpec
1038 {
1039 const char* name;
1040 const char* desc;
1041 EGLint apiBits;
1042 eglu::ConfigFilter baseFilter;
1043 int numContextsPerApi;
1044 };
1045
1046 template <deUint32 Bits>
renderable(const eglu::CandidateConfig & c)1047 static bool renderable (const eglu::CandidateConfig& c)
1048 {
1049 return (c.renderableType() & Bits) == Bits;
1050 }
1051
1052 template <class RenderClass>
createRenderGroups(EglTestContext & eglTestCtx,tcu::TestCaseGroup * group,const RenderGroupSpec * first,const RenderGroupSpec * last)1053 static void createRenderGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group, const RenderGroupSpec* first, const RenderGroupSpec* last)
1054 {
1055 for (const RenderGroupSpec* groupIter = first; groupIter != last; groupIter++)
1056 {
1057 tcu::TestCaseGroup* configGroup = new tcu::TestCaseGroup(eglTestCtx.getTestContext(), groupIter->name, groupIter->desc);
1058 group->addChild(configGroup);
1059
1060 vector<RenderFilterList> filterLists;
1061 eglu::FilterList baseFilters;
1062 baseFilters << groupIter->baseFilter;
1063 getDefaultRenderFilterLists(filterLists, baseFilters);
1064
1065 for (vector<RenderFilterList>::const_iterator listIter = filterLists.begin(); listIter != filterLists.end(); listIter++)
1066 configGroup->addChild(new RenderClass(eglTestCtx, listIter->getName(), "", groupIter->apiBits, listIter->getSurfaceTypeMask(), *listIter, groupIter->numContextsPerApi));
1067 }
1068 }
1069
init(void)1070 void RenderTests::init (void)
1071 {
1072 static const RenderGroupSpec singleContextCases[] =
1073 {
1074 {
1075 "gles2",
1076 "Primitive rendering using GLES2",
1077 EGL_OPENGL_ES2_BIT,
1078 renderable<EGL_OPENGL_ES2_BIT>,
1079 1
1080 },
1081 {
1082 "gles3",
1083 "Primitive rendering using GLES3",
1084 EGL_OPENGL_ES3_BIT,
1085 renderable<EGL_OPENGL_ES3_BIT>,
1086 1
1087 },
1088 };
1089
1090 static const RenderGroupSpec multiContextCases[] =
1091 {
1092 {
1093 "gles2",
1094 "Primitive rendering using multiple GLES2 contexts to shared surface",
1095 EGL_OPENGL_ES2_BIT,
1096 renderable<EGL_OPENGL_ES2_BIT>,
1097 3
1098 },
1099 {
1100 "gles3",
1101 "Primitive rendering using multiple GLES3 contexts to shared surface",
1102 EGL_OPENGL_ES3_BIT,
1103 renderable<EGL_OPENGL_ES3_BIT>,
1104 3
1105 },
1106 {
1107 "gles2_gles3",
1108 "Primitive rendering using multiple APIs to shared surface",
1109 EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT,
1110 renderable<EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT>,
1111 1
1112 },
1113 };
1114
1115 tcu::TestCaseGroup* singleContextGroup = new tcu::TestCaseGroup(m_testCtx, "single_context", "Single-context rendering");
1116 addChild(singleContextGroup);
1117 createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, singleContextGroup, &singleContextCases[0], &singleContextCases[DE_LENGTH_OF_ARRAY(singleContextCases)]);
1118
1119 tcu::TestCaseGroup* multiContextGroup = new tcu::TestCaseGroup(m_testCtx, "multi_context", "Multi-context rendering with shared surface");
1120 addChild(multiContextGroup);
1121 createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, multiContextGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
1122
1123 tcu::TestCaseGroup* multiThreadGroup = new tcu::TestCaseGroup(m_testCtx, "multi_thread", "Multi-thread rendering with shared surface");
1124 addChild(multiThreadGroup);
1125 createRenderGroups<MultiThreadRenderCase>(m_eglTestCtx, multiThreadGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
1126 }
1127
1128 } // egl
1129 } // deqp
1130