Fix atomic ssbo xor test am: f0fa05e898 am: b426d8bfad am: 580f143209 am: 73a16f417e...
[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
508                 if (frameNdx % 2 == 0)
509                         generateRandomFrame(newFrame, m_evenFrameDrawType, rnd);
510                 else
511                         generateRandomFrame(newFrame, m_oddFrameDrawType, rnd);
512
513                 frameSequence.push_back(newFrame);
514
515                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &currentBufferAge));
516
517                 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
518                 {
519                         std::ostringstream stream;
520                         stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
521                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
522                         return STOP;
523                 }
524
525                 bufferAges.push_back(currentBufferAge);
526                 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
527
528                 if (currentBufferAge > 0)
529                 {
530                         vector<EGLint>  damageRegion;
531
532                         hasPositiveAge = true;
533
534                         if (m_supportBufferAge)
535                         {
536                                 damageRegion = getDamageRegion(newFrame, 10, 10, 10, 10);
537                         }
538                         else
539                         {
540                                 damageRegion = getDamageRegion(newFrame, 0, 0, 0, 0);
541                                 // Set empty damage region to avoid invalidating the framebuffer. The damage area is invalidated
542                                 // if the buffer age extension is not supported.
543                                 if (damageRegion.size() == 0)
544                                         damageRegion = vector<EGLint>(4, 0);
545                         }
546
547                         EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
548                 }
549                 else
550                 {
551                         EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, NULL, 0));
552                         clearColorScreen(m_gl, clearColor);
553                 }
554
555                 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
556                 if (frameNdx < numFrames/2)
557                         m_gles2Renderer->render(width, height, newFrame);
558                 else // do verification in the second half
559                 {
560                         const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
561
562                         clearColorReference(&refBuffer, clearColor);
563
564                         for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
565                                 m_refRenderer->render(&refBuffer, frameSequence[*it]);
566
567                         m_gles2Renderer->render(width, height, newFrame);
568                         m_refRenderer->render(&refBuffer, newFrame);
569
570                         readPixels(m_gl, &currentBuffer);
571
572                         if (!compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx))
573                         {
574                                 string errorMessage("Fail, render result is wrong. Buffer age is ");
575                                 errorMessage += (m_supportBufferAge ? "supported" : "not supported");
576                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, errorMessage.c_str());
577                                 return STOP;
578                         }
579                 }
580                 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
581         }
582
583         if (!hasPositiveAge) // fraud behavior, pretend to support partial_update
584         {
585                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, claim to support partial_update but buffer age is always 0");
586                 return STOP;
587         }
588
589         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
590         return STOP;
591 }
592
593 string generateDrawTypeName (const vector<PartialUpdateTest::DrawType>& drawTypes)
594 {
595         std::ostringstream stream;
596         if (drawTypes.size() == 0)
597                 return string("_none");
598
599         for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
600         {
601                 if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
602                         stream << "_render";
603                 else if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
604                         stream << "_clear";
605                 else
606                         DE_ASSERT(false);
607         }
608         return stream.str();
609 }
610
611 string generateTestName (const vector<PartialUpdateTest::DrawType>& oddFrameDrawType, const vector<PartialUpdateTest::DrawType>& evenFrameDrawType)
612 {
613         return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
614 }
615
616 bool isWindow (const eglu::CandidateConfig& c)
617 {
618         return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
619 }
620
621 bool isES2Renderable (const eglu::CandidateConfig& c)
622 {
623         return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
624 }
625
626 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay)
627 {
628         eglu::FilterList filters;
629         filters << isWindow << isES2Renderable;
630         return eglu::chooseSingleConfig(egl, eglDisplay, filters);
631 }
632
633 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
634 {
635         gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
636         gl.clear(GL_COLOR_BUFFER_BIT);
637 }
638
639 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
640 {
641         tcu::clear(ref->getAccess(), clearColor);
642 }
643
644 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
645 {
646         gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
647 }
648
649 float windowToDeviceCoordinates (int x, int length)
650 {
651         return (2.0f * float(x) / float(length)) - 1.0f;
652 }
653
654 bool compareToReference (tcu::TestLog& log,      const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
655 {
656         std::ostringstream stream;
657         stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
658         return tcu::intThresholdPositionDeviationCompare(log, "partial update test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
659                                                                                                          tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
660 }
661
662 class RenderOutsideDamageRegion : public PartialUpdateTest
663 {
664 public:
665                                                                 RenderOutsideDamageRegion               (EglTestContext& eglTestCtx);
666         TestCase::IterateResult         iterate                                                 (void);
667 };
668
669 RenderOutsideDamageRegion::RenderOutsideDamageRegion (EglTestContext& eglTestCtx)
670         : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_outside_damage_region", "")
671 {
672 }
673
674 TestCase::IterateResult RenderOutsideDamageRegion::iterate (void)
675 {
676         de::Random                      rnd                             (m_seed);
677         const Library&          egl                             = m_eglTestCtx.getLibrary();
678         tcu::TestLog&           log                             = m_testCtx.getLog();
679         const int                       width                   = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
680         const int                       height                  = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
681         const float                     clearRed                = rnd.getFloat();
682         const float                     clearGreen              = rnd.getFloat();
683         const float                     clearBlue               = rnd.getFloat();
684         const tcu::Vec4         clearColor              (clearRed, clearGreen, clearBlue, 1.0f);
685         tcu::Surface            currentBuffer   (width, height);
686         tcu::Surface            refBuffer               (width, height);
687         Frame                           frame                   (width, height);
688
689         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
690
691         generateRandomFrame(frame, m_evenFrameDrawType, rnd);
692
693         {
694                 // render outside the region
695                 EGLint             bufferAge    = -1;
696                 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
697
698                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
699                 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
700                 clearColorScreen(m_gl, clearColor);
701                 m_gles2Renderer->render(width, height, frame);
702
703                 // next line will make the bug on Nexus 6 disappear
704                 // readPixels(m_gl, &currentBuffer);
705         }
706
707         EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
708
709         // render a new frame
710         clearColorScreen(m_gl, clearColor);
711         m_gles2Renderer->render(width, height, frame);
712         clearColorReference(&refBuffer, clearColor);
713         m_refRenderer->render(&refBuffer, frame);
714         readPixels(m_gl, &currentBuffer);
715
716         if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
717                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, fail to recover after rendering outside damageRegion");
718         else
719                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
720
721         return STOP;
722 }
723
724 class RenderBeforeSetDamageRegion : public PartialUpdateTest
725 {
726 public:
727                                                                 RenderBeforeSetDamageRegion             (EglTestContext& eglTestCtx);
728         TestCase::IterateResult         iterate                                                 (void);
729 };
730
731 RenderBeforeSetDamageRegion::RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx)
732         : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_before_set_damage_region", "")
733 {
734 }
735
736 TestCase::IterateResult RenderBeforeSetDamageRegion::iterate (void)
737 {
738         de::Random                      rnd                             (m_seed);
739         const Library&          egl                             = m_eglTestCtx.getLibrary();
740         tcu::TestLog&           log                             = m_testCtx.getLog();
741         const int                       width                   = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
742         const int                       height                  = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
743         const float                     clearRed                = rnd.getFloat();
744         const float                     clearGreen              = rnd.getFloat();
745         const float                     clearBlue               = rnd.getFloat();
746         const tcu::Vec4         clearColor              (clearRed, clearGreen, clearBlue, 1.0f);
747         tcu::Surface            currentBuffer   (width, height);
748         tcu::Surface            refBuffer               (width, height);
749         Frame                           frame                   (width, height);
750
751         EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
752
753         generateRandomFrame(frame, m_evenFrameDrawType, rnd);
754
755         {
756                 // render before setDamageRegion
757                 EGLint             bufferAge    = -1;
758                 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
759
760                 m_gles2Renderer->render(width, height, frame);
761                 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
762                 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
763
764                 // next line will make the bug on Nexus 6 disappear
765                 // readPixels(m_gl, &currentBuffer);
766         }
767
768         EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
769
770         // render a new frame
771         clearColorScreen(m_gl, clearColor);
772         m_gles2Renderer->render(width, height, frame);
773         clearColorReference(&refBuffer, clearColor);
774         m_refRenderer->render(&refBuffer, frame);
775         readPixels(m_gl, &currentBuffer);
776
777         if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
778                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
779         else
780                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
781
782         return STOP;
783 }
784
785 } // anonymous
786
787 PartialUpdateTests::PartialUpdateTests (EglTestContext& eglTestCtx)
788         : TestCaseGroup(eglTestCtx, "partial_update", "Partial update tests")
789 {
790 }
791
792 void PartialUpdateTests::init (void)
793 {
794         const PartialUpdateTest::DrawType clearRender[2] =
795         {
796                 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR,
797                 PartialUpdateTest::DRAWTYPE_GLES2_RENDER
798         };
799
800         const PartialUpdateTest::DrawType renderClear[2] =
801         {
802                 PartialUpdateTest::DRAWTYPE_GLES2_RENDER,
803                 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR
804         };
805
806         vector< vector<PartialUpdateTest::DrawType> > frameDrawTypes;
807         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> ());
808         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
809         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
810         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
811         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
812         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
813         frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
814
815         for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
816         {
817                 const vector<PartialUpdateTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
818
819                 for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
820                 {
821                         const vector<PartialUpdateTest::DrawType>&      oddFrameDrawType = frameDrawTypes[oddNdx];
822                         const std::string                                                       name                     = generateTestName(oddFrameDrawType, evenFrameDrawType);
823                         if (oddFrameDrawType.size() == 0 && evenFrameDrawType.size() == 0)
824                                 continue;
825
826                         addChild(new PartialUpdateTest(m_eglTestCtx, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
827                 }
828         }
829         addChild(new RenderOutsideDamageRegion(m_eglTestCtx));
830         addChild(new RenderBeforeSetDamageRegion(m_eglTestCtx));
831 }
832
833 } // egl
834 } // deqp