eglGetFrameTimestamps: Consider timestamps of 0 as invalid.
[platform/upstream/VK-GL-CTS.git] / modules / egl / teglSwapBuffersWithDamageTests.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 KHR_swap_buffer_with_damage
22  *//*--------------------------------------------------------------------*/
23
24 #include "teglSwapBuffersWithDamageTests.hpp"
25
26 #include "tcuImageCompare.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuTextureUtil.hpp"
29
30 #include "egluNativeWindow.hpp"
31 #include "egluUtil.hpp"
32 #include "egluConfigFilter.hpp"
33
34 #include "eglwLibrary.hpp"
35 #include "eglwEnums.hpp"
36
37 #include "gluDefs.hpp"
38 #include "gluRenderContext.hpp"
39 #include "gluShaderProgram.hpp"
40
41 #include "glwDefs.hpp"
42 #include "glwEnums.hpp"
43 #include "glwFunctions.hpp"
44
45 #include "deRandom.hpp"
46 #include "deString.h"
47
48 #include <string>
49 #include <vector>
50 #include <sstream>
51
52 using std::string;
53 using std::vector;
54 using glw::GLubyte;
55 using tcu::IVec2;
56
57 using namespace eglw;
58
59 namespace deqp
60 {
61 namespace egl
62 {
63 namespace
64 {
65
66 typedef tcu::Vector<GLubyte, 3> Color;
67
68 enum DrawType
69 {
70     DRAWTYPE_GLES2_CLEAR,
71     DRAWTYPE_GLES2_RENDER
72 };
73
74 enum ResizeType
75 {
76         RESIZETYPE_NONE = 0,
77         RESIZETYPE_BEFORE_SWAP,
78         RESIZETYPE_AFTER_SWAP,
79
80         RESIZETYPE_LAST
81 };
82
83 struct ColoredRect
84 {
85 public:
86                                 ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
87         IVec2           bottomLeft;
88         IVec2           topRight;
89         Color           color;
90 };
91
92 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
93         : bottomLeft    (bottomLeft_)
94         , topRight              (topRight_)
95         , color                 (color_)
96 {
97 }
98
99 struct DrawCommand
100 {
101                                 DrawCommand (DrawType drawType_, const ColoredRect& rect_);
102     DrawType    drawType;
103         ColoredRect     rect;
104 };
105
106 DrawCommand::DrawCommand (DrawType drawType_, const ColoredRect& rect_)
107         : drawType      (drawType_)
108         , rect          (rect_)
109 {
110 }
111
112 struct Frame
113 {
114                                                 Frame (int width_, int height_);
115         int                                     width;
116         int                                     height;
117         vector<DrawCommand> draws;
118 };
119
120 Frame::Frame (int width_, int height_)
121         : width (width_)
122         , height(height_)
123 {
124 }
125
126 typedef vector<Frame> FrameSequence;
127
128 //helper function declaration
129 EGLConfig               getEGLConfig                                    (const Library& egl, EGLDisplay eglDisplay, bool preserveBuffer);
130 void                    clearColorScreen                                (const glw::Functions& gl, const tcu::Vec4& clearColor);
131 float                   windowToDeviceCoordinates               (int x, int length);
132
133 class GLES2Renderer
134 {
135 public:
136                                                         GLES2Renderer           (const glw::Functions& gl);
137                                                         ~GLES2Renderer          (void);
138         void                                    render                          (int width, int height, const Frame& frame) const;
139
140 private:
141                                                         GLES2Renderer           (const GLES2Renderer&);
142         GLES2Renderer&                  operator=                       (const GLES2Renderer&);
143
144         const glw::Functions&   m_gl;
145         glu::ShaderProgram              m_glProgram;
146         glw::GLuint                             m_coordLoc;
147         glw::GLuint                             m_colorLoc;
148 };
149
150 // generate sources for vertex and fragment buffer
151 glu::ProgramSources getSources (void)
152 {
153         const char* const vertexShaderSource =
154                 "attribute mediump vec2 a_pos;\n"
155                 "attribute mediump vec4 a_color;\n"
156                 "varying mediump vec4 v_color;\n"
157                 "void main(void)\n"
158                 "{\n"
159                 "\tv_color = a_color;\n"
160                 "\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
161                 "}";
162
163         const char* const fragmentShaderSource =
164                 "varying mediump vec4 v_color;\n"
165                 "void main(void)\n"
166                 "{\n"
167                 "\tgl_FragColor = v_color;\n"
168                 "}";
169
170         return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
171 }
172
173 GLES2Renderer::GLES2Renderer (const glw::Functions& gl)
174         : m_gl        (gl)
175         , m_glProgram (gl, getSources())
176         , m_coordLoc  ((glw::GLuint)-1)
177         , m_colorLoc  ((glw::GLuint)-1)
178 {
179         m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color");
180         m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos");
181         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
182 }
183
184 GLES2Renderer::~GLES2Renderer (void)
185 {
186 }
187
188 void GLES2Renderer::render (int width, int height, const Frame& frame) const
189 {
190         for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
191         {
192                 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
193
194                 if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_RENDER)
195                 {
196                         const float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width);
197                         const float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height);
198                         const float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width);
199                         const float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height);
200
201                         const glw::GLfloat coords[] =
202                         {
203                                 x1, y1,
204                                 x1, y2,
205                                 x2, y2,
206
207                                 x2, y2,
208                                 x2, y1,
209                                 x1, y1,
210                         };
211
212                         const glw::GLubyte colors[] =
213                         {
214                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
215                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
216                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
217
218                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
219                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
220                                 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
221                         };
222
223                         m_gl.useProgram(m_glProgram.getProgram());
224                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
225
226                         m_gl.enableVertexAttribArray(m_coordLoc);
227                         m_gl.enableVertexAttribArray(m_colorLoc);
228                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
229
230                         m_gl.vertexAttribPointer(m_coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords);
231                         m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
232                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
233
234                         m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/2);
235                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed");
236
237                         m_gl.disableVertexAttribArray(m_coordLoc);
238                         m_gl.disableVertexAttribArray(m_colorLoc);
239                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
240
241                         m_gl.useProgram(0);
242                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
243                 }
244                 else if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_CLEAR)
245                 {
246                         m_gl.enable(GL_SCISSOR_TEST);
247                         m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
248                                                  coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y());
249                         m_gl.clearColor(coloredRect.color.x()/255.0f, coloredRect.color.y()/255.0f, coloredRect.color.z()/255.0f, 1.0f);
250                         m_gl.clear(GL_COLOR_BUFFER_BIT);
251                         m_gl.disable(GL_SCISSOR_TEST);
252                 }
253                 else
254                         DE_FATAL("Invalid drawtype");
255         }
256 }
257
258 class SwapBuffersWithDamageTest : public TestCase
259 {
260 public:
261                                                                 SwapBuffersWithDamageTest               (EglTestContext&                        eglTestCtx,
262                                                                                                                                  const vector<DrawType>&        frameDrawType,
263                                                                                                                                  int                                            iterationTimes,
264                                                                                                                                  ResizeType                                     resizeType,
265                                                                                                                                  const char*                            name,
266                                                                                                                                  const char*                            description);
267
268                                                                 ~SwapBuffersWithDamageTest              (void);
269
270         virtual void                            init                                                    (void);
271         void                                            deinit                                                  (void);
272         virtual IterateResult           iterate                                                 (void);
273
274 protected:
275         virtual EGLConfig                       getConfig                                               (const Library& egl, EGLDisplay eglDisplay);
276         virtual void                            checkExtension                                  (const Library& egl, EGLDisplay eglDisplay);
277         void                                            initEGLSurface                                  (EGLConfig config);
278         void                                            initEGLContext                                  (EGLConfig config);
279
280         eglu::NativeWindow*                     m_window;
281         EGLConfig                                       m_eglConfig;
282         EGLContext                                      m_eglContext;
283         const int                                       m_seed;
284         const int                                       m_iterationTimes;
285         const vector<DrawType>          m_frameDrawType;
286         const ResizeType                        m_resizeType;
287         EGLDisplay                                      m_eglDisplay;
288         EGLSurface                                      m_eglSurface;
289         glw::Functions                          m_gl;
290         GLES2Renderer*                          m_gles2Renderer;
291 };
292
293 SwapBuffersWithDamageTest::SwapBuffersWithDamageTest (EglTestContext& eglTestCtx, const vector<DrawType>& frameDrawType, int iterationTimes, ResizeType resizeType, const char* name, const char* description)
294         : TestCase                      (eglTestCtx, name, description)
295         , m_window                      (DE_NULL)
296         , m_eglContext          (EGL_NO_CONTEXT)
297         , m_seed                        (deStringHash(name))
298         , m_iterationTimes      (iterationTimes)
299         , m_frameDrawType       (frameDrawType)
300         , m_resizeType          (resizeType)
301         , m_eglDisplay          (EGL_NO_DISPLAY)
302         , m_eglSurface          (EGL_NO_SURFACE)
303         , m_gles2Renderer        (DE_NULL)
304 {
305 }
306
307 SwapBuffersWithDamageTest::~SwapBuffersWithDamageTest (void)
308 {
309         deinit();
310 }
311
312 EGLConfig SwapBuffersWithDamageTest::getConfig (const Library& egl, EGLDisplay eglDisplay)
313 {
314         return getEGLConfig(egl, eglDisplay, false);
315 }
316
317 void SwapBuffersWithDamageTest::checkExtension (const Library& egl, EGLDisplay eglDisplay)
318 {
319         if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage"))
320                 TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported");
321 }
322
323 void SwapBuffersWithDamageTest::init (void)
324 {
325         const Library& egl = m_eglTestCtx.getLibrary();
326
327         m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
328         m_eglConfig  = getConfig(egl, m_eglDisplay);
329
330         checkExtension(egl, m_eglDisplay);
331
332         initEGLSurface(m_eglConfig);
333         initEGLContext(m_eglConfig);
334
335         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
336         m_gles2Renderer = new GLES2Renderer(m_gl);
337 }
338
339 void SwapBuffersWithDamageTest::deinit (void)
340 {
341         const Library& egl = m_eglTestCtx.getLibrary();
342
343         delete m_gles2Renderer;
344         m_gles2Renderer = DE_NULL;
345
346         if (m_eglContext != EGL_NO_CONTEXT)
347         {
348                 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
349                 egl.destroyContext(m_eglDisplay, m_eglContext);
350                 m_eglContext = EGL_NO_CONTEXT;
351         }
352
353         if (m_eglSurface != EGL_NO_SURFACE)
354         {
355                 egl.destroySurface(m_eglDisplay, m_eglSurface);
356                 m_eglSurface = EGL_NO_SURFACE;
357         }
358
359         if (m_eglDisplay != EGL_NO_DISPLAY)
360         {
361                 egl.terminate(m_eglDisplay);
362                 m_eglDisplay = EGL_NO_DISPLAY;
363         }
364
365         delete m_window;
366         m_window = DE_NULL;
367 }
368
369 void SwapBuffersWithDamageTest::initEGLSurface (EGLConfig config)
370 {
371         const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
372         m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
373                                                                         eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
374         m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
375 }
376
377 void SwapBuffersWithDamageTest::initEGLContext (EGLConfig config)
378 {
379         const Library&  egl                      = m_eglTestCtx.getLibrary();
380         const EGLint    attribList[] =
381         {
382                 EGL_CONTEXT_CLIENT_VERSION, 2,
383                 EGL_NONE
384         };
385
386         egl.bindAPI(EGL_OPENGL_ES_API);
387         m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
388         EGLU_CHECK_MSG(egl, "eglCreateContext");
389         TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
390         egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
391         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
392 }
393
394 FrameSequence   generateFrameSequence   (const vector<DrawType>& frameDrawType, de::Random& rnd, int numFrames, int width, int height);
395 vector<EGLint>  getDamageRegion                 (const Frame& frame);
396
397 TestCase::IterateResult SwapBuffersWithDamageTest::iterate (void)
398 {
399         de::Random                      rnd                             (m_seed);
400         const Library&          egl                             = m_eglTestCtx.getLibrary();
401         const int                       width                   = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
402         const int                       height                  = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
403         const float                     clearRed                = rnd.getFloat();
404         const float                     clearGreen              = rnd.getFloat();
405         const float                     clearBlue               = rnd.getFloat();
406         const tcu::Vec4         clearColor              (clearRed, clearGreen, clearBlue, 1.0f);
407         const int                       numFrames               = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible
408         const FrameSequence frameSequence       = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height);
409
410         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
411         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
412
413         for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++)
414         {
415                 for (int currentFrameNdx = 0; currentFrameNdx < numFrames; currentFrameNdx++)
416                 {
417                         vector<EGLint>  damageRegion = getDamageRegion(frameSequence[currentFrameNdx]);
418
419                         clearColorScreen(m_gl, clearColor);
420                         for (int ndx = 0; ndx <= currentFrameNdx; ndx++)
421                                 m_gles2Renderer->render(width, height, frameSequence[ndx]);
422
423                         if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
424                         {
425                                 if (iterationNdx % 2 == 0)
426                                         m_window->setSurfaceSize(IVec2(width*2, height/2));
427                                 else
428                                         m_window->setSurfaceSize(IVec2(height/2, width*2));
429                         }
430
431                         EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
432
433                         if (m_resizeType == RESIZETYPE_AFTER_SWAP)
434                         {
435                                 if (iterationNdx % 2 == 0)
436                                         m_window->setSurfaceSize(IVec2(width*2, height/2));
437                                 else
438                                         m_window->setSurfaceSize(IVec2(height/2, width*2));
439                         }
440                 }
441         }
442         return STOP;
443 }
444
445 class SwapBuffersWithDamageAndPreserveBufferTest : public SwapBuffersWithDamageTest
446 {
447 public:
448                                         SwapBuffersWithDamageAndPreserveBufferTest      (EglTestContext&                        eglTestCtx,
449                                                                                                                                  const vector<DrawType>&        frameDrawType,
450                                                                                                                                  int                                            iterationTimes,
451                                                                                                                                  ResizeType                                     resizeType,
452                                                                                                                                  const char*                            name,
453                                                                                                                                  const char*                            description);
454
455         IterateResult   iterate                                                                         (void);
456
457 protected:
458         EGLConfig               getConfig                                                                       (const Library& egl, EGLDisplay eglDisplay);
459 };
460
461 SwapBuffersWithDamageAndPreserveBufferTest::SwapBuffersWithDamageAndPreserveBufferTest (EglTestContext&                 eglTestCtx,
462                                                                                                                                                                                 const vector<DrawType>& frameDrawType,
463                                                                                                                                                                                 int                                             iterationTimes,
464                                                                                                                                                                                 ResizeType                              resizeType,
465                                                                                                                                                                                 const char*                             name,
466                                                                                                                                                                                 const char*                             description)
467         : SwapBuffersWithDamageTest (eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description)
468 {
469 }
470
471 EGLConfig SwapBuffersWithDamageAndPreserveBufferTest::getConfig (const Library& egl, EGLDisplay eglDisplay)
472 {
473         return getEGLConfig(egl, eglDisplay, true);
474 }
475
476 TestCase::IterateResult SwapBuffersWithDamageAndPreserveBufferTest::iterate (void)
477 {
478
479         de::Random                      rnd                             (m_seed);
480         const Library&          egl                             = m_eglTestCtx.getLibrary();
481         const int                       width                   = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
482         const int                       height                  = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
483         const float                     clearRed                = rnd.getFloat();
484         const float                     clearGreen              = rnd.getFloat();
485         const float                     clearBlue               = rnd.getFloat();
486         const tcu::Vec4         clearColor              (clearRed, clearGreen, clearBlue, 1.0f);
487         const int                       numFrames               = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible
488         const FrameSequence frameSequence       = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height);
489
490         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
491         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
492
493         for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++)
494         {
495                 clearColorScreen(m_gl, clearColor);
496                 EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0));
497
498                 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
499                 {
500                         const Frame&    currentFrame = frameSequence[frameNdx];
501                         vector<EGLint>  damageRegion = getDamageRegion(currentFrame);
502
503                         m_gles2Renderer->render(width, height, currentFrame);
504
505                         if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
506                         {
507                                 if (iterationNdx % 2 == 0)
508                                         m_window->setSurfaceSize(IVec2(width*2, height/2));
509                                 else
510                                         m_window->setSurfaceSize(IVec2(height/2, width*2));
511                         }
512
513                         EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
514
515                         if (m_resizeType == RESIZETYPE_AFTER_SWAP)
516                         {
517                                 if (iterationNdx % 2 == 0)
518                                         m_window->setSurfaceSize(IVec2(width*2, height/2));
519                                 else
520                                         m_window->setSurfaceSize(IVec2(height/2, width*2));
521                         }
522                 }
523         }
524
525         return STOP;
526 }
527
528 class SwapBuffersWithDamageAndBufferAgeTest : public SwapBuffersWithDamageTest
529 {
530 public:
531                                         SwapBuffersWithDamageAndBufferAgeTest   (EglTestContext&                        eglTestCtx,
532                                                                                                                          const vector<DrawType>&        frameDrawType,
533                                                                                                                          int                                            iterationTimes,
534                                                                                                                          ResizeType                                     resizeType,
535                                                                                                                          const char*                            name,
536                                                                                                                          const char*                            description);
537
538         IterateResult   iterate                                                                 (void);
539
540 protected:
541         void                    checkExtension                                                  (const Library& egl, EGLDisplay eglDisplay);
542 };
543
544 SwapBuffersWithDamageAndBufferAgeTest::SwapBuffersWithDamageAndBufferAgeTest (EglTestContext&                   eglTestCtx,
545                                                                                                                                                           const vector<DrawType>&       frameDrawType,
546                                                                                                                                                           int                                           iterationTimes,
547                                                                                                                                                           ResizeType                            resizeType,
548                                                                                                                                                           const char*                           name,
549                                                                                                                                                           const char*                           description)
550         : SwapBuffersWithDamageTest (eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description)
551 {
552 }
553
554
555 void SwapBuffersWithDamageAndBufferAgeTest::checkExtension (const Library& egl, EGLDisplay eglDisplay)
556 {
557         if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage"))
558                 TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported");
559
560         if (!eglu::hasExtension(egl, eglDisplay, "EGL_EXT_buffer_age"))
561                 TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age not supported");
562 }
563
564 TestCase::IterateResult SwapBuffersWithDamageAndBufferAgeTest::iterate (void)
565 {
566
567         de::Random                      rnd                             (m_seed);
568         const Library&          egl                             = m_eglTestCtx.getLibrary();
569         const int                       width                   = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
570         const int                       height                  = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
571         const float                     clearRed                = rnd.getFloat();
572         const float                     clearGreen              = rnd.getFloat();
573         const float                     clearBlue               = rnd.getFloat();
574         const tcu::Vec4         clearColor              (clearRed, clearGreen, clearBlue, 1.0f);
575         const int                       numFrames               = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible
576         const FrameSequence frameSequence       = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height);
577
578         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
579         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
580
581         for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++)
582         {
583                 clearColorScreen(m_gl, clearColor);
584                 EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0));
585
586                 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
587                 {
588                         vector<EGLint>  damageRegion;
589                         int                             bufferAge               = -1;
590                         int                             startFrameNdx   = -1;
591                         int                             endFrameNdx             = frameNdx;
592
593                         EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &bufferAge));
594
595                         if (bufferAge < 0) // invalid buffer age
596                         {
597                                 std::ostringstream stream;
598                                 stream << "Fail, the age is invalid. Age: " << bufferAge << ", frameNdx: " << frameNdx;
599                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
600                                 return STOP;
601                         }
602
603                         if (bufferAge == 0 || bufferAge > frameNdx)
604                         {
605                                 clearColorScreen(m_gl, clearColor);
606                                 startFrameNdx = 0;
607                         }
608                         else
609                                 startFrameNdx = frameNdx-bufferAge+1;
610
611                         for (int ndx = startFrameNdx; ndx <= endFrameNdx; ndx++)
612                         {
613                                 const vector<EGLint> partialDamageRegion = getDamageRegion(frameSequence[ndx]);
614
615                                 damageRegion.insert(damageRegion.end(), partialDamageRegion.begin(), partialDamageRegion.end());
616                                 m_gles2Renderer->render(width, height, frameSequence[ndx]);
617                         }
618
619                         if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
620                         {
621                                 if (iterationNdx % 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                         EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
628
629                         if (m_resizeType == RESIZETYPE_AFTER_SWAP)
630                         {
631                                 if (iterationNdx % 2 == 0)
632                                         m_window->setSurfaceSize(IVec2(width*2, height/2));
633                                 else
634                                         m_window->setSurfaceSize(IVec2(height/2, width*2));
635                         }
636                 }
637         }
638         return STOP;
639 }
640
641 // generate a frame sequence with certain frame for visual verification
642 FrameSequence generateFrameSequence (const vector<DrawType>& frameDrawType, de::Random& rnd, int numFrames, int width, int height)
643 {
644         const int                       frameDiff               = height / numFrames;
645         const GLubyte           r                               = rnd.getUint8();
646         const GLubyte           g                               = rnd.getUint8();
647         const GLubyte           b                               = rnd.getUint8();
648         const Color                     color                   (r, g, b);
649         FrameSequence           frameSequence;
650
651         for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
652         {
653                 Frame frame (width, height);
654
655                 for (int rectNdx = 0; rectNdx < (int)frameDrawType.size(); rectNdx++)
656                 {
657                         const int                       rectHeight              = frameDiff / (int)frameDrawType.size();
658                         const ColoredRect       rect                    (IVec2(0, frameNdx*frameDiff+rectNdx*rectHeight), IVec2(width, frameNdx*frameDiff+(rectNdx+1)*rectHeight), color);
659                         const DrawCommand       drawCommand             (frameDrawType[rectNdx], rect);
660
661                         frame.draws.push_back(drawCommand);
662                 }
663                 frameSequence.push_back(frame);
664         }
665         return frameSequence;
666 }
667
668 vector<EGLint> getDamageRegion (const Frame& frame)
669 {
670         vector<EGLint> damageRegion;
671         for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
672         {
673                 const ColoredRect& rect = frame.draws[drawNdx].rect;
674                 damageRegion.push_back(rect.bottomLeft.x());
675                 damageRegion.push_back(rect.bottomLeft.y());
676                 damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x());
677                 damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y());
678         }
679
680         DE_ASSERT(damageRegion.size() % 4 == 0);
681         return damageRegion;
682 }
683
684 string generateTestName (const vector<DrawType>& frameDrawType)
685 {
686         std::ostringstream stream;
687
688         for (size_t ndx = 0; ndx < frameDrawType.size(); ndx++)
689         {
690                 if (frameDrawType[ndx] == DRAWTYPE_GLES2_RENDER)
691                         stream << "render";
692                 else if (frameDrawType[ndx] == DRAWTYPE_GLES2_CLEAR)
693                         stream << "clear";
694                 else
695                         DE_ASSERT(false);
696
697                 if (ndx < frameDrawType.size()-1)
698                         stream << "_";
699         }
700
701         return stream.str();
702 }
703
704 string generateResizeGroupName (ResizeType resizeType)
705 {
706         switch (resizeType)
707         {
708                 case RESIZETYPE_NONE:
709                         return "no_resize";
710
711                 case RESIZETYPE_AFTER_SWAP:
712                         return "resize_after_swap";
713
714                 case RESIZETYPE_BEFORE_SWAP:
715                         return "resize_before_swap";
716
717                 default:
718                         DE_FATAL("Unknown resize type");
719                         return "";
720         }
721 }
722
723 bool isWindow (const eglu::CandidateConfig& c)
724 {
725         return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
726 }
727
728 bool isES2Renderable (const eglu::CandidateConfig& c)
729 {
730         return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
731 }
732
733 bool hasPreserveSwap (const eglu::CandidateConfig& c)
734 {
735         return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
736 }
737
738 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveBuffer)
739 {
740         eglu::FilterList filters;
741
742         filters << isWindow << isES2Renderable;
743         if (preserveBuffer)
744                 filters << hasPreserveSwap;
745
746         return eglu::chooseSingleConfig(egl, eglDisplay, filters);
747 }
748
749 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
750 {
751         gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
752         gl.clear(GL_COLOR_BUFFER_BIT);
753 }
754
755 float windowToDeviceCoordinates (int x, int length)
756 {
757         return (2.0f * float(x) / float(length)) - 1.0f;
758 }
759
760 } // anonymous
761
762 SwapBuffersWithDamageTests::SwapBuffersWithDamageTests (EglTestContext& eglTestCtx)
763         : TestCaseGroup(eglTestCtx, "swap_buffers_with_damage", "Swap buffers with damages tests")
764 {
765 }
766
767 void SwapBuffersWithDamageTests::init (void)
768 {
769         const DrawType clearRender[2] =
770         {
771                 DRAWTYPE_GLES2_CLEAR,
772                 DRAWTYPE_GLES2_RENDER
773         };
774
775         const DrawType renderClear[2] =
776         {
777                 DRAWTYPE_GLES2_RENDER,
778                 DRAWTYPE_GLES2_CLEAR
779         };
780
781         const ResizeType resizeTypes[] =
782         {
783                 RESIZETYPE_NONE,
784                 RESIZETYPE_BEFORE_SWAP,
785                 RESIZETYPE_AFTER_SWAP
786         };
787
788         vector< vector<DrawType> > frameDrawTypes;
789         frameDrawTypes.push_back(vector<DrawType> (1, DRAWTYPE_GLES2_CLEAR));
790         frameDrawTypes.push_back(vector<DrawType> (1, DRAWTYPE_GLES2_RENDER));
791         frameDrawTypes.push_back(vector<DrawType> (2, DRAWTYPE_GLES2_CLEAR));
792         frameDrawTypes.push_back(vector<DrawType> (2, DRAWTYPE_GLES2_RENDER));
793         frameDrawTypes.push_back(vector<DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
794         frameDrawTypes.push_back(vector<DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
795
796         for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++)
797         {
798                 const ResizeType                resizeType      = resizeTypes[resizeTypeNdx];
799                 TestCaseGroup* const    resizeGroup     = new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), "");
800
801                 for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++)
802                 {
803                         string name = generateTestName(frameDrawTypes[drawTypeNdx]);
804                         resizeGroup->addChild(new SwapBuffersWithDamageTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), ""));
805                 }
806
807                 for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++)
808                 {
809                         string name = "preserve_buffer_" + generateTestName(frameDrawTypes[drawTypeNdx]);
810                         resizeGroup->addChild(new SwapBuffersWithDamageAndPreserveBufferTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), ""));
811                 }
812
813                 for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++)
814                 {
815                         string name = "buffer_age_" + generateTestName(frameDrawTypes[drawTypeNdx]);
816                         resizeGroup->addChild(new SwapBuffersWithDamageAndBufferAgeTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(),  ""));
817                 }
818
819                 addChild(resizeGroup);
820         }
821 }
822
823 } // egl
824 } // deqp