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