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