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 442