Home | History | Annotate | Download | only in egl
      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