• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
ClearOpdeqp::egl::ClearOp60 	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 
ClearOpdeqp::egl::ClearOp69 	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 
computeRandomClear(de::Random & rnd,int width,int height)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 
renderReference(tcu::Surface & dst,const vector<ClearOp> & clears,const tcu::PixelFormat & pixelFormat)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 
renderClear(EGLint api,const ApiFunctions & func,const ClearOp & clear)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 
finish(EGLint api,const ApiFunctions & func)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 
readPixels(EGLint api,const ApiFunctions & func,tcu::Surface & dst)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 
getPixelFormat(const Library & egl,EGLDisplay display,EGLConfig config)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 
SingleThreadColorClearCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)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 
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)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 		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 
257 enum
258 {
259 	NUM_CLEARS_PER_PACKET	= 2 //!< Number of clears performed in one context activation in one thread.
260 };
261 
262 class ColorClearThread;
263 
264 typedef de::SharedPtr<ColorClearThread>	ColorClearThreadSp;
265 typedef de::SharedPtr<de::Semaphore>	SemaphoreSp;
266 
267 struct ClearPacket
268 {
ClearPacketdeqp::egl::ClearPacket269 	ClearPacket (void)
270 	{
271 	}
272 
273 	ClearOp			clears[NUM_CLEARS_PER_PACKET];
274 	SemaphoreSp		wait;
275 	SemaphoreSp		signal;
276 };
277 
278 class ColorClearThread : public de::Thread
279 {
280 public:
ColorClearThread(const Library & egl,EGLDisplay display,EGLSurface surface,EGLContext context,EGLint api,const ApiFunctions & funcs,const std::vector<ClearPacket> & packets)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 
run(void)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 
316 private:
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 
MultiThreadColorClearCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)326 MultiThreadColorClearCase::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 
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)331 void 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