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 m_egl.releaseThread(); 314 } 315 316private: 317 const Library& m_egl; 318 EGLDisplay m_display; 319 EGLSurface m_surface; 320 EGLContext m_context; 321 EGLint m_api; 322 const ApiFunctions& m_funcs; 323 const std::vector<ClearPacket>& m_packets; 324}; 325 326MultiThreadColorClearCase::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) 328{ 329} 330 331void MultiThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts) 332{ 333 const Library& egl = m_eglTestCtx.getLibrary(); 334 335 const tcu::IVec2 surfaceSize = eglu::getSurfaceSize(egl, display, surface); 336 const int width = surfaceSize.x(); 337 const int height = surfaceSize.y(); 338 339 TestLog& log = m_testCtx.getLog(); 340 341 tcu::Surface refFrame (width, height); 342 tcu::Surface frame (width, height); 343 tcu::PixelFormat pixelFmt = getPixelFormat(egl, display, config.config); 344 345 de::Random rnd (deStringHash(getName())); 346 347 ApiFunctions funcs; 348 349 m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0)); 350 351 // Create clear packets. 352 const int numPacketsPerThread = 2; 353 int numThreads = (int)contexts.size(); 354 int numPackets = numThreads * numPacketsPerThread; 355 356 vector<SemaphoreSp> semaphores (numPackets+1); 357 vector<vector<ClearPacket> > packets (numThreads); 358 vector<ColorClearThreadSp> threads (numThreads); 359 360 // Initialize semaphores. 361 for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem) 362 *sem = SemaphoreSp(new de::Semaphore(0)); 363 364 // Create packets. 365 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++) 366 { 367 packets[threadNdx].resize(numPacketsPerThread); 368 369 for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++) 370 { 371 ClearPacket& packet = packets[threadNdx][packetNdx]; 372 373 // Threads take turns with packets. 374 packet.wait = semaphores[packetNdx*numThreads + threadNdx]; 375 packet.signal = semaphores[packetNdx*numThreads + threadNdx + 1]; 376 377 for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++) 378 { 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()); 382 else 383 packet.clears[clearNdx] = computeRandomClear(rnd, width, height); 384 } 385 } 386 } 387 388 // Create and launch threads (actual rendering starts once first semaphore is signaled). 389 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++) 390 { 391 threads[threadNdx] = ColorClearThreadSp(new ColorClearThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, funcs, packets[threadNdx])); 392 threads[threadNdx]->start(); 393 } 394 395 // Signal start and wait until complete. 396 semaphores.front()->increment(); 397 semaphores.back()->decrement(); 398 399 // Read pixels using first context. \todo [pyry] Randomize? 400 { 401 EGLint api = contexts[0].first; 402 EGLContext context = contexts[0].second; 403 404 egl.makeCurrent(display, surface, surface, context); 405 EGLU_CHECK_MSG(egl, "eglMakeCurrent"); 406 407 readPixels(api, funcs, frame); 408 } 409 410 egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 411 EGLU_CHECK_MSG(egl, "eglMakeCurrent"); 412 413 // Join threads. 414 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++) 415 threads[threadNdx]->join(); 416 417 // Render reference. 418 for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++) 419 { 420 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++) 421 { 422 const ClearPacket& packet = packets[threadNdx][packetNdx]; 423 for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++) 424 { 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()); 429 } 430 } 431 } 432 433 // Compare images 434 { 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); 437 438 if (!imagesOk) 439 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 440 } 441} 442 443} // egl 444} // deqp 445