x11_egl: use quotes to include glesv1_cm directories am: f5e7ab6b79
[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                         // tcu does not support degenerate subregions. Since they correspond to no-op rendering, just skip them.
338                         if (coloredRect.bottomLeft.x() == coloredRect.topRight.x() || coloredRect.bottomLeft.y() == coloredRect.topRight.y())
339                                 continue;
340
341                         const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
342                         tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
343                                                                                  coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
344                 }
345                 else
346                         DE_FATAL("Invalid drawtype");
347         }
348 }
349
350 PartialUpdateTest::PartialUpdateTest (EglTestContext& eglTestCtx,
351                                                                           const vector<DrawType>& oddFrameDrawType,
352                                                                           const vector<DrawType>& evenFrameDrawType,
353                                                                           const char* name, const char* description)
354         : TestCase                              (eglTestCtx, name, description)
355         , m_window                              (DE_NULL)
356         , m_eglContext                  (EGL_NO_CONTEXT)
357         , m_seed                                (deStringHash(name))
358         , m_oddFrameDrawType    (oddFrameDrawType)
359         , m_evenFrameDrawType   (evenFrameDrawType)
360         , m_supportBufferAge    (false)
361         , m_eglDisplay                  (EGL_NO_DISPLAY)
362         , m_eglSurface                  (EGL_NO_SURFACE)
363         , m_gles2Renderer               (DE_NULL)
364         , m_refRenderer                 (DE_NULL)
365 {
366 }
367
368 PartialUpdateTest::~PartialUpdateTest (void)
369 {
370         deinit();
371 }
372
373 void PartialUpdateTest::init (void)
374 {
375         const Library&  egl     = m_eglTestCtx.getLibrary();
376
377         m_eglDisplay            = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
378         m_eglConfig                     = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay);
379
380         //create surface and context and make them current
381         initEGLSurface(m_eglConfig);
382         initEGLContext(m_eglConfig);
383
384         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
385
386         m_supportBufferAge = eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age");
387
388         if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_partial_update"))
389                 TCU_THROW(NotSupportedError, "EGL_KHR_partial_update is not supported");
390
391         m_gles2Renderer = new GLES2Renderer(m_gl);
392         m_refRenderer   = new ReferenceRenderer();
393 }
394
395 void PartialUpdateTest::deinit (void)
396 {
397         const Library& egl = m_eglTestCtx.getLibrary();
398
399         delete m_refRenderer;
400         m_refRenderer = DE_NULL;
401
402         delete m_gles2Renderer;
403         m_gles2Renderer = DE_NULL;
404
405         if (m_eglContext != EGL_NO_CONTEXT)
406         {
407                 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
408                 egl.destroyContext(m_eglDisplay, m_eglContext);
409                 m_eglContext = EGL_NO_CONTEXT;
410         }
411
412         if (m_eglSurface != EGL_NO_SURFACE)
413         {
414                 egl.destroySurface(m_eglDisplay, m_eglSurface);
415                 m_eglSurface = EGL_NO_SURFACE;
416         }
417
418         if (m_eglDisplay != EGL_NO_DISPLAY)
419         {
420                 egl.terminate(m_eglDisplay);
421                 m_eglDisplay = EGL_NO_DISPLAY;
422         }
423
424         delete m_window;
425         m_window = DE_NULL;
426 }
427
428 void PartialUpdateTest::initEGLSurface (EGLConfig config)
429 {
430         const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
431         m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
432                                                                         eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
433         m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
434 }
435
436 void PartialUpdateTest::initEGLContext (EGLConfig config)
437 {
438         const Library&  egl                      = m_eglTestCtx.getLibrary();
439         const EGLint    attribList[] =
440         {
441                 EGL_CONTEXT_CLIENT_VERSION, 2,
442                 EGL_NONE
443         };
444
445         egl.bindAPI(EGL_OPENGL_ES_API);
446         m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
447         EGLU_CHECK_MSG(egl, "eglCreateContext");
448         TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
449         egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
450         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
451 }
452
453 // return indices of frames that have been written to the given buffer
454 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
455 {
456         DE_ASSERT(frameNdx < (int)bufferAges.size());
457         vector<int> frameOnBuffer;
458         int                     age = bufferAges[frameNdx];
459         while (age != 0)
460         {
461                 frameNdx = frameNdx - age;
462                 DE_ASSERT(frameNdx >= 0);
463                 frameOnBuffer.push_back(frameNdx);
464                 age = bufferAges[frameNdx];
465         }
466
467         reverse(frameOnBuffer.begin(), frameOnBuffer.end());
468         return frameOnBuffer;
469 }
470
471 vector<EGLint> getDamageRegion (const Frame& frame, int marginLeft, int marginBottom, int marginRight, int marginTop)
472 {
473         vector<EGLint> damageRegion;
474         for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
475         {
476                 const ColoredRect& rect = frame.draws[drawNdx].rect;
477                 damageRegion.push_back(rect.bottomLeft.x() - marginLeft);
478                 damageRegion.push_back(rect.bottomLeft.y() - marginBottom);
479                 damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x() + marginLeft + marginRight);
480                 damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y() + marginBottom + marginTop);
481         }
482
483         DE_ASSERT(damageRegion.size() % 4 == 0);
484         return damageRegion;
485 }
486
487 TestCase::IterateResult PartialUpdateTest::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         bool                    hasPositiveAge  = false;
502
503         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
504
505         for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
506         {
507                 tcu::Surface    currentBuffer    (width, height);
508                 tcu::Surface    refBuffer                (width, height);
509                 Frame                   newFrame                 (width, height);
510                 EGLint                  currentBufferAge = -1;
511
512                 if (frameNdx % 2 == 0)
513                         generateRandomFrame(newFrame, m_evenFrameDrawType, rnd);
514                 else
515                         generateRandomFrame(newFrame, m_oddFrameDrawType, rnd);
516
517                 frameSequence.push_back(newFrame);
518
519                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &currentBufferAge));
520
521                 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
522                 {
523                         std::ostringstream stream;
524                         stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
525                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
526                         return STOP;
527                 }
528
529                 bufferAges.push_back(currentBufferAge);
530                 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
531
532                 if (currentBufferAge > 0)
533                 {
534                         vector<EGLint>  damageRegion;
535
536                         hasPositiveAge = true;
537
538                         if (m_supportBufferAge)
539                         {
540                                 damageRegion = getDamageRegion(newFrame, 10, 10, 10, 10);
541                         }
542                         else
543                         {
544                                 damageRegion = getDamageRegion(newFrame, 0, 0, 0, 0);
545                                 // Set empty damage region to avoid invalidating the framebuffer. The damage area is invalidated
546                                 // if the buffer age extension is not supported.
547                                 if (damageRegion.size() == 0)
548                                         damageRegion = vector<EGLint>(4, 0);
549                         }
550
551                         EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
552                 }
553                 else
554                 {
555                         EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, NULL, 0));
556                         clearColorScreen(m_gl, clearColor);
557                 }
558
559                 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
560                 if (frameNdx < numFrames/2)
561                         m_gles2Renderer->render(width, height, newFrame);
562                 else // do verification in the second half
563                 {
564                         const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
565
566                         clearColorReference(&refBuffer, clearColor);
567
568                         for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
569                                 m_refRenderer->render(&refBuffer, frameSequence[*it]);
570
571                         m_gles2Renderer->render(width, height, newFrame);
572                         m_refRenderer->render(&refBuffer, newFrame);
573
574                         readPixels(m_gl, &currentBuffer);
575
576                         if (!compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx))
577                         {
578                                 string errorMessage("Fail, render result is wrong. Buffer age is ");
579                                 errorMessage += (m_supportBufferAge ? "supported" : "not supported");
580                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, errorMessage.c_str());
581                                 return STOP;
582                         }
583                 }
584                 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
585         }
586
587         if (!hasPositiveAge) // fraud behavior, pretend to support partial_update
588         {
589                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, claim to support partial_update but buffer age is always 0");
590                 return STOP;
591         }
592
593         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
594         return STOP;
595 }
596
597 string generateDrawTypeName (const vector<PartialUpdateTest::DrawType>& drawTypes)
598 {
599         std::ostringstream stream;
600         if (drawTypes.size() == 0)
601                 return string("_none");
602
603         for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
604         {
605                 if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
606                         stream << "_render";
607                 else if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
608                         stream << "_clear";
609                 else
610                         DE_ASSERT(false);
611         }
612         return stream.str();
613 }
614
615 string generateTestName (const vector<PartialUpdateTest::DrawType>& oddFrameDrawType, const vector<PartialUpdateTest::DrawType>& evenFrameDrawType)
616 {
617         return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
618 }
619
620 bool isWindow (const eglu::CandidateConfig& c)
621 {
622         return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
623 }
624
625 bool isES2Renderable (const eglu::CandidateConfig& c)
626 {
627         return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
628 }
629
630 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay)
631 {
632         eglu::FilterList filters;
633         filters << isWindow << isES2Renderable;
634         return eglu::chooseSingleConfig(egl, eglDisplay, filters);
635 }
636
637 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
638 {
639         gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
640         gl.clear(GL_COLOR_BUFFER_BIT);
641 }
642
643 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
644 {
645         tcu::clear(ref->getAccess(), clearColor);
646 }
647
648 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
649 {
650         gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
651 }
652
653 float windowToDeviceCoordinates (int x, int length)
654 {
655         return (2.0f * float(x) / float(length)) - 1.0f;
656 }
657
658 bool compareToReference (tcu::TestLog& log,      const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
659 {
660         std::ostringstream stream;
661         stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
662         return tcu::intThresholdPositionDeviationCompare(log, "partial update test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
663                                                                                                          tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
664 }
665
666 class RenderOutsideDamageRegion : public PartialUpdateTest
667 {
668 public:
669                                                                 RenderOutsideDamageRegion               (EglTestContext& eglTestCtx);
670         TestCase::IterateResult         iterate                                                 (void);
671 };
672
673 RenderOutsideDamageRegion::RenderOutsideDamageRegion (EglTestContext& eglTestCtx)
674         : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_outside_damage_region", "")
675 {
676 }
677
678 TestCase::IterateResult RenderOutsideDamageRegion::iterate (void)
679 {
680         de::Random                      rnd                             (m_seed);
681         const Library&          egl                             = m_eglTestCtx.getLibrary();
682         tcu::TestLog&           log                             = m_testCtx.getLog();
683         const int                       width                   = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
684         const int                       height                  = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
685         const float                     clearRed                = rnd.getFloat();
686         const float                     clearGreen              = rnd.getFloat();
687         const float                     clearBlue               = rnd.getFloat();
688         const tcu::Vec4         clearColor              (clearRed, clearGreen, clearBlue, 1.0f);
689         tcu::Surface            currentBuffer   (width, height);
690         tcu::Surface            refBuffer               (width, height);
691         Frame                           frame                   (width, height);
692
693         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
694
695         generateRandomFrame(frame, m_evenFrameDrawType, rnd);
696
697         {
698                 // render outside the region
699                 EGLint             bufferAge    = -1;
700                 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
701
702                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
703                 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
704                 clearColorScreen(m_gl, clearColor);
705                 m_gles2Renderer->render(width, height, frame);
706
707                 // next line will make the bug on Nexus 6 disappear
708                 // readPixels(m_gl, &currentBuffer);
709         }
710
711         EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
712
713         // render a new frame
714         clearColorScreen(m_gl, clearColor);
715         m_gles2Renderer->render(width, height, frame);
716         clearColorReference(&refBuffer, clearColor);
717         m_refRenderer->render(&refBuffer, frame);
718         readPixels(m_gl, &currentBuffer);
719
720         if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
721                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, fail to recover after rendering outside damageRegion");
722         else
723                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
724
725         return STOP;
726 }
727
728 class RenderBeforeSetDamageRegion : public PartialUpdateTest
729 {
730 public:
731                                                                 RenderBeforeSetDamageRegion             (EglTestContext& eglTestCtx);
732         TestCase::IterateResult         iterate                                                 (void);
733 };
734
735 RenderBeforeSetDamageRegion::RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx)
736         : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_before_set_damage_region", "")
737 {
738 }
739
740 TestCase::IterateResult RenderBeforeSetDamageRegion::iterate (void)
741 {
742         de::Random                      rnd                             (m_seed);
743         const Library&          egl                             = m_eglTestCtx.getLibrary();
744         tcu::TestLog&           log                             = m_testCtx.getLog();
745         const int                       width                   = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
746         const int                       height                  = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
747         const float                     clearRed                = rnd.getFloat();
748         const float                     clearGreen              = rnd.getFloat();
749         const float                     clearBlue               = rnd.getFloat();
750         const tcu::Vec4         clearColor              (clearRed, clearGreen, clearBlue, 1.0f);
751         tcu::Surface            currentBuffer   (width, height);
752         tcu::Surface            refBuffer               (width, height);
753         Frame                           frame                   (width, height);
754
755         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
756
757         generateRandomFrame(frame, m_evenFrameDrawType, rnd);
758
759         {
760                 // render before setDamageRegion
761                 EGLint             bufferAge    = -1;
762                 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
763
764                 m_gles2Renderer->render(width, height, frame);
765                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
766                 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
767
768                 // next line will make the bug on Nexus 6 disappear
769                 // readPixels(m_gl, &currentBuffer);
770         }
771
772         EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
773
774         // render a new frame
775         clearColorScreen(m_gl, clearColor);
776         m_gles2Renderer->render(width, height, frame);
777         clearColorReference(&refBuffer, clearColor);
778         m_refRenderer->render(&refBuffer, frame);
779         readPixels(m_gl, &currentBuffer);
780
781         if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
782                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
783         else
784                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
785
786         return STOP;
787 }
788
789 } // anonymous
790
791 PartialUpdateTests::PartialUpdateTests (EglTestContext& eglTestCtx)
792         : TestCaseGroup(eglTestCtx, "partial_update", "Partial update tests")
793 {
794 }
795
796 void PartialUpdateTests::init (void)
797 {
798         const PartialUpdateTest::DrawType clearRender[2] =
799         {
800                 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR,
801                 PartialUpdateTest::DRAWTYPE_GLES2_RENDER
802         };
803
804         const PartialUpdateTest::DrawType renderClear[2] =
805         {
806                 PartialUpdateTest::DRAWTYPE_GLES2_RENDER,
807                 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR
808         };
809
810         vector< vector<PartialUpdateTest::DrawType> > frameDrawTypes;
811         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> ());
812         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
813         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
814         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
815         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
816         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
817         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
818
819         for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
820         {
821                 const vector<PartialUpdateTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
822
823                 for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
824                 {
825                         const vector<PartialUpdateTest::DrawType>&      oddFrameDrawType = frameDrawTypes[oddNdx];
826                         const std::string                                                       name                     = generateTestName(oddFrameDrawType, evenFrameDrawType);
827                         if (oddFrameDrawType.size() == 0 && evenFrameDrawType.size() == 0)
828                                 continue;
829
830                         addChild(new PartialUpdateTest(m_eglTestCtx, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
831                 }
832         }
833         addChild(new RenderOutsideDamageRegion(m_eglTestCtx));
834         addChild(new RenderBeforeSetDamageRegion(m_eglTestCtx));
835 }
836
837 } // egl
838 } // deqp