teglColorClearCase.cpp revision d2722f6ec95d6f745a9ee1bfa5f033574b91f235
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 readPixels (EGLint api, const ApiFunctions& func, tcu::Surface& dst)
124{
125	switch (api)
126	{
127		case EGL_OPENGL_ES_BIT:			gles1::readPixels	(dst, 0, 0, dst.getWidth(), dst.getHeight());			break;
128		case EGL_OPENGL_ES2_BIT:		gles2::readPixels	(func.gl, dst, 0, 0, dst.getWidth(), dst.getHeight());	break;
129		case EGL_OPENGL_ES3_BIT_KHR:	gles2::readPixels	(func.gl, dst, 0, 0, dst.getWidth(), dst.getHeight());	break;
130		case EGL_OPENVG_BIT:			vg::readPixels		(dst, 0, 0, dst.getWidth(), dst.getHeight());			break;
131		default:
132			DE_ASSERT(DE_FALSE);
133	}
134}
135
136static tcu::PixelFormat getPixelFormat (const Library& egl, EGLDisplay display, EGLConfig config)
137{
138	tcu::PixelFormat pixelFmt;
139
140	egl.getConfigAttrib(display, config, EGL_RED_SIZE,		&pixelFmt.redBits);
141	egl.getConfigAttrib(display, config, EGL_GREEN_SIZE,	&pixelFmt.greenBits);
142	egl.getConfigAttrib(display, config, EGL_BLUE_SIZE,		&pixelFmt.blueBits);
143	egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE,	&pixelFmt.alphaBits);
144
145	return pixelFmt;
146}
147
148// SingleThreadColorClearCase
149
150SingleThreadColorClearCase::SingleThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
151	: MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
152{
153}
154
155void SingleThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
156{
157	const Library&		egl			= m_eglTestCtx.getLibrary();
158
159	const tcu::IVec2	surfaceSize	= eglu::getSurfaceSize(egl, display, surface);
160	const int			width		= surfaceSize.x();
161	const int			height		= surfaceSize.y();
162
163	TestLog&			log			= m_testCtx.getLog();
164
165	tcu::Surface		refFrame	(width, height);
166	tcu::Surface		frame		(width, height);
167	tcu::PixelFormat	pixelFmt	= getPixelFormat(egl, display, config.config);
168
169	de::Random			rnd			(deStringHash(getName()));
170	vector<ClearOp>		clears;
171	const int			ctxClears	= 2;
172	const int			numIters	= 3;
173
174	ApiFunctions		funcs;
175
176	m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0));
177
178	// Clear to black using first context.
179	{
180		EGLint		api			= contexts[0].first;
181		EGLContext	context		= contexts[0].second;
182		ClearOp		clear		(0, 0, width, height, RGBA::black);
183
184		egl.makeCurrent(display, surface, surface, context);
185		EGLU_CHECK_MSG(egl, "eglMakeCurrent");
186
187		renderClear(api, funcs, clear);
188		clears.push_back(clear);
189	}
190
191	// Render.
192	for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
193	{
194		for (vector<std::pair<EGLint, EGLContext> >::const_iterator ctxIter = contexts.begin(); ctxIter != contexts.end(); ctxIter++)
195		{
196			EGLint		api			= ctxIter->first;
197			EGLContext	context		= ctxIter->second;
198
199			egl.makeCurrent(display, surface, surface, context);
200			EGLU_CHECK_MSG(egl, "eglMakeCurrent");
201
202			for (int clearNdx = 0; clearNdx < ctxClears; clearNdx++)
203			{
204				ClearOp clear = computeRandomClear(rnd, width, height);
205
206				renderClear(api, funcs, clear);
207				clears.push_back(clear);
208			}
209		}
210	}
211
212	// Read pixels using first context. \todo [pyry] Randomize?
213	{
214		EGLint		api		= contexts[0].first;
215		EGLContext	context	= contexts[0].second;
216
217		egl.makeCurrent(display, surface, surface, context);
218		EGLU_CHECK_MSG(egl, "eglMakeCurrent");
219
220		readPixels(api, funcs, frame);
221	}
222
223	egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
224	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
225
226	// Render reference.
227	renderReference(refFrame, clears, pixelFmt);
228
229	// Compare images
230	{
231		bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, RGBA(1,1,1,1) + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
232
233		if (!imagesOk)
234			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
235	}
236}
237
238// MultiThreadColorClearCase
239
240enum
241{
242	NUM_CLEARS_PER_PACKET	= 2 //!< Number of clears performed in one context activation in one thread.
243};
244
245class ColorClearThread;
246
247typedef de::SharedPtr<ColorClearThread>	ColorClearThreadSp;
248typedef de::SharedPtr<de::Semaphore>	SemaphoreSp;
249
250struct ClearPacket
251{
252	ClearPacket (void)
253	{
254	}
255
256	ClearOp			clears[NUM_CLEARS_PER_PACKET];
257	SemaphoreSp		wait;
258	SemaphoreSp		signal;
259};
260
261class ColorClearThread : public de::Thread
262{
263public:
264	ColorClearThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const ApiFunctions& funcs, const std::vector<ClearPacket>& packets)
265		: m_egl		(egl)
266		, m_display	(display)
267		, m_surface	(surface)
268		, m_context	(context)
269		, m_api		(api)
270		, m_funcs	(funcs)
271		, m_packets	(packets)
272	{
273	}
274
275	void run (void)
276	{
277		for (std::vector<ClearPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
278		{
279			// Wait until it is our turn.
280			packetIter->wait->decrement();
281
282			// Acquire context.
283			m_egl.makeCurrent(m_display, m_surface, m_surface, m_context);
284
285			// Execute clears.
286			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(packetIter->clears); ndx++)
287				renderClear(m_api, m_funcs, packetIter->clears[ndx]);
288
289			// Release context.
290			m_egl.makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
291
292			// Signal completion.
293			packetIter->signal->increment();
294		}
295	}
296
297private:
298	const Library&					m_egl;
299	EGLDisplay						m_display;
300	EGLSurface						m_surface;
301	EGLContext						m_context;
302	EGLint							m_api;
303	const ApiFunctions&				m_funcs;
304	const std::vector<ClearPacket>&	m_packets;
305};
306
307MultiThreadColorClearCase::MultiThreadColorClearCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
308	: MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
309{
310}
311
312void MultiThreadColorClearCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
313{
314	const Library&		egl			= m_eglTestCtx.getLibrary();
315
316	const tcu::IVec2	surfaceSize	= eglu::getSurfaceSize(egl, display, surface);
317	const int			width		= surfaceSize.x();
318	const int			height		= surfaceSize.y();
319
320	TestLog&			log			= m_testCtx.getLog();
321
322	tcu::Surface		refFrame	(width, height);
323	tcu::Surface		frame		(width, height);
324	tcu::PixelFormat	pixelFmt	= getPixelFormat(egl, display, config.config);
325
326	de::Random			rnd			(deStringHash(getName()));
327
328	ApiFunctions		funcs;
329
330	m_eglTestCtx.initGLFunctions(&funcs.gl, glu::ApiType::es(2,0));
331
332	// Create clear packets.
333	const int						numPacketsPerThread		= 2;
334	int								numThreads				= (int)contexts.size();
335	int								numPackets				= numThreads * numPacketsPerThread;
336
337	vector<SemaphoreSp>				semaphores				(numPackets+1);
338	vector<vector<ClearPacket> >	packets					(numThreads);
339	vector<ColorClearThreadSp>		threads					(numThreads);
340
341	// Initialize semaphores.
342	for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
343		*sem = SemaphoreSp(new de::Semaphore(0));
344
345	// Create packets.
346	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
347	{
348		packets[threadNdx].resize(numPacketsPerThread);
349
350		for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
351		{
352			ClearPacket& packet = packets[threadNdx][packetNdx];
353
354			// Threads take turns with packets.
355			packet.wait		= semaphores[packetNdx*numThreads + threadNdx];
356			packet.signal	= semaphores[packetNdx*numThreads + threadNdx + 1];
357
358			for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
359			{
360				// First clear is always full-screen black.
361				if (threadNdx == 0 && packetNdx == 0 && clearNdx == 0)
362					packet.clears[clearNdx] = ClearOp(0, 0, width, height, RGBA::black);
363				else
364					packet.clears[clearNdx] = computeRandomClear(rnd, width, height);
365			}
366		}
367	}
368
369	// Create and launch threads (actual rendering starts once first semaphore is signaled).
370	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
371	{
372		threads[threadNdx] = ColorClearThreadSp(new ColorClearThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, funcs, packets[threadNdx]));
373		threads[threadNdx]->start();
374	}
375
376	// Signal start and wait until complete.
377	semaphores.front()->increment();
378	semaphores.back()->decrement();
379
380	// Read pixels using first context. \todo [pyry] Randomize?
381	{
382		EGLint		api		= contexts[0].first;
383		EGLContext	context	= contexts[0].second;
384
385		egl.makeCurrent(display, surface, surface, context);
386		EGLU_CHECK_MSG(egl, "eglMakeCurrent");
387
388		readPixels(api, funcs, frame);
389	}
390
391	egl.makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
392	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
393
394	// Join threads.
395	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
396		threads[threadNdx]->join();
397
398	// Render reference.
399	for (int packetNdx = 0; packetNdx < numPacketsPerThread; packetNdx++)
400	{
401		for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
402		{
403			const ClearPacket& packet = packets[threadNdx][packetNdx];
404			for (int clearNdx = 0; clearNdx < DE_LENGTH_OF_ARRAY(packet.clears); clearNdx++)
405			{
406				tcu::PixelBufferAccess access = tcu::getSubregion(refFrame.getAccess(),
407																  packet.clears[clearNdx].x, packet.clears[clearNdx].y, 0,
408																  packet.clears[clearNdx].width, packet.clears[clearNdx].height, 1);
409				tcu::clear(access, pixelFmt.convertColor(packet.clears[clearNdx].color).toIVec());
410			}
411		}
412	}
413
414	// Compare images
415	{
416		bool imagesOk = tcu::pixelThresholdCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, RGBA(1,1,1,1) + pixelFmt.getColorThreshold(), tcu::COMPARE_LOG_RESULT);
417
418		if (!imagesOk)
419			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
420	}
421}
422
423} // egl
424} // deqp
425