Fix sample_mask_in.bit_count_per_two_samples tests for 2x MSAA.
[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                 bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, RGBA(1,1,1,1) + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
248
249                 if (!imagesOk)
250                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
251         }
252 }
253
254 // MultiThreadColorClearCase
255
256 enum
257 {
258         NUM_CLEARS_PER_PACKET   = 2 //!< Number of clears performed in one context activation in one thread.
259 };
260
261 class ColorClearThread;
262
263 typedef de::SharedPtr<ColorClearThread> ColorClearThreadSp;
264 typedef de::SharedPtr<de::Semaphore>    SemaphoreSp;
265
266 struct ClearPacket
267 {
268         ClearPacket (void)
269         {
270         }
271
272         ClearOp                 clears[NUM_CLEARS_PER_PACKET];
273         SemaphoreSp             wait;
274         SemaphoreSp             signal;
275 };
276
277 class ColorClearThread : public de::Thread
278 {
279 public:
280         ColorClearThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const ApiFunctions& funcs, const std::vector<ClearPacket>& packets)
281                 : m_egl         (egl)
282                 , m_display     (display)
283                 , m_surface     (surface)
284                 , m_context     (context)
285                 , m_api         (api)
286                 , m_funcs       (funcs)
287                 , m_packets     (packets)
288         {
289         }
290
291         void run (void)
292         {
293                 for (std::vector<ClearPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
294                 {
295                         // Wait until it is our turn.
296                         packetIter->wait->decrement();
297
298                         // Acquire context.
299                         m_egl.makeCurrent(m_display, m_surface, m_surface, m_context);
300
301                         // Execute clears.
302                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(packetIter->clears); ndx++)
303                                 renderClear(m_api, m_funcs, packetIter->clears[ndx]);
304
305                         finish(m_api, m_funcs);
306                         // Release context.
307                         m_egl.makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
308
309                         // Signal completion.
310                         packetIter->signal->increment();
311                 }
312         }
313
314 private:
315         const Library&                                  m_egl;
316         EGLDisplay                                              m_display;
317         EGLSurface                                              m_surface;
318         EGLContext                                              m_context;
319         EGLint                                                  m_api;
320         const ApiFunctions&                             m_funcs;
321         const std::vector<ClearPacket>& m_packets;
322 };
323
324 MultiThreadColorClearCase::MultiThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
325         : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
326 {
327 }
328
329 void MultiThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
330 {
331         const Library&          egl                     = m_eglTestCtx.getLibrary();
332
333         const tcu::IVec2        surfaceSize     = eglu::getSurfaceSize(egl, display, surface);
334         const int                       width           = surfaceSize.x();
335         const int                       height          = surfaceSize.y();
336
337         TestLog&                        log                     = m_testCtx.getLog();
338
339         tcu::Surface            refFrame        (width, height);
340         tcu::Surface            frame           (width, height);
341         tcu::PixelFormat        pixelFmt        = getPixelFormat(egl, display, config.config);
342
343         de::Random                      rnd                     (deStringHash(getName()));
344
345         ApiFunctions            funcs;
346
347         m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0));
348
349         // Create clear packets.
350         const int                                               numPacketsPerThread             = 2;
351         int                                                             numThreads                              = (int)contexts.size();
352         int                                                             numPackets                              = numThreads * numPacketsPerThread;
353
354         vector<SemaphoreSp>                             semaphores                              (numPackets+1);
355         vector<vector<ClearPacket> >    packets                                 (numThreads);
356         vector<ColorClearThreadSp>              threads                                 (numThreads);
357
358         // Initialize semaphores.
359         for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
360                 *sem = SemaphoreSp(new de::Semaphore(0));
361
362         // Create packets.
363         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
364         {
365                 packets[threadNdx].resize(numPacketsPerThread);
366
367                 for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
368                 {
369                         ClearPacket& packet = packets[threadNdx][packetNdx];
370
371                         // Threads take turns with packets.
372                         packet.wait             = semaphores[packetNdx*numThreads + threadNdx];
373                         packet.signal   = semaphores[packetNdx*numThreads + threadNdx + 1];
374
375                         for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
376                         {
377                                 // First clear is always full-screen black.
378                                 if (threadNdx == 0 && packetNdx == 0 && clearNdx == 0)
379                                         packet.clears[clearNdx] = ClearOp(0, 0, width, height, RGBA::black());
380                                 else
381                                         packet.clears[clearNdx] = computeRandomClear(rnd, width, height);
382                         }
383                 }
384         }
385
386         // Create and launch threads (actual rendering starts once first semaphore is signaled).
387         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
388         {
389                 threads[threadNdx] = ColorClearThreadSp(new ColorClearThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, funcs, packets[threadNdx]));
390                 threads[threadNdx]->start();
391         }
392
393         // Signal start and wait until complete.
394         semaphores.front()->increment();
395         semaphores.back()->decrement();
396
397         // Read pixels using first context. \todo [pyry] Randomize?
398         {
399                 EGLint          api             = contexts[0].first;
400                 EGLContext      context = contexts[0].second;
401
402                 egl.makeCurrent(display, surface, surface, context);
403                 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
404
405                 readPixels(api, funcs, frame);
406         }
407
408         egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
409         EGLU_CHECK_MSG(egl, "eglMakeCurrent");
410
411         // Join threads.
412         for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
413                 threads[threadNdx]->join();
414
415         // Render reference.
416         for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
417         {
418                 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
419                 {
420                         const ClearPacket& packet = packets[threadNdx][packetNdx];
421                         for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
422                         {
423                                 tcu::PixelBufferAccess access = tcu::getSubregion(refFrame.getAccess(),
424                                                                                                                                   packet.clears[clearNdx].x, packet.clears[clearNdx].y, 0,
425                                                                                                                                   packet.clears[clearNdx].width, packet.clears[clearNdx].height, 1);
426                                 tcu::clear(access, pixelFmt.convertColor(packet.clears[clearNdx].color).toIVec());
427                         }
428                 }
429         }
430
431         // Compare images
432         {
433                 bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, RGBA(1,1,1,1) + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
434
435                 if (!imagesOk)
436                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
437         }
438 }
439
440 } // egl
441 } // deqp