Merge vk-gl-cts/vulkan-cts-1.3.4 into vk-gl-cts/vulkan-cts-1.3.5
[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                         // tcu does not support degenerate subregions. Since they correspond to no-op rendering, just skip them.
349                         if (coloredRect.bottomLeft.x() == coloredRect.topRight.x() || coloredRect.bottomLeft.y() == coloredRect.topRight.y())
350                                 continue;
351
352                         const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
353                         tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
354                                                                                  coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
355                 }
356                 else
357                         DE_ASSERT(false);
358         }
359 }
360
361 BufferAgeTest::BufferAgeTest (EglTestContext&                   eglTestCtx,
362                                                           bool                                          preserveColorBuffer,
363                                                           const vector<DrawType>&       oddFrameDrawType,
364                                                           const vector<DrawType>&       evenFrameDrawType,
365                                                           ResizeType                            resizeType,
366                                                           const char*                           name,
367                                                           const char*                           description)
368         : TestCase                              (eglTestCtx, name, description)
369         , m_seed                                (deStringHash(name))
370         , m_preserveColorBuffer (preserveColorBuffer)
371         , m_oddFrameDrawType    (oddFrameDrawType)
372         , m_evenFrameDrawType   (evenFrameDrawType)
373         , m_resizeType                  (resizeType)
374         , m_eglDisplay                  (EGL_NO_DISPLAY)
375         , m_window                              (DE_NULL)
376         , m_eglSurface                  (EGL_NO_SURFACE)
377         , m_eglContext                  (EGL_NO_CONTEXT)
378         , m_gles2Renderer               (DE_NULL)
379         , m_refRenderer                 (DE_NULL)
380 {
381 }
382
383 BufferAgeTest::~BufferAgeTest (void)
384 {
385         deinit();
386 }
387
388 void BufferAgeTest::init (void)
389 {
390         const Library&  egl     = m_eglTestCtx.getLibrary();
391
392         m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
393
394         if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age") == false)
395         {
396                 egl.terminate(m_eglDisplay);
397                 m_eglDisplay = EGL_NO_DISPLAY;
398                 TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age is not supported");
399         }
400
401         m_eglConfig      = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorBuffer);
402
403         if (m_eglConfig == DE_NULL)
404                 TCU_THROW(NotSupportedError, "No supported config found");
405
406         //create surface and context and make them current
407         initEGLSurface(m_eglConfig);
408         initEGLContext(m_eglConfig);
409
410         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
411
412         m_gles2Renderer = new GLES2Renderer(m_gl);
413         m_refRenderer   = new ReferenceRenderer();
414 }
415
416 void BufferAgeTest::deinit (void)
417 {
418         const Library& egl = m_eglTestCtx.getLibrary();
419
420         delete m_refRenderer;
421         m_refRenderer = DE_NULL;
422
423         delete m_gles2Renderer;
424         m_gles2Renderer = DE_NULL;
425
426         if (m_eglContext != EGL_NO_CONTEXT)
427         {
428                 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
429                 egl.destroyContext(m_eglDisplay, m_eglContext);
430                 m_eglContext = EGL_NO_CONTEXT;
431         }
432
433         if (m_eglSurface != EGL_NO_SURFACE)
434         {
435                 egl.destroySurface(m_eglDisplay, m_eglSurface);
436                 m_eglSurface = EGL_NO_SURFACE;
437         }
438
439         if (m_eglDisplay != EGL_NO_DISPLAY)
440         {
441                 egl.terminate(m_eglDisplay);
442                 m_eglDisplay = EGL_NO_DISPLAY;
443         }
444
445         delete m_window;
446         m_window = DE_NULL;
447 }
448
449 void BufferAgeTest::initEGLSurface (EGLConfig config)
450 {
451         const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
452         m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
453                                                                         eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
454         m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
455 }
456
457 void BufferAgeTest::initEGLContext (EGLConfig config)
458 {
459         const Library&  egl                      = m_eglTestCtx.getLibrary();
460         const EGLint    attribList[] =
461         {
462                 EGL_CONTEXT_CLIENT_VERSION, 2,
463                 EGL_NONE
464         };
465
466         egl.bindAPI(EGL_OPENGL_ES_API);
467         m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
468         EGLU_CHECK_MSG(egl, "eglCreateContext");
469         DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
470         egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
471         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
472 }
473
474 // return indices of frames that have been written to the given buffer
475 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
476 {
477         DE_ASSERT(frameNdx < (int)bufferAges.size());
478         vector<int> frameOnBuffer;
479         int                     age = bufferAges[frameNdx];
480         while (age != 0)
481         {
482                 frameNdx = frameNdx - age;
483                 DE_ASSERT(frameNdx >= 0);
484                 frameOnBuffer.push_back(frameNdx);
485                 age = bufferAges[frameNdx];
486         }
487
488         reverse(frameOnBuffer.begin(), frameOnBuffer.end());
489         return frameOnBuffer;
490 }
491
492 TestCase::IterateResult BufferAgeTest::iterate (void)
493 {
494         de::Random              rnd                                     (m_seed);
495         const Library&  egl                                     = m_eglTestCtx.getLibrary();
496         tcu::TestLog&   log                                     = m_testCtx.getLog();
497         const int               width                           = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
498         const int               height                          = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
499         const float             clearRed                        = rnd.getFloat();
500         const float             clearGreen                      = rnd.getFloat();
501         const float             clearBlue                       = rnd.getFloat();
502         const tcu::Vec4 clearColor                      (clearRed, clearGreen, clearBlue, 1.0f);
503         const int               numFrames                       = 20;
504         FrameSequence   frameSequence;
505         vector<int>             bufferAges;
506
507         if (m_preserveColorBuffer)
508                 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
509         else
510                 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
511
512         for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
513         {
514                 tcu::Surface                                    currentBuffer                   (width, height);
515                 tcu::Surface                                    refBuffer                               (width, height);
516                 Frame                                                   newFrame                                (width, height);
517                 EGLint                                                  currentBufferAge                = -1;
518
519                 if (frameNdx % 2 == 0)
520                         generateRandomFrame(&newFrame, m_evenFrameDrawType, rnd);
521                 else
522                         generateRandomFrame(&newFrame, m_oddFrameDrawType, rnd);
523
524                 frameSequence.push_back(newFrame);
525
526                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &currentBufferAge));
527
528                 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
529                 {
530                         std::ostringstream stream;
531                         stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
532                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
533                         return STOP;
534                 }
535
536                 if (frameNdx > 0 && m_preserveColorBuffer && currentBufferAge != 1)
537                 {
538                         std::ostringstream stream;
539                         stream << "Fail, EGL_BUFFER_PRESERVED is set to true, but buffer age is: " << currentBufferAge << " (should be 1)";
540                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
541                         return STOP;
542                 }
543
544                 bufferAges.push_back(currentBufferAge);
545                 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
546
547                 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
548                 if (frameNdx < numFrames/2)
549                 {
550                         if (currentBufferAge == 0)
551                                 clearColorScreen(m_gl, clearColor);
552
553                         m_gles2Renderer->render(width, height, newFrame);
554
555                         if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
556                         {
557                                 if (frameNdx % 2 == 0)
558                                         m_window->setSurfaceSize(IVec2(width*2, height/2));
559                                 else
560                                         m_window->setSurfaceSize(IVec2(height/2, width*2));
561                         }
562
563                         EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
564
565                         if (m_resizeType == RESIZETYPE_AFTER_SWAP)
566                         {
567                                 if (frameNdx % 2 == 0)
568                                         m_window->setSurfaceSize(IVec2(width*2, height/2));
569                                 else
570                                         m_window->setSurfaceSize(IVec2(height/2, width*2));
571                         }
572
573                         continue;
574                 }
575
576                 // do verification in the second half
577                 if (currentBufferAge > 0) //buffer contain previous content, need to verify
578                 {
579                         const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
580                         readPixels(m_gl, &currentBuffer);
581                         clearColorReference(&refBuffer, clearColor);
582
583                         for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
584                                 m_refRenderer->render(&refBuffer, frameSequence[*it]);
585
586                         if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx-currentBufferAge) == false)
587                         {
588                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, buffer content is not well preserved when age > 0");
589                                 return STOP;
590                         }
591                 }
592                 else // currentBufferAge == 0, content is undefined, clear the buffer, currentBufferAge < 0 is ruled out at the beginning
593                 {
594                         clearColorScreen(m_gl, clearColor);
595                         clearColorReference(&refBuffer, clearColor);
596                 }
597
598                 m_gles2Renderer->render(width, height, newFrame);
599                 m_refRenderer->render(&refBuffer, newFrame);
600
601                 readPixels(m_gl, &currentBuffer);
602
603                 if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx) == false)
604                 {
605                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, render result is wrong");
606                         return STOP;
607                 }
608
609                 if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
610                 {
611                         if (frameNdx % 2 == 0)
612                                 m_window->setSurfaceSize(IVec2(width*2, height/2));
613                         else
614                                 m_window->setSurfaceSize(IVec2(height/2, width*2));
615                 }
616
617                 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
618
619                 if (m_resizeType == RESIZETYPE_AFTER_SWAP)
620                 {
621                         if (frameNdx % 2 == 0)
622                                 m_window->setSurfaceSize(IVec2(width*2, height/2));
623                         else
624                                 m_window->setSurfaceSize(IVec2(height/2, width*2));
625                 }
626         }
627
628         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
629         return STOP;
630 }
631
632 string generateDrawTypeName (const vector<BufferAgeTest::DrawType>& drawTypes)
633 {
634         std::ostringstream stream;
635         if (drawTypes.size() == 0)
636                 return string("_none");
637
638         for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
639         {
640                 if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
641                         stream << "_render";
642                 else if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
643                         stream << "_clear";
644                 else
645                         DE_ASSERT(false);
646         }
647         return stream.str();
648 }
649
650 string generateTestName (const vector<BufferAgeTest::DrawType>& oddFrameDrawType, const vector<BufferAgeTest::DrawType>& evenFrameDrawType)
651 {
652         return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
653 }
654
655 string generateResizeGroupName (BufferAgeTest::ResizeType resizeType)
656 {
657         switch (resizeType)
658         {
659                 case BufferAgeTest::RESIZETYPE_NONE:
660                         return "no_resize";
661
662                 case BufferAgeTest::RESIZETYPE_AFTER_SWAP:
663                         return "resize_after_swap";
664
665                 case BufferAgeTest::RESIZETYPE_BEFORE_SWAP:
666                         return "resize_before_swap";
667
668                 default:
669                         DE_FATAL("Unknown resize type");
670                         return "";
671         }
672 }
673
674 bool isWindow (const eglu::CandidateConfig& c)
675 {
676         return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
677 }
678
679 bool isES2Renderable (const eglu::CandidateConfig& c)
680 {
681         return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
682 }
683
684 bool hasPreserveSwap (const eglu::CandidateConfig& c)
685 {
686         return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
687 }
688
689 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer)
690 {
691         eglu::FilterList filters;
692         filters << isWindow << isES2Renderable;
693         if (preserveColorBuffer)
694                 filters << hasPreserveSwap;
695         return eglu::chooseSingleConfig(egl, eglDisplay, filters);
696 }
697
698 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
699 {
700         gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
701         gl.clear(GL_COLOR_BUFFER_BIT);
702 }
703
704 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
705 {
706         tcu::clear(ref->getAccess(), clearColor);
707 }
708
709 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
710 {
711         gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
712 }
713
714 float windowToDeviceCoordinates (int x, int length)
715 {
716         return (2.0f * float(x) / float(length)) - 1.0f;
717 }
718
719 bool compareToReference (tcu::TestLog& log,      const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
720 {
721         std::ostringstream stream;
722         stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
723         return tcu::intThresholdPositionDeviationCompare(log, "buffer age test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
724                                                                                                          tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
725 }
726
727 } // anonymous
728
729 BufferAgeTests::BufferAgeTests (EglTestContext& eglTestCtx)
730         : TestCaseGroup(eglTestCtx, "buffer_age", "Color buffer age tests")
731 {
732 }
733
734 void BufferAgeTests::init (void)
735 {
736         const BufferAgeTest::DrawType clearRender[] =
737         {
738                 BufferAgeTest::DRAWTYPE_GLES2_CLEAR,
739                 BufferAgeTest::DRAWTYPE_GLES2_RENDER
740         };
741
742         const BufferAgeTest::DrawType renderClear[] =
743         {
744                 BufferAgeTest::DRAWTYPE_GLES2_RENDER,
745                 BufferAgeTest::DRAWTYPE_GLES2_CLEAR
746         };
747
748         const BufferAgeTest::ResizeType resizeTypes[] =
749         {
750                 BufferAgeTest::RESIZETYPE_NONE,
751                 BufferAgeTest::RESIZETYPE_BEFORE_SWAP,
752                 BufferAgeTest::RESIZETYPE_AFTER_SWAP
753         };
754
755         vector< vector<BufferAgeTest::DrawType> > frameDrawTypes;
756         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> ());
757         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
758         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
759         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
760         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
761         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
762         frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
763
764         for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
765         {
766                 const bool                              preserve                = (preserveNdx == 0);
767                 TestCaseGroup* const    preserveGroup   = new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
768
769                 for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++)
770                 {
771                         const BufferAgeTest::ResizeType resizeType      = resizeTypes[resizeTypeNdx];
772                         TestCaseGroup* const                    resizeGroup     = new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), "");
773
774                         for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
775                         {
776                                 const vector<BufferAgeTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
777
778                                 for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
779                                 {
780                                         const vector<BufferAgeTest::DrawType>&  oddFrameDrawType        = frameDrawTypes[oddNdx];
781                                         const std::string                                               name                            = generateTestName(oddFrameDrawType, evenFrameDrawType);
782                                         resizeGroup->addChild(new BufferAgeTest(m_eglTestCtx, preserve, oddFrameDrawType, evenFrameDrawType, BufferAgeTest::RESIZETYPE_NONE, name.c_str(), ""));
783                                 }
784                         }
785
786                         preserveGroup->addChild(resizeGroup);
787                 }
788                 addChild(preserveGroup);
789         }
790 }
791
792 } // egl
793 } // deqp