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,const int subpixelBits)419 void renderReference (const tcu::PixelBufferAccess& dst, const vector<DrawPrimitiveOp>& drawOps, const tcu::PixelFormat& colorBits, const int depthBits, const int stencilBits, const int numSamples, const int subpixelBits)
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())), subpixelBits);
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 int subpixelBits = 0;
823 m_gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
824
825 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
826
827 // Render reference.
828 // \note Reference image is always generated using single-sampling.
829 renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1, subpixelBits);
830
831 // Compare images
832 {
833 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
834
835 if (!imagesOk)
836 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
837 }
838 }
839
840 // MultiThreadRenderCase
841
842 class MultiThreadRenderCase : public MultiContextRenderCase
843 {
844 public:
845 MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi);
846
847 void init (void);
848
849 private:
850 virtual void executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts);
851
852 glw::Functions m_gl;
853 };
854
855 class RenderTestThread;
856
857 typedef de::SharedPtr<RenderTestThread> RenderTestThreadSp;
858 typedef de::SharedPtr<de::Semaphore> SemaphoreSp;
859
860 struct DrawOpPacket
861 {
DrawOpPacketdeqp::egl::DrawOpPacket862 DrawOpPacket (void)
863 : drawOps (DE_NULL)
864 , numOps (0)
865 {
866 }
867
868 const DrawPrimitiveOp* drawOps;
869 int numOps;
870 SemaphoreSp wait;
871 SemaphoreSp signal;
872 };
873
874 class RenderTestThread : public de::Thread
875 {
876 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)877 RenderTestThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const glw::Functions& gl, const Program& program, const std::vector<DrawOpPacket>& packets)
878 : m_egl (egl)
879 , m_display (display)
880 , m_surface (surface)
881 , m_context (context)
882 , m_api (api)
883 , m_gl (gl)
884 , m_program (program)
885 , m_packets (packets)
886 {
887 }
888
run(void)889 void run (void)
890 {
891 for (std::vector<DrawOpPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
892 {
893 // Wait until it is our turn.
894 packetIter->wait->decrement();
895
896 // Acquire context.
897 EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, m_surface, m_surface, m_context));
898
899 // Execute rendering.
900 for (int ndx = 0; ndx < packetIter->numOps; ndx++)
901 draw(m_gl, m_api, m_program, packetIter->drawOps[ndx]);
902
903 finish(m_gl, m_api);
904
905 // Release context.
906 EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
907
908 // Signal completion.
909 packetIter->signal->increment();
910 }
911 m_egl.releaseThread();
912 }
913
914 private:
915 const Library& m_egl;
916 EGLDisplay m_display;
917 EGLSurface m_surface;
918 EGLContext m_context;
919 EGLint m_api;
920 const glw::Functions& m_gl;
921 const Program& m_program;
922 const std::vector<DrawOpPacket>& m_packets;
923 };
924
MultiThreadRenderCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)925 MultiThreadRenderCase::MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
926 : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
927 {
928 }
929
init(void)930 void MultiThreadRenderCase::init (void)
931 {
932 MultiContextRenderCase::init();
933 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
934 }
935
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)936 void MultiThreadRenderCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
937 {
938 const Library& egl = m_eglTestCtx.getLibrary();
939 const int width = eglu::querySurfaceInt(egl, display, surface, EGL_WIDTH);
940 const int height = eglu::querySurfaceInt(egl, display, surface, EGL_HEIGHT);
941 const int numContexts = (int)contexts.size();
942 const int opsPerPacket = 2;
943 const int packetsPerThread = 2;
944 const int numThreads = numContexts;
945 const int numPackets = numThreads * packetsPerThread;
946 const tcu::PixelFormat pixelFmt = getPixelFormat(egl, display, config.config);
947 const float threshold = getColorThreshold(pixelFmt);
948
949 const int depthBits = eglu::getConfigAttribInt(egl, display, config.config, EGL_DEPTH_SIZE);
950 const int stencilBits = eglu::getConfigAttribInt(egl, display, config.config, EGL_STENCIL_SIZE);
951 const int numSamples = eglu::getConfigAttribInt(egl, display, config.config, EGL_SAMPLES);
952
953 TestLog& log = m_testCtx.getLog();
954
955 tcu::Surface refFrame (width, height);
956 tcu::Surface frame (width, height);
957
958 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(numContexts));
959
960 // Resources that need cleanup
961 vector<ProgramSp> programs (numContexts);
962 vector<SemaphoreSp> semaphores (numPackets+1);
963 vector<DrawPrimitiveOp> drawOps (numPackets*opsPerPacket);
964 vector<vector<DrawOpPacket> > packets (numThreads);
965 vector<RenderTestThreadSp> threads (numThreads);
966
967 // Log basic information about config.
968 log << TestLog::Message << "EGL_RED_SIZE = " << pixelFmt.redBits << TestLog::EndMessage;
969 log << TestLog::Message << "EGL_GREEN_SIZE = " << pixelFmt.greenBits << TestLog::EndMessage;
970 log << TestLog::Message << "EGL_BLUE_SIZE = " << pixelFmt.blueBits << TestLog::EndMessage;
971 log << TestLog::Message << "EGL_ALPHA_SIZE = " << pixelFmt.alphaBits << TestLog::EndMessage;
972 log << TestLog::Message << "EGL_DEPTH_SIZE = " << depthBits << TestLog::EndMessage;
973 log << TestLog::Message << "EGL_STENCIL_SIZE = " << stencilBits << TestLog::EndMessage;
974 log << TestLog::Message << "EGL_SAMPLES = " << numSamples << TestLog::EndMessage;
975
976 // Initialize semaphores.
977 for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
978 *sem = SemaphoreSp(new de::Semaphore(0));
979
980 // Create draw ops.
981 for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp)
982 randomizeDrawOp(rnd, *drawOp, (pixelFmt.alphaBits == 1));
983
984 // Create packets.
985 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
986 {
987 packets[threadNdx].resize(packetsPerThread);
988
989 for (int packetNdx = 0; packetNdx < packetsPerThread; packetNdx++)
990 {
991 DrawOpPacket& packet = packets[threadNdx][packetNdx];
992
993 // Threads take turns with packets.
994 packet.wait = semaphores[packetNdx*numThreads + threadNdx];
995 packet.signal = semaphores[packetNdx*numThreads + threadNdx + 1];
996 packet.numOps = opsPerPacket;
997 packet.drawOps = &drawOps[(packetNdx*numThreads + threadNdx)*opsPerPacket];
998 }
999 }
1000
1001 // Create and setup programs per context
1002 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
1003 {
1004 EGLint api = contexts[ctxNdx].first;
1005 EGLContext context = contexts[ctxNdx].second;
1006
1007 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
1008
1009 programs[ctxNdx] = ProgramSp(createProgram(m_gl, api));
1010 programs[ctxNdx]->setup();
1011
1012 // Release context
1013 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1014 }
1015
1016 // Clear to black using first context.
1017 {
1018 EGLint api = contexts[0].first;
1019 EGLContext context = contexts[0].second;
1020
1021 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
1022
1023 clear(m_gl, api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL);
1024 finish(m_gl, api);
1025
1026 // Release context
1027 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1028 }
1029
1030 // Create and launch threads (actual rendering starts once first semaphore is signaled).
1031 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
1032 {
1033 threads[threadNdx] = RenderTestThreadSp(new RenderTestThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, m_gl, *programs[threadNdx], packets[threadNdx]));
1034 threads[threadNdx]->start();
1035 }
1036
1037 // Signal start and wait until complete.
1038 semaphores.front()->increment();
1039 semaphores.back()->decrement();
1040
1041 // Read pixels using first context. \todo [pyry] Randomize?
1042 {
1043 EGLint api = contexts[0].first;
1044 EGLContext context = contexts[0].second;
1045
1046 EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
1047
1048 readPixels(m_gl, api, frame);
1049 }
1050
1051 int subpixelBits = 0;
1052 m_gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
1053
1054 EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1055
1056 // Join threads.
1057 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
1058 threads[threadNdx]->join();
1059
1060 // Render reference.
1061 renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1, subpixelBits);
1062
1063 // Compare images
1064 {
1065 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
1066
1067 if (!imagesOk)
1068 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1069 }
1070 }
1071
RenderTests(EglTestContext & eglTestCtx)1072 RenderTests::RenderTests (EglTestContext& eglTestCtx)
1073 : TestCaseGroup(eglTestCtx, "render", "Basic rendering with different client APIs")
1074 {
1075 }
1076
~RenderTests(void)1077 RenderTests::~RenderTests (void)
1078 {
1079 }
1080
1081 struct RenderGroupSpec
1082 {
1083 const char* name;
1084 const char* desc;
1085 EGLint apiBits;
1086 eglu::ConfigFilter baseFilter;
1087 int numContextsPerApi;
1088 };
1089
1090 template <deUint32 Bits>
renderable(const eglu::CandidateConfig & c)1091 static bool renderable (const eglu::CandidateConfig& c)
1092 {
1093 return (c.renderableType() & Bits) == Bits;
1094 }
1095
1096 template <class RenderClass>
createRenderGroups(EglTestContext & eglTestCtx,tcu::TestCaseGroup * group,const RenderGroupSpec * first,const RenderGroupSpec * last)1097 static void createRenderGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group, const RenderGroupSpec* first, const RenderGroupSpec* last)
1098 {
1099 for (const RenderGroupSpec* groupIter = first; groupIter != last; groupIter++)
1100 {
1101 tcu::TestCaseGroup* configGroup = new tcu::TestCaseGroup(eglTestCtx.getTestContext(), groupIter->name, groupIter->desc);
1102 group->addChild(configGroup);
1103
1104 vector<RenderFilterList> filterLists;
1105 eglu::FilterList baseFilters;
1106 baseFilters << groupIter->baseFilter;
1107 getDefaultRenderFilterLists(filterLists, baseFilters);
1108
1109 for (vector<RenderFilterList>::const_iterator listIter = filterLists.begin(); listIter != filterLists.end(); listIter++)
1110 configGroup->addChild(new RenderClass(eglTestCtx, listIter->getName(), "", groupIter->apiBits, listIter->getSurfaceTypeMask(), *listIter, groupIter->numContextsPerApi));
1111 }
1112 }
1113
init(void)1114 void RenderTests::init (void)
1115 {
1116 static const RenderGroupSpec singleContextCases[] =
1117 {
1118 {
1119 "gles2",
1120 "Primitive rendering using GLES2",
1121 EGL_OPENGL_ES2_BIT,
1122 renderable<EGL_OPENGL_ES2_BIT>,
1123 1
1124 },
1125 {
1126 "gles3",
1127 "Primitive rendering using GLES3",
1128 EGL_OPENGL_ES3_BIT,
1129 renderable<EGL_OPENGL_ES3_BIT>,
1130 1
1131 },
1132 };
1133
1134 static const RenderGroupSpec multiContextCases[] =
1135 {
1136 {
1137 "gles2",
1138 "Primitive rendering using multiple GLES2 contexts to shared surface",
1139 EGL_OPENGL_ES2_BIT,
1140 renderable<EGL_OPENGL_ES2_BIT>,
1141 3
1142 },
1143 {
1144 "gles3",
1145 "Primitive rendering using multiple GLES3 contexts to shared surface",
1146 EGL_OPENGL_ES3_BIT,
1147 renderable<EGL_OPENGL_ES3_BIT>,
1148 3
1149 },
1150 {
1151 "gles2_gles3",
1152 "Primitive rendering using multiple APIs to shared surface",
1153 EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT,
1154 renderable<EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT>,
1155 1
1156 },
1157 };
1158
1159 tcu::TestCaseGroup* singleContextGroup = new tcu::TestCaseGroup(m_testCtx, "single_context", "Single-context rendering");
1160 addChild(singleContextGroup);
1161 createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, singleContextGroup, &singleContextCases[0], &singleContextCases[DE_LENGTH_OF_ARRAY(singleContextCases)]);
1162
1163 tcu::TestCaseGroup* multiContextGroup = new tcu::TestCaseGroup(m_testCtx, "multi_context", "Multi-context rendering with shared surface");
1164 addChild(multiContextGroup);
1165 createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, multiContextGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
1166
1167 tcu::TestCaseGroup* multiThreadGroup = new tcu::TestCaseGroup(m_testCtx, "multi_thread", "Multi-thread rendering with shared surface");
1168 addChild(multiThreadGroup);
1169 createRenderGroups<MultiThreadRenderCase>(m_eglTestCtx, multiThreadGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
1170 }
1171
1172 } // egl
1173 } // deqp
1174