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 46namespace deqp 47{ 48namespace egl 49{ 50 51using tcu::TestLog; 52using tcu::RGBA; 53using std::vector; 54using namespace eglw; 55 56// Utilities. 57 58struct 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 85struct ApiFunctions 86{ 87 glw::Functions gl; 88}; 89 90static 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 101static 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 110static 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 123static 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 136static 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 149static 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 163SingleThreadColorClearCase::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 168void 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 257enum 258{ 259 NUM_CLEARS_PER_PACKET = 2 //!< Number of clears performed in one context activation in one thread. 260}; 261 262class ColorClearThread; 263 264typedef de::SharedPtr<ColorClearThread> ColorClearThreadSp; 265typedef de::SharedPtr<de::Semaphore> SemaphoreSp; 266 267struct ClearPacket 268{ 269 ClearPacket (void) 270 { 271 } 272 273 ClearOp clears[NUM_CLEARS_PER_PACKET]; 274 SemaphoreSp wait; 275 SemaphoreSp signal; 276}; 277 278class ColorClearThread : public de::Thread 279{ 280public: 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 315private: 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 325MultiThreadColorClearCase::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 330void 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 444