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 "deRandom.hpp"
     27 #include "deString.h"
     28 #include "tcuImageCompare.hpp"
     29 #include "tcuVector.hpp"
     30 #include "tcuTextureUtil.hpp"
     31 #include "deThread.hpp"
     32 #include "deSemaphore.hpp"
     33 #include "deSharedPtr.hpp"
     34 #include "teglGLES1RenderUtil.hpp"
     35 #include "teglGLES2RenderUtil.hpp"
     36 #include "teglVGRenderUtil.hpp"
     37 
     38 #include <memory>
     39 #include <iterator>
     40 
     41 #include <EGL/eglext.h>
     42 
     43 #if !defined(EGL_OPENGL_ES3_BIT_KHR)
     44 #	define EGL_OPENGL_ES3_BIT_KHR	0x0040
     45 #endif
     46 #if !defined(EGL_CONTEXT_MAJOR_VERSION_KHR)
     47 #	define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION
     48 #endif
     49 
     50 using tcu::TestLog;
     51 using tcu::RGBA;
     52 
     53 using std::vector;
     54 
     55 namespace deqp
     56 {
     57 namespace egl
     58 {
     59 
     60 // Utilities.
     61 
     62 struct ClearOp
     63 {
     64 	ClearOp (int x_, int y_, int width_, int height_, const tcu::RGBA& color_)
     65 		: x			(x_)
     66 		, y			(y_)
     67 		, width		(width_)
     68 		, height	(height_)
     69 		, color		(color_)
     70 	{
     71 	}
     72 
     73 	ClearOp (void)
     74 		: x			(0)
     75 		, y			(0)
     76 		, width		(0)
     77 		, height	(0)
     78 		, color		(0)
     79 	{
     80 	}
     81 
     82 	int			x;
     83 	int			y;
     84 	int			width;
     85 	int			height;
     86 	tcu::RGBA	color;
     87 };
     88 
     89 static ClearOp computeRandomClear (de::Random& rnd, int width, int height)
     90 {
     91 	int			w		= rnd.getInt(1, width);
     92 	int			h		= rnd.getInt(1, height);
     93 	int			x		= rnd.getInt(0, width-w);
     94 	int			y		= rnd.getInt(0, height-h);
     95 	tcu::RGBA	col		(rnd.getUint32());
     96 
     97 	return ClearOp(x, y, w, h, col);
     98 }
     99 
    100 static void renderReference (tcu::Surface& dst, const vector<ClearOp>& clears, const tcu::PixelFormat& pixelFormat)
    101 {
    102 	for (vector<ClearOp>::const_iterator clearIter = clears.begin(); clearIter != clears.end(); clearIter++)
    103 	{
    104 		tcu::PixelBufferAccess access = tcu::getSubregion(dst.getAccess(), clearIter->x, clearIter->y, 0, clearIter->width, clearIter->height, 1);
    105 		tcu::clear(access, pixelFormat.convertColor(clearIter->color).toIVec());
    106 	}
    107 }
    108 
    109 static void renderClear (EGLint api, const ClearOp& clear)
    110 {
    111 	switch (api)
    112 	{
    113 		case EGL_OPENGL_ES_BIT:			gles1::clear(clear.x, clear.y, clear.width, clear.height, clear.color.toVec());	break;
    114 		case EGL_OPENGL_ES2_BIT:		gles2::clear(clear.x, clear.y, clear.width, clear.height, clear.color.toVec());	break;
    115 		case EGL_OPENGL_ES3_BIT_KHR:	gles2::clear(clear.x, clear.y, clear.width, clear.height, clear.color.toVec());	break;
    116 		case EGL_OPENVG_BIT:			vg::clear	(clear.x, clear.y, clear.width, clear.height, clear.color.toVec());	break;
    117 		default:
    118 			DE_ASSERT(DE_FALSE);
    119 	}
    120 }
    121 
    122 static void readPixels (EGLint api, tcu::Surface& dst)
    123 {
    124 	switch (api)
    125 	{
    126 		case EGL_OPENGL_ES_BIT:			gles1::readPixels	(dst, 0, 0, dst.getWidth(), dst.getHeight());	break;
    127 		case EGL_OPENGL_ES2_BIT:		gles2::readPixels	(dst, 0, 0, dst.getWidth(), dst.getHeight());	break;
    128 		case EGL_OPENGL_ES3_BIT_KHR:	gles2::readPixels	(dst, 0, 0, dst.getWidth(), dst.getHeight());	break;
    129 		case EGL_OPENVG_BIT:			vg::readPixels		(dst, 0, 0, dst.getWidth(), dst.getHeight());	break;
    130 		default:
    131 			DE_ASSERT(DE_FALSE);
    132 	}
    133 }
    134 
    135 // SingleThreadColorClearCase
    136 
    137 SingleThreadColorClearCase::SingleThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const std::vector<EGLint>& configIds, int numContextsPerApi)
    138 	: MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, configIds, numContextsPerApi)
    139 {
    140 }
    141 
    142 void SingleThreadColorClearCase::executeForContexts (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config, const std::vector<std::pair<EGLint, tcu::egl::Context*> >& contexts)
    143 {
    144 	int					width		= surface.getWidth();
    145 	int					height		= surface.getHeight();
    146 
    147 	TestLog&			log			= m_testCtx.getLog();
    148 
    149 	tcu::Surface		refFrame	(width, height);
    150 	tcu::Surface		frame		(width, height);
    151 	tcu::PixelFormat	pixelFmt;
    152 
    153 	de::Random			rnd			(deStringHash(getName()));
    154 	vector<ClearOp>		clears;
    155 	const int			ctxClears	= 2;
    156 	const int			numIters	= 3;
    157 
    158 	// Query pixel format.
    159 	display.describeConfig(config, pixelFmt);
    160 
    161 	// Clear to black using first context.
    162 	{
    163 		EGLint				api			= contexts[0].first;
    164 		tcu::egl::Context*	context		= contexts[0].second;
    165 		ClearOp				clear		(0, 0, width, height, RGBA::black);
    166 
    167 		eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext());
    168 		TCU_CHECK_EGL();
    169 
    170 		renderClear(api, clear);
    171 		clears.push_back(clear);
    172 	}
    173 
    174 	// Render.
    175 	for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
    176 	{
    177 		for (vector<std::pair<EGLint, tcu::egl::Context*> >::const_iterator ctxIter = contexts.begin(); ctxIter != contexts.end(); ctxIter++)
    178 		{
    179 			EGLint				api			= ctxIter->first;
    180 			tcu::egl::Context*	context		= ctxIter->second;
    181 
    182 			eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext());
    183 			TCU_CHECK_EGL();
    184 
    185 			for (int clearNdx = 0; clearNdx < ctxClears; clearNdx++)
    186 			{
    187 				ClearOp clear = computeRandomClear(rnd, width, height);
    188 
    189 				renderClear(api, clear);
    190 				clears.push_back(clear);
    191 			}
    192 		}
    193 	}
    194 
    195 	// Read pixels using first context. \todo [pyry] Randomize?
    196 	{
    197 		EGLint				api		= contexts[0].first;
    198 		tcu::egl::Context*	context	= contexts[0].second;
    199 
    200 		eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext());
    201 		TCU_CHECK_EGL();
    202 
    203 		readPixels(api, frame);
    204 	}
    205 
    206 	// Render reference.
    207 	renderReference(refFrame, clears, pixelFmt);
    208 
    209 	// Compare images
    210 	{
    211 		bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, RGBA(1,1,1,1) + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
    212 
    213 		if (!imagesOk)
    214 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    215 	}
    216 }
    217 
    218 // MultiThreadColorClearCase
    219 
    220 enum
    221 {
    222 	NUM_CLEARS_PER_PACKET	= 2 //!< Number of clears performed in one context activation in one thread.
    223 };
    224 
    225 class ColorClearThread;
    226 
    227 typedef de::SharedPtr<ColorClearThread>	ColorClearThreadSp;
    228 typedef de::SharedPtr<de::Semaphore>	SemaphoreSp;
    229 
    230 struct ClearPacket
    231 {
    232 	ClearPacket (void)
    233 	{
    234 	}
    235 
    236 	ClearOp			clears[NUM_CLEARS_PER_PACKET];
    237 	SemaphoreSp		wait;
    238 	SemaphoreSp		signal;
    239 };
    240 
    241 class ColorClearThread : public de::Thread
    242 {
    243 public:
    244 	ColorClearThread (tcu::egl::Display& display, tcu::egl::Surface& surface, tcu::egl::Context& context, EGLint api, const std::vector<ClearPacket>& packets)
    245 		: m_display	(display)
    246 		, m_surface	(surface)
    247 		, m_context	(context)
    248 		, m_api		(api)
    249 		, m_packets	(packets)
    250 	{
    251 	}
    252 
    253 	void run (void)
    254 	{
    255 		for (std::vector<ClearPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
    256 		{
    257 			// Wait until it is our turn.
    258 			packetIter->wait->decrement();
    259 
    260 			// Acquire context.
    261 			eglMakeCurrent(m_display.getEGLDisplay(), m_surface.getEGLSurface(), m_surface.getEGLSurface(), m_context.getEGLContext());
    262 
    263 			// Execute clears.
    264 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(packetIter->clears); ndx++)
    265 				renderClear(m_api, packetIter->clears[ndx]);
    266 
    267 			// Release context.
    268 			eglMakeCurrent(m_display.getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    269 
    270 			// Signal completion.
    271 			packetIter->signal->increment();
    272 		}
    273 	}
    274 
    275 private:
    276 	tcu::egl::Display&				m_display;
    277 	tcu::egl::Surface&				m_surface;
    278 	tcu::egl::Context&				m_context;
    279 	EGLint							m_api;
    280 	const std::vector<ClearPacket>&	m_packets;
    281 };
    282 
    283 MultiThreadColorClearCase::MultiThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const std::vector<EGLint>& configIds, int numContextsPerApi)
    284 	: MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, configIds, numContextsPerApi)
    285 {
    286 }
    287 
    288 void MultiThreadColorClearCase::executeForContexts (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config, const std::vector<std::pair<EGLint, tcu::egl::Context*> >& contexts)
    289 {
    290 	int					width		= surface.getWidth();
    291 	int					height		= surface.getHeight();
    292 
    293 	TestLog&			log			= m_testCtx.getLog();
    294 
    295 	tcu::Surface		refFrame	(width, height);
    296 	tcu::Surface		frame		(width, height);
    297 	tcu::PixelFormat	pixelFmt;
    298 
    299 	de::Random			rnd			(deStringHash(getName()));
    300 
    301 	// Query pixel format.
    302 	display.describeConfig(config, pixelFmt);
    303 
    304 	// Create clear packets.
    305 	const int						numPacketsPerThread		= 2;
    306 	int								numThreads				= (int)contexts.size();
    307 	int								numPackets				= numThreads * numPacketsPerThread;
    308 
    309 	vector<SemaphoreSp>				semaphores				(numPackets+1);
    310 	vector<vector<ClearPacket> >	packets					(numThreads);
    311 	vector<ColorClearThreadSp>		threads					(numThreads);
    312 
    313 	// Initialize semaphores.
    314 	for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
    315 		*sem = SemaphoreSp(new de::Semaphore(0));
    316 
    317 	// Create packets.
    318 	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
    319 	{
    320 		packets[threadNdx].resize(numPacketsPerThread);
    321 
    322 		for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
    323 		{
    324 			ClearPacket& packet = packets[threadNdx][packetNdx];
    325 
    326 			// Threads take turns with packets.
    327 			packet.wait		= semaphores[packetNdx*numThreads + threadNdx];
    328 			packet.signal	= semaphores[packetNdx*numThreads + threadNdx + 1];
    329 
    330 			for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
    331 			{
    332 				// First clear is always full-screen black.
    333 				if (threadNdx == 0 && packetNdx == 0 && clearNdx == 0)
    334 					packet.clears[clearNdx] = ClearOp(0, 0, width, height, RGBA::black);
    335 				else
    336 					packet.clears[clearNdx] = computeRandomClear(rnd, width, height);
    337 			}
    338 		}
    339 	}
    340 
    341 	// Create and launch threads (actual rendering starts once first semaphore is signaled).
    342 	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
    343 	{
    344 		threads[threadNdx] = ColorClearThreadSp(new ColorClearThread(display, surface, *contexts[threadNdx].second, contexts[threadNdx].first, packets[threadNdx]));
    345 		threads[threadNdx]->start();
    346 	}
    347 
    348 	// Signal start and wait until complete.
    349 	semaphores.front()->increment();
    350 	semaphores.back()->decrement();
    351 
    352 	// Read pixels using first context. \todo [pyry] Randomize?
    353 	{
    354 		EGLint				api		= contexts[0].first;
    355 		tcu::egl::Context*	context	= contexts[0].second;
    356 
    357 		eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext());
    358 		TCU_CHECK_EGL();
    359 
    360 		readPixels(api, frame);
    361 	}
    362 
    363 	// Join threads.
    364 	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
    365 		threads[threadNdx]->join();
    366 
    367 	// Render reference.
    368 	for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
    369 	{
    370 		for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
    371 		{
    372 			const ClearPacket& packet = packets[threadNdx][packetNdx];
    373 			for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
    374 			{
    375 				tcu::PixelBufferAccess access = tcu::getSubregion(refFrame.getAccess(),
    376 																  packet.clears[clearNdx].x, packet.clears[clearNdx].y, 0,
    377 																  packet.clears[clearNdx].width, packet.clears[clearNdx].height, 1);
    378 				tcu::clear(access, pixelFmt.convertColor(packet.clears[clearNdx].color).toIVec());
    379 			}
    380 		}
    381 	}
    382 
    383 	// Compare images
    384 	{
    385 		bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, RGBA(1,1,1,1) + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
    386 
    387 		if (!imagesOk)
    388 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    389 	}
    390 }
    391 
    392 } // egl
    393 } // deqp
    394