Lower correlation threshold in flush-finish tests again am: 6455e6f987 am: 2e18b48b04...
[platform/upstream/VK-GL-CTS.git] / modules / egl / teglColorClearCase.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 Color clear case.
22  *//*--------------------------------------------------------------------*/
23
24 #include "teglColorClearCase.hpp"
25 #include "tcuTestLog.hpp"
26 #include "eglwLibrary.hpp"
27 #include "eglwEnums.hpp"
28 #include "egluUtil.hpp"
29 #include "deRandom.hpp"
30 #include "deString.h"
31 #include "tcuImageCompare.hpp"
32 #include "tcuVector.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuPixelFormat.hpp"
35 #include "glwFunctions.hpp"
36 #include "deThread.hpp"
37 #include "deSemaphore.hpp"
38 #include "deSharedPtr.hpp"
39 #include "teglGLES1RenderUtil.hpp"
40 #include "teglGLES2RenderUtil.hpp"
41 #include "teglVGRenderUtil.hpp"
42
43 #include <memory>
44 #include <iterator>
45
46 namespace deqp
47 {
48 namespace egl
49 {
50
51 using tcu::TestLog;
52 using tcu::RGBA;
53 using std::vector;
54 using namespace eglw;
55
56 // Utilities.
57
58 struct ClearOp
59 {
60         ClearOp (int x_, int y_, int width_, int height_, const tcu::RGBA& color_)
61                 : x                     (x_)
62                 , y                     (y_)
63                 , width         (width_)
64                 , height        (height_)
65                 , color         (color_)
66         {
67         }
68
69         ClearOp (void)
70                 : x                     (0)
71                 , y                     (0)
72                 , width         (0)
73                 , height        (0)
74                 , color         (0)
75         {
76         }
77
78         int                     x;
79         int                     y;
80         int                     width;
81         int                     height;
82         tcu::RGBA       color;
83 };
84
85 struct ApiFunctions
86 {
87         glw::Functions  gl;
88 };
89
90 static ClearOp computeRandomClear (de::Random& rnd, int width, int height)
91 {
92         int                     w               = rnd.getInt(1, width);
93         int                     h               = rnd.getInt(1, height);
94         int                     x               = rnd.getInt(0, width-w);
95         int                     y               = rnd.getInt(0, height-h);
96         tcu::RGBA       col             (rnd.getUint32());
97
98         return ClearOp(x, y, w, h, col);
99 }
100
101 static void renderReference (tcu::Surface& dst, const vector<ClearOp>& clears, const tcu::PixelFormat& pixelFormat)
102 {
103         for (vector<ClearOp>::const_iterator clearIter = clears.begin(); clearIter != clears.end(); clearIter++)
104         {
105                 tcu::PixelBufferAccess access = tcu::getSubregion(dst.getAccess(), clearIter->x, clearIter->y, 0, clearIter->width, clearIter->height, 1);
106                 tcu::clear(access, pixelFormat.convertColor(clearIter->color).toIVec());
107         }
108 }
109
110 static void renderClear (EGLint api, const ApiFunctions& func, const ClearOp& clear)
111 {
112         switch (api)
113         {
114                 case EGL_OPENGL_ES_BIT:                 gles1::clear(clear.x, clear.y, clear.width, clear.height, clear.color.toVec());                         break;
115                 case EGL_OPENGL_ES2_BIT:                gles2::clear(func.gl, clear.x, clear.y, clear.width, clear.height, clear.color.toVec());        break;
116                 case EGL_OPENGL_ES3_BIT_KHR:    gles2::clear(func.gl, clear.x, clear.y, clear.width, clear.height, clear.color.toVec());        break;
117                 case EGL_OPENVG_BIT:                    vg::clear       (clear.x, clear.y, clear.width, clear.height, clear.color.toVec());                             break;
118                 default:
119                         DE_ASSERT(DE_FALSE);
120         }
121 }
122
123 static void finish (EGLint api, const ApiFunctions& func)
124 {
125         switch (api)
126         {
127                 case EGL_OPENGL_ES_BIT:                 gles1::finish();                break;
128                 case EGL_OPENGL_ES2_BIT:                gles2::finish(func.gl); break;
129                 case EGL_OPENGL_ES3_BIT_KHR:    gles2::finish(func.gl); break;
130                 case EGL_OPENVG_BIT:                    vg::finish();                   break;
131                 default:
132                         DE_ASSERT(DE_FALSE);
133         }
134 }
135
136 static void readPixels (EGLint api, const ApiFunctions& func, tcu::Surface& dst)
137 {
138         switch (api)
139         {
140                 case EGL_OPENGL_ES_BIT:                 gles1::readPixels       (dst, 0, 0, dst.getWidth(), dst.getHeight());                   break;
141                 case EGL_OPENGL_ES2_BIT:                gles2::readPixels       (func.gl, dst, 0, 0, dst.getWidth(), dst.getHeight());  break;
142                 case EGL_OPENGL_ES3_BIT_KHR:    gles2::readPixels       (func.gl, dst, 0, 0, dst.getWidth(), dst.getHeight());  break;
143                 case EGL_OPENVG_BIT:                    vg::readPixels          (dst, 0, 0, dst.getWidth(), dst.getHeight());                   break;
144                 default:
145                         DE_ASSERT(DE_FALSE);
146         }
147 }
148
149 static tcu::PixelFormat getPixelFormat (const Library& egl, EGLDisplay display, EGLConfig config)
150 {
151         tcu::PixelFormat pixelFmt;
152
153         egl.getConfigAttrib(display, config, EGL_RED_SIZE,              &pixelFmt.redBits);
154         egl.getConfigAttrib(display, config, EGL_GREEN_SIZE,    &pixelFmt.greenBits);
155         egl.getConfigAttrib(display, config, EGL_BLUE_SIZE,             &pixelFmt.blueBits);
156         egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE,    &pixelFmt.alphaBits);
157
158         return pixelFmt;
159 }
160
161 // SingleThreadColorClearCase
162
163 SingleThreadColorClearCase::SingleThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
164         : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
165 {
166 }
167
168 void SingleThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
169 {
170         const Library&          egl                     = m_eglTestCtx.getLibrary();
171
172         const tcu::IVec2        surfaceSize     = eglu::getSurfaceSize(egl, display, surface);
173         const int                       width           = surfaceSize.x();
174         const int                       height          = surfaceSize.y();
175
176         TestLog&                        log                     = m_testCtx.getLog();
177
178         tcu::Surface            refFrame        (width, height);
179         tcu::Surface            frame           (width, height);
180         tcu::PixelFormat        pixelFmt        = getPixelFormat(egl, display, config.config);
181
182         de::Random                      rnd                     (deStringHash(getName()));
183         vector<ClearOp>         clears;
184         const int                       ctxClears       = 2;
185         const int                       numIters        = 3;
186
187         ApiFunctions            funcs;
188
189         m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0));
190
191         // Clear to black using first context.
192         {
193                 EGLint          api                     = contexts[0].first;
194                 EGLContext      context         = contexts[0].second;
195                 ClearOp         clear           (0, 0, width, height, RGBA::black());
196
197                 egl.makeCurrent(display, surface, surface, context);
198                 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
199
200                 renderClear(api, funcs, clear);
201                 finish(api, funcs);
202                 clears.push_back(clear);
203         }
204
205         // Render.
206         for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
207         {
208                 for (vector<std::pair<EGLint, EGLContext> >::const_iterator ctxIter = contexts.begin(); ctxIter != contexts.end(); ctxIter++)
209                 {
210                         EGLint          api                     = ctxIter->first;
211                         EGLContext      context         = ctxIter->second;
212
213                         egl.makeCurrent(display, surface, surface, context);
214                         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
215
216                         for (int clearNdx = 0; clearNdx < ctxClears; clearNdx++)
217                         {
218                                 ClearOp clear = computeRandomClear(rnd, width, height);
219
220                                 renderClear(api, funcs, clear);
221                                 clears.push_back(clear);
222                         }
223
224                         finish(api, funcs);
225                 }
226         }
227
228         // Read pixels using first context. \todo [pyry] Randomize?
229         {
230                 EGLint          api             = contexts[0].first;
231                 EGLContext      context = contexts[0].second;
232
233                 egl.makeCurrent(display, surface, surface, context);
234                 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
235
236                 readPixels(api, funcs, frame);
237         }
238
239         egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
240         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
241
242         // Render reference.
243         renderReference(refFrame, clears, pixelFmt);
244
245         // Compare images
246         {
247                 tcu::RGBA eps = pixelFmt.alphaBits == 1 ? RGBA(1,1,1,127) : RGBA(1,1,1,1);
248                 bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, eps + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
249
250                 if (!imagesOk)
251                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
252         }
253 }
254
255 // MultiThreadColorClearCase
256
257 enum
258 {
259         NUM_CLEARS_PER_PACKET   = 2 //!< Number of clears performed in one context activation in one thread.
260 };
261
262 class ColorClearThread;
263
264 typedef de::SharedPtr<ColorClearThread> ColorClearThreadSp;
265 typedef de::SharedPtr<de::Semaphore>    SemaphoreSp;
266
267 struct ClearPacket
268 {
269         ClearPacket (void)
270         {
271         }
272
273         ClearOp                 clears[NUM_CLEARS_PER_PACKET];
274         SemaphoreSp             wait;
275         SemaphoreSp             signal;
276 };
277
278 class ColorClearThread : public de::Thread
279 {
280 public:
281         ColorClearThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const ApiFunctions& funcs, const std::vector<ClearPacket>& packets)
282                 : m_egl         (egl)
283                 , m_display     (display)
284                 , m_surface     (surface)
285                 , m_context     (context)
286                 , m_api         (api)
287                 , m_funcs       (funcs)
288                 , m_packets     (packets)
289         {
290         }
291
292         void run (void)
293         {
294                 for (std::vector<ClearPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
295                 {
296                         // Wait until it is our turn.
297                         packetIter->wait->decrement();
298
299                         // Acquire context.
300                         m_egl.makeCurrent(m_display, m_surface, m_surface, m_context);
301
302                         // Execute clears.
303                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(packetIter->clears); ndx++)
304                                 renderClear(m_api, m_funcs, packetIter->clears[ndx]);
305
306                         finish(m_api, m_funcs);
307                         // Release context.
308                         m_egl.makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
309
310                         // Signal completion.
311                         packetIter->signal->increment();
312                 }
313         }
314
315 private:
316         const Library&                                  m_egl;
317         EGLDisplay                                              m_display;
318         EGLSurface                                              m_surface;
319         EGLContext                                              m_context;
320         EGLint                                                  m_api;
321         const ApiFunctions&                             m_funcs;
322         const std::vector<ClearPacket>& m_packets;
323 };
324
325 MultiThreadColorClearCase::MultiThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
326         : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
327 {
328 }
329
330 void MultiThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
331 {
332         const Library&          egl                     = m_eglTestCtx.getLibrary();
333
334         const tcu::IVec2        surfaceSize     = eglu::getSurfaceSize(egl, display, surface);
335         const int                       width           = surfaceSize.x();
336         const int                       height          = surfaceSize.y();
337
338         TestLog&                        log                     = m_testCtx.getLog();
339
340         tcu::Surface            refFrame        (width, height);
341         tcu::Surface            frame           (width, height);
342         tcu::PixelFormat        pixelFmt        = getPixelFormat(egl, display, config.config);
343
344         de::Random                      rnd                     (deStringHash(getName()));
345
346         ApiFunctions            funcs;
347
348         m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0));
349
350         // Create clear packets.
351         const int                                               numPacketsPerThread             = 2;
352         int                                                             numThreads                              = (int)contexts.size();
353         int                                                             numPackets                              = numThreads * numPacketsPerThread;
354
355         vector<SemaphoreSp>                             semaphores                              (numPackets+1);
356         vector<vector<ClearPacket> >    packets                                 (numThreads);
357         vector<ColorClearThreadSp>              threads                                 (numThreads);
358
359         // Initialize semaphores.
360         for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
361                 *sem = SemaphoreSp(new de::Semaphore(0));
362
363         // Create packets.
364         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
365         {
366                 packets[threadNdx].resize(numPacketsPerThread);
367
368                 for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
369                 {
370                         ClearPacket& packet = packets[threadNdx][packetNdx];
371
372                         // Threads take turns with packets.
373                         packet.wait             = semaphores[packetNdx*numThreads + threadNdx];
374                         packet.signal   = semaphores[packetNdx*numThreads + threadNdx + 1];
375
376                         for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
377                         {
378                                 // First clear is always full-screen black.
379                                 if (threadNdx == 0 && packetNdx == 0 && clearNdx == 0)
380                                         packet.clears[clearNdx] = ClearOp(0, 0, width, height, RGBA::black());
381                                 else
382                                         packet.clears[clearNdx] = computeRandomClear(rnd, width, height);
383                         }
384                 }
385         }
386
387         // Create and launch threads (actual rendering starts once first semaphore is signaled).
388         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
389         {
390                 threads[threadNdx] = ColorClearThreadSp(new ColorClearThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, funcs, packets[threadNdx]));
391                 threads[threadNdx]->start();
392         }
393
394         // Signal start and wait until complete.
395         semaphores.front()->increment();
396         semaphores.back()->decrement();
397
398         // Read pixels using first context. \todo [pyry] Randomize?
399         {
400                 EGLint          api             = contexts[0].first;
401                 EGLContext      context = contexts[0].second;
402
403                 egl.makeCurrent(display, surface, surface, context);
404                 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
405
406                 readPixels(api, funcs, frame);
407         }
408
409         egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
410         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
411
412         // Join threads.
413         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
414                 threads[threadNdx]->join();
415
416         // Render reference.
417         for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
418         {
419                 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
420                 {
421                         const ClearPacket& packet = packets[threadNdx][packetNdx];
422                         for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
423                         {
424                                 tcu::PixelBufferAccess access = tcu::getSubregion(refFrame.getAccess(),
425                                                                                                                                   packet.clears[clearNdx].x, packet.clears[clearNdx].y, 0,
426                                                                                                                                   packet.clears[clearNdx].width, packet.clears[clearNdx].height, 1);
427                                 tcu::clear(access, pixelFmt.convertColor(packet.clears[clearNdx].color).toIVec());
428                         }
429                 }
430         }
431
432         // Compare images
433         {
434                 tcu::RGBA eps = pixelFmt.alphaBits == 1 ? RGBA(1,1,1,127) : RGBA(1,1,1,1);
435                 bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, eps + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
436
437                 if (!imagesOk)
438                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
439         }
440 }
441
442 } // egl
443 } // deqp