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,const bool alphaZeroOrOne)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
ReferenceShader()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
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const258 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
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const275 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
toReferenceRenderState(rr::RenderState & state,const DrawPrimitiveOp & drawOp)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
getColorFormat(const tcu::PixelFormat & colorBits)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
getColorThreshold(const tcu::PixelFormat & colorBits)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
getDepthFormat(const int depthBits)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
getStencilFormat(int stencilBits)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
renderReference(const tcu::PixelBufferAccess & dst,const vector<DrawPrimitiveOp> & drawOps,const tcu::PixelFormat & colorBits,const int depthBits,const int stencilBits,const int numSamples)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:
Program(void)491 Program (void) {}
~Program(void)492 virtual ~Program (void) {}
493
494 virtual void setup (void) const = DE_NULL;
495 };
496
497 typedef de::SharedPtr<Program> ProgramSp;
498
getProgramSourcesES2(void)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:
GLES2Program(const glw::Functions & gl)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
~GLES2Program(void)535 ~GLES2Program (void)
536 {
537 }
538
setup(void) const539 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
getPositionLoc(void) const547 int getPositionLoc (void) const { return m_positionLoc; }
getColorLoc(void) const548 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
clearGLES2(const glw::Functions & gl,const tcu::Vec4 & color,const float depth,const int stencil)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
drawGLES2(const glw::Functions & gl,const Program & program,const DrawPrimitiveOp & drawOp)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
readPixelsGLES2(const glw::Functions & gl,tcu::Surface & dst)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
createProgram(const glw::Functions & gl,EGLint api)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
draw(const glw::Functions & gl,EGLint api,const Program & program,const DrawPrimitiveOp & drawOp)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
clear(const glw::Functions & gl,EGLint api,const tcu::Vec4 & color,const float depth,const int stencil)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
readPixels(const glw::Functions & gl,EGLint api,tcu::Surface & dst)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
finish(const glw::Functions & gl,EGLint api)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
getPixelFormat(const Library & egl,EGLDisplay display,EGLConfig config)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
SingleThreadRenderCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)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
init(void)725 void SingleThreadRenderCase::init (void)
726 {
727 MultiContextRenderCase::init();
728 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
729 }
730
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)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 {
DrawOpPacketdeqp::egl::DrawOpPacket859 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:
RenderTestThread(const Library & egl,EGLDisplay display,EGLSurface surface,EGLContext context,EGLint api,const glw::Functions & gl,const Program & program,const std::vector<DrawOpPacket> & packets)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
run(void)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
MultiThreadRenderCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)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
init(void)927 void MultiThreadRenderCase::init (void)
928 {
929 MultiContextRenderCase::init();
930 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
931 }
932
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)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
RenderTests(EglTestContext & eglTestCtx)1066 RenderTests::RenderTests (EglTestContext& eglTestCtx)
1067 : TestCaseGroup(eglTestCtx, "render", "Basic rendering with different client APIs")
1068 {
1069 }
1070
~RenderTests(void)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>
renderable(const eglu::CandidateConfig & c)1085 static bool renderable (const eglu::CandidateConfig& c)
1086 {
1087 return (c.renderableType() & Bits) == Bits;
1088 }
1089
1090 template <class RenderClass>
createRenderGroups(EglTestContext & eglTestCtx,tcu::TestCaseGroup * group,const RenderGroupSpec * first,const RenderGroupSpec * last)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
init(void)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
1168