1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program EGL Module
3 * ---------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Color clear case.
22 *//*--------------------------------------------------------------------*/
24 #include "teglColorClearCase.hpp"
25 #include "tcuTestLog.hpp"
26 #include "eglwLibrary.hpp"
27 #include "eglwEnums.hpp"
28 #include "egluUtil.hpp"
29 #include "deRandom.hpp"
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"
60 ClearOp (int x_, int y_, int width_, int height_, const tcu::RGBA& color_)
90 static ClearOp computeRandomClear (de::Random& rnd, int width, int height)
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());
98 return ClearOp(x, y, w, h, col);
101 static void renderReference (tcu::Surface& dst, const vector<ClearOp>& clears, const tcu::PixelFormat& pixelFormat)
103 for (vector<ClearOp>::const_iterator clearIter = clears.begin(); clearIter != clears.end(); clearIter++)
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());
110 static void renderClear (EGLint api, const ApiFunctions& func, const ClearOp& clear)
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;
123 static void finish (EGLint api, const ApiFunctions& func)
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;
136 static void readPixels (EGLint api, const ApiFunctions& func, tcu::Surface& dst)
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;
149 static tcu::PixelFormat getPixelFormat (const Library& egl, EGLDisplay display, EGLConfig config)
151 tcu::PixelFormat pixelFmt;
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);
161 // SingleThreadColorClearCase
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)
168 void SingleThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
170 const Library& egl = m_eglTestCtx.getLibrary();
172 const tcu::IVec2 surfaceSize = eglu::getSurfaceSize(egl, display, surface);
173 const int width = surfaceSize.x();
174 const int height = surfaceSize.y();
176 TestLog& log = m_testCtx.getLog();
178 tcu::Surface refFrame (width, height);
179 tcu::Surface frame (width, height);
180 tcu::PixelFormat pixelFmt = getPixelFormat(egl, display, config.config);
182 de::Random rnd (deStringHash(getName()));
183 vector<ClearOp> clears;
184 const int ctxClears = 2;
185 const int numIters = 3;
189 m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0));
191 // Clear to black using first context.
193 EGLint api = contexts[0].first;
194 EGLContext context = contexts[0].second;
195 ClearOp clear (0, 0, width, height, RGBA::black());
197 egl.makeCurrent(display, surface, surface, context);
198 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
200 renderClear(api, funcs, clear);
202 clears.push_back(clear);
206 for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
208 for (vector<std::pair<EGLint, EGLContext> >::const_iterator ctxIter = contexts.begin(); ctxIter != contexts.end(); ctxIter++)
210 EGLint api = ctxIter->first;
211 EGLContext context = ctxIter->second;
213 egl.makeCurrent(display, surface, surface, context);
214 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
216 for (int clearNdx = 0; clearNdx < ctxClears; clearNdx++)
218 ClearOp clear = computeRandomClear(rnd, width, height);
220 renderClear(api, funcs, clear);
221 clears.push_back(clear);
228 // Read pixels using first context. \todo [pyry] Randomize?
230 EGLint api = contexts[0].first;
231 EGLContext context = contexts[0].second;
233 egl.makeCurrent(display, surface, surface, context);
234 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
236 readPixels(api, funcs, frame);
239 egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
240 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
243 renderReference(refFrame, clears, pixelFmt);
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);
251 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
255 // MultiThreadColorClearCase
259 NUM_CLEARS_PER_PACKET = 2 //!< Number of clears performed in one context activation in one thread.
262 class ColorClearThread;
264 typedef de::SharedPtr<ColorClearThread> ColorClearThreadSp;
265 typedef de::SharedPtr<de::Semaphore> SemaphoreSp;
273 ClearOp clears[NUM_CLEARS_PER_PACKET];
278 class ColorClearThread : public de::Thread
281 ColorClearThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const ApiFunctions& funcs, const std::vector<ClearPacket>& packets)
283 , m_display (display)
284 , m_surface (surface)
285 , m_context (context)
288 , m_packets (packets)
294 for (std::vector<ClearPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
296 // Wait until it is our turn.
297 packetIter->wait->decrement();
300 m_egl.makeCurrent(m_display, m_surface, m_surface, m_context);
303 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(packetIter->clears); ndx++)
304 renderClear(m_api, m_funcs, packetIter->clears[ndx]);
306 finish(m_api, m_funcs);
308 m_egl.makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
310 // Signal completion.
311 packetIter->signal->increment();
313 m_egl.releaseThread();
317 const Library& m_egl;
318 EGLDisplay m_display;
319 EGLSurface m_surface;
320 EGLContext m_context;
322 const ApiFunctions& m_funcs;
323 const std::vector<ClearPacket>& m_packets;
326 MultiThreadColorClearCase::MultiThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
327 : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
331 void MultiThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
333 const Library& egl = m_eglTestCtx.getLibrary();
335 const tcu::IVec2 surfaceSize = eglu::getSurfaceSize(egl, display, surface);
336 const int width = surfaceSize.x();
337 const int height = surfaceSize.y();
339 TestLog& log = m_testCtx.getLog();
341 tcu::Surface refFrame (width, height);
342 tcu::Surface frame (width, height);
343 tcu::PixelFormat pixelFmt = getPixelFormat(egl, display, config.config);
345 de::Random rnd (deStringHash(getName()));
349 m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0));
351 // Create clear packets.
352 const int numPacketsPerThread = 2;
353 int numThreads = (int)contexts.size();
354 int numPackets = numThreads * numPacketsPerThread;
356 vector<SemaphoreSp> semaphores (numPackets+1);
357 vector<vector<ClearPacket> > packets (numThreads);
358 vector<ColorClearThreadSp> threads (numThreads);
360 // Initialize semaphores.
361 for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
362 *sem = SemaphoreSp(new de::Semaphore(0));
365 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
367 packets[threadNdx].resize(numPacketsPerThread);
369 for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
371 ClearPacket& packet = packets[threadNdx][packetNdx];
373 // Threads take turns with packets.
374 packet.wait = semaphores[packetNdx*numThreads + threadNdx];
375 packet.signal = semaphores[packetNdx*numThreads + threadNdx + 1];
377 for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
379 // First clear is always full-screen black.
380 if (threadNdx == 0 && packetNdx == 0 && clearNdx == 0)
381 packet.clears[clearNdx] = ClearOp(0, 0, width, height, RGBA::black());
383 packet.clears[clearNdx] = computeRandomClear(rnd, width, height);
388 // Create and launch threads (actual rendering starts once first semaphore is signaled).
389 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
391 threads[threadNdx] = ColorClearThreadSp(new ColorClearThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, funcs, packets[threadNdx]));
392 threads[threadNdx]->start();
395 // Signal start and wait until complete.
396 semaphores.front()->increment();
397 semaphores.back()->decrement();
399 // Read pixels using first context. \todo [pyry] Randomize?
401 EGLint api = contexts[0].first;
402 EGLContext context = contexts[0].second;
404 egl.makeCurrent(display, surface, surface, context);
405 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
407 readPixels(api, funcs, frame);
410 egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
411 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
414 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
415 threads[threadNdx]->join();
418 for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
420 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
422 const ClearPacket& packet = packets[threadNdx][packetNdx];
423 for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
425 tcu::PixelBufferAccess access = tcu::getSubregion(refFrame.getAccess(),
426 packet.clears[clearNdx].x, packet.clears[clearNdx].y, 0,
427 packet.clears[clearNdx].width, packet.clears[clearNdx].height, 1);
428 tcu::clear(access, pixelFmt.convertColor(packet.clears[clearNdx].color).toIVec());
435 tcu::RGBA eps = pixelFmt.alphaBits == 1 ? RGBA(1,1,1,127) : RGBA(1,1,1,1);
436 bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, eps + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
439 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");