am a7b6dc7a: am 342b03b5: (-s ours) am ca04416b: am 33c9e110: am cee84aa0: am 652dd63...
[platform/upstream/VK-GL-CTS.git] / modules / egl / teglBufferAgeTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program EGL Module
3  * ---------------------------------------
4  *
5  * Copyright 2015 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 Test EXT_buffer_age
22  *//*--------------------------------------------------------------------*/
23
24 #include "teglBufferAgeTests.hpp"
25
26 #include "tcuImageCompare.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuTextureUtil.hpp"
30
31 #include "egluNativeWindow.hpp"
32 #include "egluUtil.hpp"
33 #include "egluConfigFilter.hpp"
34
35 #include "eglwLibrary.hpp"
36 #include "eglwEnums.hpp"
37
38 #include "gluDefs.hpp"
39 #include "gluRenderContext.hpp"
40 #include "gluShaderProgram.hpp"
41
42 #include "glwDefs.hpp"
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
45
46 #include "deRandom.hpp"
47 #include "deString.h"
48
49 #include <string>
50 #include <vector>
51 #include <sstream>
52
53 using std::string;
54 using std::vector;
55 using glw::GLubyte;
56 using tcu::IVec2;
57
58 using namespace eglw;
59
60 namespace deqp
61 {
62 namespace egl
63 {
64 namespace
65 {
66
67 typedef tcu::Vector<GLubyte, 3> Color;
68
69 class GLES2Renderer;
70
71 class ReferenceRenderer;
72
73 class BufferAgeTest : public TestCase
74 {
75 public:
76         enum DrawType
77         {
78                 DRAWTYPE_GLES2_CLEAR,
79                 DRAWTYPE_GLES2_RENDER
80         };
81
82                                                                 BufferAgeTest   (EglTestContext& eglTestCtx, bool preserveColorBuffer, const vector<DrawType>& oddFrameDrawType,
83                                                                                                  const vector<DrawType>& evenFrameDrawType, const char* name, const char* description);
84                                                                 ~BufferAgeTest  (void);
85
86         void                                            init                    (void);
87         void                                            deinit                  (void);
88         IterateResult                           iterate                 (void);
89
90 private:
91         void                                            initEGLSurface (EGLConfig config);
92         void                                            initEGLContext (EGLConfig config);
93
94         const int                                       m_seed;
95         const bool                                      m_preserveColorBuffer;
96         const vector<DrawType>          m_oddFrameDrawType;
97         const vector<DrawType>          m_evenFrameDrawType;
98
99         EGLDisplay                                      m_eglDisplay;
100         eglu::NativeWindow*                     m_window;
101         EGLSurface                                      m_eglSurface;
102         EGLConfig                                       m_eglConfig;
103         EGLContext                                      m_eglContext;
104         glw::Functions                          m_gl;
105
106         GLES2Renderer*                          m_gles2Renderer;
107         ReferenceRenderer*                      m_refRenderer;
108
109 };
110
111 struct ColoredRect
112 {
113 public:
114                                                         ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
115         IVec2                                   bottomLeft;
116         IVec2                                   topRight;
117         Color                                   color;
118 };
119
120 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
121         : bottomLeft(bottomLeft_)
122         , topRight      (topRight_)
123         , color         (color_)
124 {
125 }
126
127 struct DrawCommand
128 {
129                                                         DrawCommand (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_);
130         BufferAgeTest::DrawType drawType;
131         ColoredRect                             rect;
132 };
133
134 DrawCommand::DrawCommand (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_)
135         : drawType(drawType_)
136         , rect    (rect_)
137 {
138 }
139
140 struct Frame
141 {
142                                                 Frame (int width_, int height_);
143         int                             width;
144         int                                     height;
145         vector<DrawCommand> draws;
146 };
147
148 Frame::Frame (int width_, int height_)
149         : width(width_)
150         , height(height_)
151 {
152 }
153
154
155 // (x1,y1) lie in the lower-left quadrant while (x2,y2) lie in the upper-right.
156 // the coords are multiplied by 4 to amplify the minimial difference between coords to 4 (if not zero)
157 // to avoid the situation where two edges are too close to each other which makes the rounding error
158 // intoleratable by compareToReference()
159 void generateRandomFrame (Frame* dst, const vector<BufferAgeTest::DrawType>& drawTypes, de::Random& rnd)
160 {
161         for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
162         {
163                 const int                       x1                      = rnd.getInt(0, (dst->width-1)/8) * 4;
164                 const int                       y1                      = rnd.getInt(0, (dst->height-1)/8) * 4;
165                 const int                       x2                      = rnd.getInt((dst->width-1)/8, (dst->width-1)/4) * 4;
166                 const int                       y2                      = rnd.getInt((dst->height-1)/8, (dst->height-1)/4) * 4;
167                 const GLubyte           r                       = rnd.getUint8();
168                 const GLubyte           g                       = rnd.getUint8();
169                 const GLubyte           b                       = rnd.getUint8();
170                 const ColoredRect       coloredRect     (IVec2(x1, y1), IVec2(x2, y2), Color(r, g, b));
171                 const DrawCommand       drawCommand (drawTypes[ndx], coloredRect);
172                 (*dst).draws.push_back(drawCommand);
173         }
174 }
175
176 typedef vector<Frame> FrameSequence;
177
178 //helper function declaration
179 EGLConfig               getEGLConfig                                    (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer);
180 void                    clearColorScreen                                (const glw::Functions& gl, const tcu::Vec4& clearColor);
181 void                    clearColorReference                             (tcu::Surface* ref, const tcu::Vec4& clearColor);
182 void                    readPixels                                              (const glw::Functions& gl, tcu::Surface* screen);
183 float                   windowToDeviceCoordinates               (int x, int length);
184 bool                    compareToReference                              (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum);
185 vector<int>     getFramesOnBuffer                               (const vector<int>& bufferAges, int frameNdx);
186
187 class GLES2Renderer
188 {
189 public:
190                                                         GLES2Renderer           (const glw::Functions& gl);
191                                                         ~GLES2Renderer          (void);
192         void                                    render                          (int width, int height, const Frame& frame) const;
193
194 private:
195                                                         GLES2Renderer           (const GLES2Renderer&);
196         GLES2Renderer&                  operator=                       (const GLES2Renderer&);
197
198         const glw::Functions&   m_gl;
199         glu::ShaderProgram              m_glProgram;
200         glw::GLuint                             m_coordLoc;
201         glw::GLuint                             m_colorLoc;
202 };
203
204 // generate sources for vertex and fragment buffer
205 glu::ProgramSources getSources (void)
206 {
207         const char* const vertexShaderSource =
208                 "attribute mediump vec4 a_pos;\n"
209                 "attribute mediump vec4 a_color;\n"
210                 "varying mediump vec4 v_color;\n"
211                 "void main(void)\n"
212                 "{\n"
213                 "\tv_color = a_color;\n"
214                 "\tgl_Position = a_pos;\n"
215                 "}";
216
217         const char* const fragmentShaderSource =
218                 "varying mediump vec4 v_color;\n"
219                 "void main(void)\n"
220                 "{\n"
221                 "\tgl_FragColor = v_color;\n"
222                 "}";
223
224         return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
225 }
226
227 GLES2Renderer::GLES2Renderer (const glw::Functions& gl)
228         : m_gl            (gl)
229         , m_glProgram (gl, getSources())
230         , m_coordLoc  ((glw::GLuint)-1)
231         , m_colorLoc  ((glw::GLuint)-1)
232 {
233         m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color");
234         m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos");
235         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
236 }
237
238 GLES2Renderer::~GLES2Renderer (void)
239 {
240 }
241
242 void GLES2Renderer::render (int width, int height, const Frame& frame) const
243 {
244         for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
245         {
246                 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
247                 if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
248                 {
249                         float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width);
250                         float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height);
251                         float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width);
252                         float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height);
253
254                         const glw::GLfloat coords[] =
255                         {
256                                 x1, y1, 0.0f, 1.0f,
257                                 x1, y2, 0.0f, 1.0f,
258                                 x2, y2, 0.0f, 1.0f,
259
260                                 x2, y2, 0.0f, 1.0f,
261                                 x2, y1, 0.0f, 1.0f,
262                                 x1, y1, 0.0f, 1.0f
263                         };
264
265                         const glw::GLubyte colors[] =
266                         {
267                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
268                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
269                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
270
271                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
272                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
273                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
274                         };
275
276                         m_gl.useProgram(m_glProgram.getProgram());
277                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
278
279                         m_gl.enableVertexAttribArray(m_coordLoc);
280                         m_gl.enableVertexAttribArray(m_colorLoc);
281                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
282
283                         m_gl.vertexAttribPointer(m_coordLoc, 4, GL_FLOAT, GL_FALSE, 0, coords);
284                         m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
285                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
286
287                         m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/4);
288                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed");
289
290                         m_gl.disableVertexAttribArray(m_coordLoc);
291                         m_gl.disableVertexAttribArray(m_colorLoc);
292                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
293
294                         m_gl.useProgram(0);
295                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
296                 }
297                 else if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
298                 {
299                         m_gl.enable(GL_SCISSOR_TEST);
300                         m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
301                                                  coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y());
302                         m_gl.clearColor(coloredRect.color.x()/255.0f, coloredRect.color.y()/255.0f, coloredRect.color.z()/255.0f, 1.0f);
303                         m_gl.clear(GL_COLOR_BUFFER_BIT);
304                         m_gl.disable(GL_SCISSOR_TEST);
305                 }
306                 else
307                         DE_ASSERT(false);
308         }
309 }
310
311 class ReferenceRenderer
312 {
313 public:
314                                                 ReferenceRenderer       (void);
315         void                            render                          (tcu::Surface* target, const Frame& frame) const;
316 private:
317                                                 ReferenceRenderer       (const ReferenceRenderer&);
318         ReferenceRenderer&      operator=                       (const ReferenceRenderer&);
319 };
320
321 ReferenceRenderer::ReferenceRenderer(void)
322 {
323 }
324
325 void ReferenceRenderer::render (tcu::Surface* target, const Frame& frame) const
326 {
327         for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
328         {
329                 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
330                 if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_RENDER || frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
331                 {
332                         const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
333                         tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
334                                                                                  coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
335                 }
336                 else
337                         DE_ASSERT(false);
338         }
339 }
340
341 BufferAgeTest::BufferAgeTest (EglTestContext& eglTestCtx, bool preserveColorBuffer, const vector<DrawType>& oddFrameDrawType, const vector<DrawType>& evenFrameDrawType,
342                                                           const char* name, const char* description)
343         : TestCase                              (eglTestCtx, name, description)
344         , m_seed                                (deStringHash(name))
345         , m_preserveColorBuffer (preserveColorBuffer)
346         , m_oddFrameDrawType    (oddFrameDrawType)
347         , m_evenFrameDrawType   (evenFrameDrawType)
348         , m_eglDisplay                  (EGL_NO_DISPLAY)
349         , m_window                              (DE_NULL)
350         , m_eglSurface                  (EGL_NO_SURFACE)
351         , m_eglContext                  (EGL_NO_CONTEXT)
352         , m_gles2Renderer               (DE_NULL)
353         , m_refRenderer                 (DE_NULL)
354 {
355 }
356
357 BufferAgeTest::~BufferAgeTest (void)
358 {
359         deinit();
360 }
361
362 void BufferAgeTest::init (void)
363 {
364         const Library&  egl     = m_eglTestCtx.getLibrary();
365
366         m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
367         m_eglConfig      = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorBuffer);
368
369         if (m_eglConfig == DE_NULL)
370                 TCU_THROW(NotSupportedError, "No supported config found");
371
372         //create surface and context and make them current
373         initEGLSurface(m_eglConfig);
374         initEGLContext(m_eglConfig);
375
376         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
377
378         if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age") == false)
379                 TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age is not supported");
380
381         m_gles2Renderer = new GLES2Renderer(m_gl);
382         m_refRenderer   = new ReferenceRenderer();
383 }
384
385 void BufferAgeTest::deinit (void)
386 {
387         const Library& egl = m_eglTestCtx.getLibrary();
388
389         delete m_refRenderer;
390         m_refRenderer = DE_NULL;
391
392         delete m_gles2Renderer;
393         m_gles2Renderer = DE_NULL;
394
395         if (m_eglContext != EGL_NO_CONTEXT)
396         {
397                 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
398                 egl.destroyContext(m_eglDisplay, m_eglContext);
399                 m_eglContext = EGL_NO_CONTEXT;
400         }
401
402         if (m_eglSurface != EGL_NO_SURFACE)
403         {
404                 egl.destroySurface(m_eglDisplay, m_eglSurface);
405                 m_eglSurface = EGL_NO_SURFACE;
406         }
407
408         if (m_eglDisplay != EGL_NO_DISPLAY)
409         {
410                 egl.terminate(m_eglDisplay);
411                 m_eglDisplay = EGL_NO_DISPLAY;
412         }
413
414         delete m_window;
415         m_window = DE_NULL;
416 }
417
418 void BufferAgeTest::initEGLSurface (EGLConfig config)
419 {
420         const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
421         m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
422                                                                         eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
423         m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
424 }
425
426 void BufferAgeTest::initEGLContext (EGLConfig config)
427 {
428         const Library&  egl              = m_eglTestCtx.getLibrary();
429         const EGLint    attribList[] =
430         {
431                 EGL_CONTEXT_CLIENT_VERSION, 2,
432                 EGL_NONE
433         };
434
435         egl.bindAPI(EGL_OPENGL_ES_API);
436         m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
437         EGLU_CHECK_MSG(egl, "eglCreateContext");
438         DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
439         egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
440         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
441 }
442
443 // return indices of frames that have been written to the given buffer
444 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
445 {
446         DE_ASSERT(frameNdx < (int)bufferAges.size());
447         vector<int> frameOnBuffer;
448         int             age = bufferAges[frameNdx];
449         while (age != 0)
450         {
451                 frameNdx = frameNdx - age;
452                 DE_ASSERT(frameNdx >= 0);
453                 frameOnBuffer.push_back(frameNdx);
454                 age = bufferAges[frameNdx];
455         }
456
457         reverse(frameOnBuffer.begin(), frameOnBuffer.end());
458         return frameOnBuffer;
459 }
460
461 TestCase::IterateResult BufferAgeTest::iterate (void)
462 {
463         de::Random              rnd                                     (m_seed);
464         const Library&  egl                                     = m_eglTestCtx.getLibrary();
465         tcu::TestLog&   log                                     = m_testCtx.getLog();
466         const int               width                           = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
467         const int               height                          = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
468         const float     clearRed                        = rnd.getFloat();
469         const float     clearGreen                      = rnd.getFloat();
470         const float     clearBlue                       = rnd.getFloat();
471         const tcu::Vec4 clearColor                      (clearRed, clearGreen, clearBlue, 1.0f);
472         const int               numFrames                       = 20;
473         FrameSequence   frameSequence;
474         vector<int>     bufferAges;
475
476         if (m_preserveColorBuffer)
477                 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
478         else
479                 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
480
481         for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
482         {
483                 tcu::Surface                                    currentBuffer                   (width, height);
484                 tcu::Surface                                    refBuffer                               (width, height);
485                 Frame                                                   newFrame                                (width, height);
486                 EGLint                                                  currentBufferAge                = -1;
487
488                 if (frameNdx % 2 == 0)
489                         generateRandomFrame(&newFrame, m_evenFrameDrawType, rnd);
490                 else
491                         generateRandomFrame(&newFrame, m_oddFrameDrawType, rnd);
492
493                 frameSequence.push_back(newFrame);
494
495                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &currentBufferAge));
496
497                 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
498                 {
499                         std::ostringstream stream;
500                         stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
501                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
502                         return STOP;
503                 }
504
505                 if (frameNdx > 0 && m_preserveColorBuffer && currentBufferAge != 1)
506                 {
507                         std::ostringstream stream;
508                         stream << "Fail, EGL_BUFFER_PRESERVED is set to true, but buffer age is: " << currentBufferAge << " (should be 1)";
509                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
510                         return STOP;
511                 }
512
513                 bufferAges.push_back(currentBufferAge);
514                 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
515
516                 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
517                 if (frameNdx < numFrames/2)
518                 {
519                         if (currentBufferAge == 0)
520                                 clearColorScreen(m_gl, clearColor);
521
522                         m_gles2Renderer->render(width, height, newFrame);
523                         EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
524                         continue;
525                 }
526
527                 // do verification in the second half
528                 if (currentBufferAge > 0) //buffer contain previous content, need to verify
529                 {
530                         const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
531                         readPixels(m_gl, &currentBuffer);
532                         clearColorReference(&refBuffer, clearColor);
533
534                         for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
535                                 m_refRenderer->render(&refBuffer, frameSequence[*it]);
536
537                         if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx-currentBufferAge) == false)
538                         {
539                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, buffer content is not well preserved when age > 0");
540                                 return STOP;
541                         }
542                 }
543                 else // currentBufferAge == 0, content is undefined, clear the buffer, currentBufferAge < 0 is ruled out at the beginning
544                 {
545                         clearColorScreen(m_gl, clearColor);
546                         clearColorReference(&refBuffer, clearColor);
547                 }
548
549                 m_gles2Renderer->render(width, height, newFrame);
550                 m_refRenderer->render(&refBuffer, newFrame);
551
552                 readPixels(m_gl, &currentBuffer);
553
554                 if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx) == false)
555                 {
556                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, render result is wrong");
557                         return STOP;
558                 }
559
560                 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
561         }
562
563         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
564         return STOP;
565 }
566
567 string generateDrawTypeName (const vector<BufferAgeTest::DrawType>& drawTypes)
568 {
569         std::ostringstream stream;
570         if (drawTypes.size() == 0)
571                 return string("_none");
572
573         for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
574         {
575                 if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
576                         stream << "_render";
577                 else if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
578                         stream << "_clear";
579                 else
580                         DE_ASSERT(false);
581         }
582         return stream.str();
583 }
584
585 string generateTestName (const vector<BufferAgeTest::DrawType>& oddFrameDrawType, const vector<BufferAgeTest::DrawType>& evenFrameDrawType)
586 {
587         return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
588 }
589
590 bool isWindow (const eglu::CandidateConfig& c)
591 {
592         return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
593 }
594
595 bool isES2Renderable (const eglu::CandidateConfig& c)
596 {
597         return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
598 }
599
600 bool hasPreserveSwap (const eglu::CandidateConfig& c)
601 {
602         return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
603 }
604
605 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer)
606 {
607         eglu::FilterList filters;
608         filters << isWindow << isES2Renderable;
609         if (preserveColorBuffer)
610                 filters << hasPreserveSwap;
611         return eglu::chooseSingleConfig(egl, eglDisplay, filters);
612 }
613
614 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
615 {
616         gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
617         gl.clear(GL_COLOR_BUFFER_BIT);
618 }
619
620 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
621 {
622         tcu::clear(ref->getAccess(), clearColor);
623 }
624
625 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
626 {
627         gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
628 }
629
630 float windowToDeviceCoordinates (int x, int length)
631 {
632         return (2.0f * float(x) / float(length)) - 1.0f;
633 }
634
635 bool compareToReference (tcu::TestLog& log,      const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
636 {
637         std::ostringstream stream;
638         stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
639         return tcu::intThresholdPositionDeviationCompare(log, "buffer age test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
640                                                                                                          tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
641 }
642
643 } // anonymous
644
645 BufferAgeTests::BufferAgeTests (EglTestContext& eglTestCtx)
646         : TestCaseGroup(eglTestCtx, "buffer_age", "Color buffer age tests")
647 {
648 }
649
650 void BufferAgeTests::init (void)
651 {
652         const BufferAgeTest::DrawType clearRender[2] =
653         {
654                 BufferAgeTest::DRAWTYPE_GLES2_CLEAR,
655                 BufferAgeTest::DRAWTYPE_GLES2_RENDER
656         };
657
658         const BufferAgeTest::DrawType renderClear[2] =
659         {
660                 BufferAgeTest::DRAWTYPE_GLES2_RENDER,
661                 BufferAgeTest::DRAWTYPE_GLES2_CLEAR
662         };
663
664         vector< vector<BufferAgeTest::DrawType> > frameDrawTypes;
665         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> ());
666         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
667         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
668         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
669         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
670         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
671         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
672
673         for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
674         {
675                 const bool                       preserve               = (preserveNdx == 0);
676                 TestCaseGroup* const preserveGroup      = new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
677
678                 for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
679                 {
680                         const vector<BufferAgeTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
681
682                         for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
683                         {
684                                 const vector<BufferAgeTest::DrawType>&  oddFrameDrawType = frameDrawTypes[oddNdx];
685                                 const std::string                                               name                     = generateTestName(oddFrameDrawType, evenFrameDrawType);
686                                 preserveGroup->addChild(new BufferAgeTest(m_eglTestCtx, preserve, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
687                         }
688                 }
689                 addChild(preserveGroup);
690         }
691 }
692
693 } // egl
694 } // deqp