Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / modules / egl / teglResizeTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program EGL Module
3  * ---------------------------------------
4  *
5  * Copyright 2014 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 Tests for resizing the native window of a surface.
22  *//*--------------------------------------------------------------------*/
23
24 #include "teglResizeTests.hpp"
25
26 #include "teglSimpleConfigCase.hpp"
27
28 #include "tcuImageCompare.hpp"
29 #include "tcuSurface.hpp"
30 #include "tcuPlatform.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuInterval.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuResultCollector.hpp"
35
36 #include "egluNativeDisplay.hpp"
37 #include "egluNativeWindow.hpp"
38 #include "egluNativePixmap.hpp"
39 #include "egluUnique.hpp"
40 #include "egluUtil.hpp"
41
42 #include "eglwLibrary.hpp"
43 #include "eglwEnums.hpp"
44
45 #include "gluDefs.hpp"
46 #include "glwFunctions.hpp"
47 #include "glwEnums.hpp"
48
49 #include "tcuTestLog.hpp"
50 #include "tcuVector.hpp"
51
52 #include "deThread.h"
53 #include "deUniquePtr.hpp"
54
55 #include <sstream>
56
57 namespace deqp
58 {
59 namespace egl
60 {
61
62 using std::vector;
63 using std::string;
64 using std::ostringstream;
65 using de::MovePtr;
66 using tcu::CommandLine;
67 using tcu::ConstPixelBufferAccess;
68 using tcu::Interval;
69 using tcu::IVec2;
70 using tcu::Vec3;
71 using tcu::Vec4;
72 using tcu::UVec4;
73 using tcu::ResultCollector;
74 using tcu::Surface;
75 using tcu::TestLog;
76 using eglu::AttribMap;
77 using eglu::NativeDisplay;
78 using eglu::NativeWindow;
79 using eglu::ScopedCurrentContext;
80 using eglu::UniqueSurface;
81 using eglu::UniqueContext;
82 using eglu::NativeWindowFactory;
83 using eglu::WindowParams;
84 using namespace eglw;
85
86 typedef eglu::WindowParams::Visibility  Visibility;
87 typedef TestCase::IterateResult                 IterateResult;
88
89 struct ResizeParams
90 {
91         string  name;
92         string  description;
93         IVec2   oldSize;
94         IVec2   newSize;
95 };
96
97 class ResizeTest : public TestCase
98 {
99 public:
100                                                                 ResizeTest      (EglTestContext&                eglTestCtx,
101                                                                                          const ResizeParams&    params)
102                                                                         : TestCase      (eglTestCtx,
103                                                                                                  params.name.c_str(),
104                                                                                                  params.description.c_str())
105                                                                         , m_oldSize     (params.oldSize)
106                                                                         , m_newSize     (params.newSize)
107                                                                         , m_display     (EGL_NO_DISPLAY)
108                                                                         , m_config      (DE_NULL)
109                                                                         , m_log         (m_testCtx.getLog())
110                                                                         , m_status      (m_log) {}
111
112         void                                            init            (void);
113         void                                            deinit          (void);
114
115 protected:
116         virtual EGLenum                         surfaceType     (void) const { return EGL_WINDOW_BIT; }
117         void                                            resize          (IVec2 size);
118
119         const IVec2                                     m_oldSize;
120         const IVec2                                     m_newSize;
121         EGLDisplay                                      m_display;
122         EGLConfig                                       m_config;
123         MovePtr<NativeWindow>           m_nativeWindow;
124         MovePtr<UniqueSurface>          m_surface;
125         MovePtr<UniqueContext>          m_context;
126         TestLog&                                        m_log;
127         ResultCollector                         m_status;
128         glw::Functions                          m_gl;
129 };
130
131 EGLConfig getEGLConfig (const Library& egl, const EGLDisplay eglDisplay, EGLenum surfaceType)
132 {
133         AttribMap attribMap;
134
135         attribMap[EGL_SURFACE_TYPE]             = surfaceType;
136         attribMap[EGL_RENDERABLE_TYPE]  = EGL_OPENGL_ES2_BIT;
137
138         return eglu::chooseSingleConfig(egl, eglDisplay, attribMap);
139 }
140
141 void ResizeTest::init (void)
142 {
143         TestCase::init();
144
145         const Library&                          egl                             = m_eglTestCtx.getLibrary();
146         const CommandLine&                      cmdLine                 = m_testCtx.getCommandLine();
147         const EGLDisplay                        eglDisplay              = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
148         const EGLConfig                         eglConfig               = getEGLConfig(egl, eglDisplay, surfaceType());
149         const EGLint                            ctxAttribs[]    =
150         {
151                 EGL_CONTEXT_CLIENT_VERSION, 2,
152                 EGL_NONE
153         };
154         EGLContext                                      eglContext              = egl.createContext(eglDisplay,
155                                                                                                                                    eglConfig,
156                                                                                                                                    EGL_NO_CONTEXT,
157                                                                                                                                    ctxAttribs);
158         EGLU_CHECK_MSG(egl, "eglCreateContext()");
159         MovePtr<UniqueContext>          context                 (new UniqueContext(egl, eglDisplay, eglContext));
160         const EGLint                            configId                = eglu::getConfigAttribInt(egl,
161                                                                                                                                                    eglDisplay,
162                                                                                                                                                    eglConfig,
163                                                                                                                                                    EGL_CONFIG_ID);
164         const Visibility                        visibility              = eglu::parseWindowVisibility(cmdLine);
165         NativeDisplay&                          nativeDisplay   = m_eglTestCtx.getNativeDisplay();
166         const NativeWindowFactory&      windowFactory   = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(),
167                                                                                                                                                                   cmdLine);
168
169         const WindowParams                      windowParams    (m_oldSize.x(), m_oldSize.y(), visibility);
170         MovePtr<NativeWindow>           nativeWindow    (windowFactory.createWindow(&nativeDisplay,
171                                                                                                                                                          eglDisplay,
172                                                                                                                                                          eglConfig,
173                                                                                                                                                          DE_NULL,
174                                                                                                                                                          windowParams));
175         const EGLSurface                        eglSurface              = eglu::createWindowSurface(nativeDisplay,
176                                                                                                                                                         *nativeWindow,
177                                                                                                                                                         eglDisplay,
178                                                                                                                                                         eglConfig,
179                                                                                                                                                         DE_NULL);
180         MovePtr<UniqueSurface>          surface                 (new UniqueSurface(egl, eglDisplay, eglSurface));
181
182         m_log << TestLog::Message
183                   << "Chose EGLConfig with id " << configId << ".\n"
184                   << "Created initial surface with size " << m_oldSize
185                   << TestLog::EndMessage;
186
187         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2, 0));
188         m_config                = eglConfig;
189         m_surface               = surface;
190         m_context               = context;
191         m_display               = eglDisplay;
192         m_nativeWindow  = nativeWindow;
193         EGLU_CHECK_MSG(egl, "init");
194 }
195
196 void ResizeTest::deinit (void)
197 {
198         m_config                = DE_NULL;
199         m_context.clear();
200         m_surface.clear();
201         m_nativeWindow.clear();
202
203         if (m_display != EGL_NO_DISPLAY)
204         {
205                 m_eglTestCtx.getLibrary().terminate(m_display);
206                 m_display       = EGL_NO_DISPLAY;
207         }
208 }
209
210 void ResizeTest::resize (IVec2 size)
211 {
212         m_nativeWindow->setSurfaceSize(size);
213         m_testCtx.getPlatform().processEvents();
214         m_log << TestLog::Message
215                   << "Resized surface to size " << size
216                   << TestLog::EndMessage;
217 }
218
219 class ChangeSurfaceSizeCase : public ResizeTest
220 {
221 public:
222                                         ChangeSurfaceSizeCase   (EglTestContext&                eglTestCtx,
223                                                                                          const ResizeParams&    params)
224                                                 : ResizeTest(eglTestCtx, params) {}
225
226         IterateResult   iterate                                 (void);
227 };
228
229 void drawRectangle (const glw::Functions& gl, IVec2 pos, IVec2 size, Vec3 color)
230 {
231         gl.clearColor(color.x(), color.y(), color.z(), 1.0);
232         gl.scissor(pos.x(), pos.y(), size.x(), size.y());
233         gl.enable(GL_SCISSOR_TEST);
234         gl.clear(GL_COLOR_BUFFER_BIT);
235         gl.disable(GL_SCISSOR_TEST);
236         GLU_EXPECT_NO_ERROR(gl.getError(),
237                                                 "Rectangle drawing with glScissor and glClear failed.");
238 }
239
240 void initSurface (const glw::Functions& gl, IVec2 oldSize)
241 {
242         const Vec3      frameColor      (0.0f, 0.0f, 1.0f);
243         const Vec3      fillColor       (1.0f, 0.0f, 0.0f);
244         const Vec3      markColor       (0.0f, 1.0f, 0.0f);
245
246         drawRectangle(gl, IVec2(0, 0), oldSize, frameColor);
247         drawRectangle(gl, IVec2(2, 2), oldSize - IVec2(4, 4), fillColor);
248
249         drawRectangle(gl, IVec2(0, 0), IVec2(8, 4), markColor);
250         drawRectangle(gl, oldSize - IVec2(16, 16), IVec2(8, 4), markColor);
251         drawRectangle(gl, IVec2(0, oldSize.y() - 16), IVec2(8, 4), markColor);
252         drawRectangle(gl, IVec2(oldSize.x() - 16, 0), IVec2(8, 4), markColor);
253 }
254
255 bool compareRectangles (const ConstPixelBufferAccess& rectA,
256                                                 const ConstPixelBufferAccess& rectB)
257 {
258         const int width         = rectA.getWidth();
259         const int height        = rectA.getHeight();
260         const int depth         = rectA.getDepth();
261
262         if (rectB.getWidth() != width || rectB.getHeight() != height || rectB.getDepth() != depth)
263                 return false;
264
265         for (int z = 0; z < depth; ++z)
266                 for (int y = 0; y < height; ++y)
267                         for (int x = 0; x < width; ++x)
268                                 if (rectA.getPixel(x, y, z) != rectB.getPixel(x, y, z))
269                                         return false;
270
271         return true;
272 }
273
274 // Check whether `oldSurface` and `newSurface` share a common corner.
275 bool compareCorners (const Surface& oldSurface, const Surface& newSurface)
276 {
277         const int       oldWidth        = oldSurface.getWidth();
278         const int       oldHeight       = oldSurface.getHeight();
279         const int       newWidth        = newSurface.getWidth();
280         const int       newHeight       = newSurface.getHeight();
281         const int       minWidth        = de::min(oldWidth, newWidth);
282         const int       minHeight       = de::min(oldHeight, newHeight);
283
284         for (int xCorner = 0; xCorner < 2; ++xCorner)
285         {
286                 const int oldX = xCorner == 0 ? 0 : oldWidth - minWidth;
287                 const int newX = xCorner == 0 ? 0 : newWidth - minWidth;
288
289                 for (int yCorner = 0; yCorner < 2; ++yCorner)
290                 {
291                         const int                               oldY            = yCorner == 0 ? 0 : oldHeight - minHeight;
292                         const int                               newY            = yCorner == 0 ? 0 : newHeight - minHeight;
293                         ConstPixelBufferAccess  oldAccess       =
294                                 getSubregion(oldSurface.getAccess(), oldX, oldY, minWidth, minHeight);
295                         ConstPixelBufferAccess  newAccess       =
296                                 getSubregion(newSurface.getAccess(), newX, newY, minWidth, minHeight);
297
298                         if (compareRectangles(oldAccess, newAccess))
299                                 return true;
300                 }
301         }
302
303         return false;
304 }
305
306 Surface readSurface (const glw::Functions& gl, IVec2 size)
307 {
308         Surface ret (size.x(), size.y());
309         gl.readPixels(0, 0, size.x(), size.y(), GL_RGBA, GL_UNSIGNED_BYTE,
310                                   ret.getAccess().getDataPtr());
311
312         GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed");
313         return ret;
314 }
315
316 template <typename T>
317 inline bool hasBits (T bitSet, T requiredBits)
318 {
319         return (bitSet & requiredBits) == requiredBits;
320 }
321
322 IVec2 getNativeSurfaceSize (const NativeWindow& nativeWindow,
323                                                         IVec2                           reqSize)
324 {
325         if (hasBits(nativeWindow.getCapabilities(), NativeWindow::CAPABILITY_GET_SURFACE_SIZE))
326                 return nativeWindow.getSurfaceSize();
327         return reqSize; // assume we got the requested size
328 }
329
330 IVec2 checkSurfaceSize (const Library&          egl,
331                                                 EGLDisplay                      eglDisplay,
332                                                 EGLSurface                      eglSurface,
333                                                 const NativeWindow&     nativeWindow,
334                                                 IVec2                           reqSize,
335                                                 ResultCollector&        status)
336 {
337         const IVec2             nativeSize      = getNativeSurfaceSize(nativeWindow, reqSize);
338         IVec2                   eglSize         = eglu::getSurfaceSize(egl, eglDisplay, eglSurface);
339         ostringstream   oss;
340
341         oss << "Size of EGL surface " << eglSize
342                 << " differs from size of native window " << nativeSize;
343         status.check(eglSize == nativeSize, oss.str());
344
345         return eglSize;
346 }
347
348 IterateResult ChangeSurfaceSizeCase::iterate (void)
349 {
350         const Library&                  egl                     = m_eglTestCtx.getLibrary();
351         ScopedCurrentContext    currentCtx      (egl, m_display, **m_surface, **m_surface, **m_context);
352         egl.swapBuffers(m_display, **m_surface);
353         IVec2                                   oldEglSize      = checkSurfaceSize(egl,
354                                                                                                                    m_display,
355                                                                                                                    **m_surface,
356                                                                                                                    *m_nativeWindow,
357                                                                                                                    m_oldSize,
358                                                                                                                    m_status);
359
360         initSurface(m_gl, oldEglSize);
361
362         this->resize(m_newSize);
363
364         egl.swapBuffers(m_display, **m_surface);
365         EGLU_CHECK_MSG(egl, "eglSwapBuffers()");
366         checkSurfaceSize(egl, m_display, **m_surface, *m_nativeWindow, m_newSize, m_status);
367
368         m_status.setTestContextResult(m_testCtx);
369         return STOP;
370 }
371
372 class PreserveBackBufferCase : public ResizeTest
373 {
374 public:
375                                         PreserveBackBufferCase  (EglTestContext&                eglTestCtx,
376                                                                                          const ResizeParams&    params)
377                                                 : ResizeTest(eglTestCtx, params) {}
378
379         IterateResult   iterate                                 (void);
380         EGLenum                 surfaceType                             (void) const;
381 };
382
383 EGLenum PreserveBackBufferCase::surfaceType (void) const
384 {
385         return EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
386 }
387
388 IterateResult PreserveBackBufferCase::iterate (void)
389 {
390         const Library&                  egl                     = m_eglTestCtx.getLibrary();
391         ScopedCurrentContext    currentCtx      (egl, m_display, **m_surface, **m_surface, **m_context);
392
393         EGLU_CHECK_CALL(egl, surfaceAttrib(m_display, **m_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
394
395         GLU_EXPECT_NO_ERROR(m_gl.getError(), "GL state erroneous upon initialization!");
396
397         {
398                 const IVec2 oldEglSize = eglu::getSurfaceSize(egl, m_display, **m_surface);
399                 initSurface(m_gl, oldEglSize);
400
401                 m_gl.finish();
402                 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFinish() failed");
403
404                 {
405                         const Surface oldSurface = readSurface(m_gl, oldEglSize);
406
407                         egl.swapBuffers(m_display, **m_surface);
408                         this->resize(m_newSize);
409                         egl.swapBuffers(m_display, **m_surface);
410                         EGLU_CHECK_MSG(egl, "eglSwapBuffers()");
411
412                         {
413                                 const IVec2             newEglSize      = eglu::getSurfaceSize(egl, m_display, **m_surface);
414                                 const Surface   newSurface      = readSurface(m_gl, newEglSize);
415
416                                 m_log << TestLog::ImageSet("Corner comparison",
417                                                                                    "Comparing old and new surfaces at all corners")
418                                           << TestLog::Image("Before resizing", "Before resizing", oldSurface)
419                                           << TestLog::Image("After resizing", "After resizing", newSurface)
420                                           << TestLog::EndImageSet;
421
422                                 m_status.checkResult(compareCorners(oldSurface, newSurface),
423                                                                          QP_TEST_RESULT_QUALITY_WARNING,
424                                                                          "Resizing the native window changed the contents of "
425                                                                          "the EGL surface");
426                         }
427                 }
428         }
429
430         m_status.setTestContextResult(m_testCtx);
431         return STOP;
432 }
433
434 typedef tcu::Vector<Interval, 2> IvVec2;
435
436 class UpdateResolutionCase : public ResizeTest
437 {
438 public:
439                                         UpdateResolutionCase    (EglTestContext&                eglTestCtx,
440                                                                                          const ResizeParams&    params)
441                                                 : ResizeTest(eglTestCtx, params) {}
442
443         IterateResult   iterate                                 (void);
444
445 private:
446         IvVec2                  getNativePixelsPerInch  (void);
447 };
448
449 IvVec2 ivVec2 (const IVec2& vec)
450 {
451         return IvVec2(double(vec.x()), double(vec.y()));
452 }
453
454 Interval approximateInt (int i)
455 {
456         const Interval margin(-1.0, 1.0); // The resolution may be rounded
457
458         return (Interval(i) + margin) & Interval(0.0, TCU_INFINITY);
459 }
460
461 IvVec2 UpdateResolutionCase::getNativePixelsPerInch     (void)
462 {
463         const Library&  egl                     = m_eglTestCtx.getLibrary();
464         const int               inchPer10km     = 254 * EGL_DISPLAY_SCALING;
465         const IVec2             bufSize         = eglu::getSurfaceSize(egl, m_display, **m_surface);
466         const IVec2             winSize         = m_nativeWindow->getScreenSize();
467         const IVec2             bufPp10km       = eglu::getSurfaceResolution(egl, m_display, **m_surface);
468         const IvVec2    bufPpiI         = (IvVec2(approximateInt(bufPp10km.x()),
469                                                                                   approximateInt(bufPp10km.y()))
470                                                                    / Interval(inchPer10km));
471         const IvVec2    winPpiI         = ivVec2(winSize) * bufPpiI / ivVec2(bufSize);
472         const IVec2             winPpi          (int(winPpiI.x().midpoint()), int(winPpiI.y().midpoint()));
473
474         m_log << TestLog::Message
475                   << "EGL surface size: "                                                       << bufSize              << "\n"
476                   << "EGL surface pixel density (pixels / 10 km): "     << bufPp10km    << "\n"
477                   << "Native window size: "                                                     << winSize              << "\n"
478                   << "Native pixel density (ppi): "                                     << winPpi               << "\n"
479                   << TestLog::EndMessage;
480
481         m_status.checkResult(bufPp10km.x() >= 1 && bufPp10km.y() >= 1,
482                                                  QP_TEST_RESULT_QUALITY_WARNING,
483                                                  "Surface pixel density is less than one pixel per 10 km. "
484                                                  "Is the surface really visible from space?");
485
486         return winPpiI;
487 }
488
489 IterateResult UpdateResolutionCase::iterate (void)
490 {
491         const Library&                  egl                     = m_eglTestCtx.getLibrary();
492         ScopedCurrentContext    currentCtx      (egl, m_display, **m_surface, **m_surface, **m_context);
493
494         if (!hasBits(m_nativeWindow->getCapabilities(),
495                                  NativeWindow::CAPABILITY_GET_SCREEN_SIZE))
496                 TCU_THROW(NotSupportedError, "Unable to determine surface size in screen pixels");
497
498         {
499                 const IVec2 oldEglSize = eglu::getSurfaceSize(egl, m_display, **m_surface);
500                 initSurface(m_gl, oldEglSize);
501         }
502         {
503                 const IvVec2 oldPpi = this->getNativePixelsPerInch();
504                 this->resize(m_newSize);
505                 EGLU_CHECK_CALL(egl, swapBuffers(m_display, **m_surface));
506                 {
507                         const IvVec2 newPpi = this->getNativePixelsPerInch();
508                         m_status.check(oldPpi.x().intersects(newPpi.x()) &&
509                                                    oldPpi.y().intersects(newPpi.y()),
510                                                    "Window PPI differs after resizing");
511                 }
512         }
513
514         m_status.setTestContextResult(m_testCtx);
515         return STOP;
516 }
517
518 ResizeTests::ResizeTests (EglTestContext& eglTestCtx)
519         : TestCaseGroup(eglTestCtx, "resize", "Tests resizing the native surface")
520 {
521 }
522
523 template <class Case>
524 TestCaseGroup* createCaseGroup(EglTestContext&  eglTestCtx,
525                                                            const string&        name,
526                                                            const string&        desc)
527 {
528         const ResizeParams              params[]        =
529         {
530                 { "shrink",                     "Shrink in both dimensions",
531                   IVec2(128, 128),      IVec2(32, 32) },
532                 { "grow",                       "Grow in both dimensions",
533                   IVec2(32, 32),        IVec2(128, 128) },
534                 { "stretch_width",      "Grow horizontally, shrink vertically",
535                   IVec2(32, 128),       IVec2(128, 32) },
536                 { "stretch_height",     "Grow vertically, shrink horizontally",
537                   IVec2(128, 32),       IVec2(32, 128) },
538         };
539         TestCaseGroup* const    group           =
540                 new TestCaseGroup(eglTestCtx, name.c_str(), desc.c_str());
541
542         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(params); ++ndx)
543                 group->addChild(new Case(eglTestCtx, params[ndx]));
544
545         return group;
546 }
547
548 void ResizeTests::init (void)
549 {
550         addChild(createCaseGroup<ChangeSurfaceSizeCase>(m_eglTestCtx,
551                                                                                                         "surface_size",
552                                                                                                         "EGL surface size update"));
553         addChild(createCaseGroup<PreserveBackBufferCase>(m_eglTestCtx,
554                                                                                                          "back_buffer",
555                                                                                                          "Back buffer contents"));
556         addChild(createCaseGroup<UpdateResolutionCase>(m_eglTestCtx,
557                                                                                                    "pixel_density",
558                                                                                                    "Pixel density"));
559 }
560
561 } // egl
562 } // deqp