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