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