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 Test EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
22 *//*--------------------------------------------------------------------*/
23
24#include "teglPreservingSwapTests.hpp"
25
26#include "tcuImageCompare.hpp"
27#include "tcuTestLog.hpp"
28#include "tcuSurface.hpp"
29#include "tcuTextureUtil.hpp"
30#include "tcuEgl.hpp"
31
32#include "egluNativeWindow.hpp"
33#include "egluUtil.hpp"
34
35#include "gluDefs.hpp"
36#include "gluRenderContext.hpp"
37
38#include "glwDefs.hpp"
39#include "glwEnums.hpp"
40#include "glwFunctions.hpp"
41
42#include "deRandom.hpp"
43
44#include "deString.h"
45
46#include <vector>
47#include <string>
48
49using std::vector;
50using std::string;
51
52namespace deqp
53{
54namespace egl
55{
56
57namespace
58{
59class GLES2Program;
60class ReferenceProgram;
61
62class PreservingSwapTest : public TestCase
63{
64public:
65	enum DrawType
66	{
67		DRAWTYPE_NONE = 0,
68		DRAWTYPE_GLES2_CLEAR,
69		DRAWTYPE_GLES2_RENDER
70	};
71
72					PreservingSwapTest	(EglTestContext& eglTestCtx, bool preserveColorbuffer, bool readPixelsBeforeSwap, DrawType preSwapDrawType, DrawType postSwapDrawType, const char* name, const char* description);
73					~PreservingSwapTest	(void);
74
75	void			init				(void);
76	void			deinit				(void);
77	IterateResult	iterate				(void);
78
79private:
80	const int					m_seed;
81	const bool					m_preserveColorbuffer;
82	const bool					m_readPixelsBeforeSwap;
83	const DrawType				m_preSwapDrawType;
84	const DrawType				m_postSwapDrawType;
85
86	eglu::NativeWindow*			m_window;
87	tcu::egl::WindowSurface*	m_eglSurface;
88	EGLConfig					m_eglConfig;
89	tcu::egl::Context*			m_eglContext;
90	glw::Functions				m_gl;
91
92	GLES2Program*				m_gles2Program;
93	ReferenceProgram*			m_refProgram;
94
95	void initEGLSurface	(EGLConfig config);
96	void initEGLContext (EGLConfig config);
97};
98
99class GLES2Program
100{
101public:
102					GLES2Program	(const glw::Functions& gl);
103					~GLES2Program	(void);
104
105	void			render			(int width, int height, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType);
106
107private:
108	const glw::Functions&	m_gl;
109	glw::GLuint				m_glProgram;
110	glw::GLuint				m_coordLoc;
111	glw::GLuint				m_colorLoc;
112
113	GLES2Program&			operator=		(const GLES2Program&);
114							GLES2Program	(const GLES2Program&);
115};
116
117GLES2Program::GLES2Program (const glw::Functions& gl)
118	: m_gl			(gl)
119	, m_glProgram	(0)
120	, m_coordLoc	((glw::GLuint)-1)
121	, m_colorLoc	((glw::GLuint)-1)
122{
123	const char* const vertexShaderSource =
124	"attribute mediump vec4 a_pos;\n"
125	"attribute mediump vec4 a_color;\n"
126	"varying mediump vec4 v_color;\n"
127	"void main(void)\n"
128	"{\n"
129	"\tv_color = a_color;\n"
130	"\tgl_Position = a_pos;\n"
131	"}";
132
133	const char* const fragmentShaderSource =
134	"varying mediump vec4 v_color;\n"
135	"void main(void)\n"
136	"{\n"
137	"\tgl_FragColor = v_color;\n"
138	"}";
139
140	glw::GLuint	vtxShader	= (glw::GLuint)-1;
141	glw::GLuint	fragShader	= (glw::GLuint)-1;
142
143	try
144	{
145		vtxShader = m_gl.createShader(GL_VERTEX_SHADER);
146		fragShader = m_gl.createShader(GL_FRAGMENT_SHADER);
147
148		m_glProgram	= m_gl.createProgram();
149
150		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to create resources for shader program");
151
152		m_gl.shaderSource(vtxShader, 1, &vertexShaderSource, DE_NULL);
153		m_gl.shaderSource(fragShader, 1, &fragmentShaderSource, DE_NULL);
154		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set shader sources");
155
156		m_gl.compileShader(vtxShader);
157		m_gl.compileShader(fragShader);
158		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Shader compilation failed");
159
160		m_gl.attachShader(m_glProgram, vtxShader);
161		m_gl.attachShader(m_glProgram, fragShader);
162		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to attach shaders to program");
163
164		m_gl.linkProgram(m_glProgram);
165		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to link program");
166
167		m_gl.deleteShader(fragShader);
168		fragShader = (glw::GLuint)-1;
169		m_gl.deleteShader(vtxShader);
170		vtxShader = (glw::GLuint)-1;
171		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to delete shaders");
172
173		m_colorLoc = m_gl.getAttribLocation(m_glProgram, "a_color");
174		m_coordLoc = m_gl.getAttribLocation(m_glProgram, "a_pos");
175		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
176
177		TCU_CHECK(m_colorLoc != (glw::GLuint)-1);
178		TCU_CHECK(m_coordLoc != (glw::GLuint)-1);
179
180	}
181	catch (...)
182	{
183		if (vtxShader != (glw::GLuint)-1)
184			m_gl.deleteShader(vtxShader);
185
186		if (fragShader != (glw::GLuint)-1)
187			m_gl.deleteShader(fragShader);
188
189		if (m_glProgram != (glw::GLuint)-1)
190			m_gl.deleteProgram(m_glProgram);
191
192		m_glProgram = (glw::GLuint)-1;
193
194		throw;
195	}
196}
197
198GLES2Program::~GLES2Program (void)
199{
200	if (m_glProgram != (glw::GLuint)-1)
201		m_gl.deleteProgram(m_glProgram);
202}
203
204void GLES2Program::render (int width, int height, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType)
205{
206	if (drawType == PreservingSwapTest::DRAWTYPE_GLES2_RENDER)
207	{
208		const glw::GLfloat coords[] =
209		{
210			x1, y1, 0.0f, 1.0f,
211			x1, y2, 0.0f, 1.0f,
212			x2, y2, 0.0f, 1.0f,
213
214			x2, y2, 0.0f, 1.0f,
215			x2, y1, 0.0f, 1.0f,
216			x1, y1, 0.0f, 1.0f
217		};
218
219		const glw::GLubyte colors[] =
220		{
221			127,	127,	127,	255,
222			127,	127,	127,	255,
223			127,	127,	127,	255,
224
225			127,	127,	127,	255,
226			127,	127,	127,	255,
227			127,	127,	127,	255
228		};
229
230		m_gl.useProgram(m_glProgram);
231		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
232
233		m_gl.enableVertexAttribArray(m_coordLoc);
234		m_gl.enableVertexAttribArray(m_colorLoc);
235		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
236
237		m_gl.vertexAttribPointer(m_coordLoc, 4, GL_FLOAT, GL_FALSE, 0, coords);
238		m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
239		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
240
241		m_gl.drawArrays(GL_TRIANGLES, 0, 6);
242		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() failed");
243
244		m_gl.disableVertexAttribArray(m_coordLoc);
245		m_gl.disableVertexAttribArray(m_colorLoc);
246		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
247
248		m_gl.useProgram(0);
249		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
250	}
251	else if (drawType == PreservingSwapTest::DRAWTYPE_GLES2_CLEAR)
252	{
253		const int ox	= width/2;
254		const int oy	= height/2;
255
256		const int px	= width;
257		const int py	= height;
258
259		const int x1i	= (int)((px/2.0f) * x1 + ox);
260		const int y1i	= (int)((py/2.0f) * y1 + oy);
261
262		const int x2i	= (int)((px/2.0f) * x2 + ox);
263		const int y2i	= (int)((py/2.0f) * y2 + oy);
264
265		m_gl.enable(GL_SCISSOR_TEST);
266		m_gl.scissor(x1i, y1i, x2i-x1i, y2i-y1i);
267		m_gl.clearColor(0.5f, 0.5f, 0.5f, 1.0f);
268		m_gl.clear(GL_COLOR_BUFFER_BIT);
269		m_gl.disable(GL_SCISSOR_TEST);
270	}
271	else
272		DE_ASSERT(false);
273}
274
275class ReferenceProgram
276{
277public:
278			ReferenceProgram	(void);
279			~ReferenceProgram	(void);
280
281	void	render				(tcu::Surface* target, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType);
282
283private:
284						ReferenceProgram	(const ReferenceProgram&);
285	ReferenceProgram&	operator=			(const ReferenceProgram&);
286};
287
288ReferenceProgram::ReferenceProgram (void)
289{
290}
291
292ReferenceProgram::~ReferenceProgram (void)
293{
294}
295
296void ReferenceProgram::render (tcu::Surface* target, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType)
297{
298	if (drawType == PreservingSwapTest::DRAWTYPE_GLES2_RENDER || drawType == PreservingSwapTest::DRAWTYPE_GLES2_CLEAR)
299	{
300		const int ox	= target->getWidth()/2;
301		const int oy	= target->getHeight()/2;
302
303		const int px	= target->getWidth();
304		const int py	= target->getHeight();
305
306		const int x1i	= (int)((px/2.0) * x1 + ox);
307		const int y1i	= (int)((py/2.0) * y1 + oy);
308
309		const int x2i	= (int)((px/2.0) * x2 + ox);
310		const int y2i	= (int)((py/2.0) * y2 + oy);
311
312		const tcu::RGBA	color(127, 127, 127, 255);
313
314		for (int y = y1i; y <= y2i; y++)
315		{
316			for (int x = x1i; x <= x2i; x++)
317				target->setPixel(x, y, color);
318		}
319	}
320	else
321		DE_ASSERT(false);
322}
323
324PreservingSwapTest::PreservingSwapTest (EglTestContext& eglTestCtx, bool preserveColorbuffer, bool readPixelsBeforeSwap, DrawType preSwapDrawType, DrawType postSwapDrawType, const char* name, const char* description)
325	: TestCase					(eglTestCtx, name, description)
326	, m_seed					(deStringHash(name))
327	, m_preserveColorbuffer		(preserveColorbuffer)
328	, m_readPixelsBeforeSwap	(readPixelsBeforeSwap)
329	, m_preSwapDrawType			(preSwapDrawType)
330	, m_postSwapDrawType		(postSwapDrawType)
331	, m_window					(DE_NULL)
332	, m_eglSurface				(DE_NULL)
333	, m_eglContext				(DE_NULL)
334	, m_gles2Program			(DE_NULL)
335	, m_refProgram				(DE_NULL)
336{
337}
338
339PreservingSwapTest::~PreservingSwapTest (void)
340{
341	deinit();
342}
343
344EGLConfig getEGLConfig (tcu::egl::Display& eglDisplay, bool preserveColorbuffer)
345{
346	vector<EGLConfig>	configs;
347	const EGLint		attribList[] =
348	{
349		EGL_SURFACE_TYPE,		EGL_WINDOW_BIT | (preserveColorbuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
350		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
351		EGL_NONE
352	};
353
354	eglDisplay.chooseConfig(attribList, configs);
355
356	if (configs.size() == 0)
357		return DE_NULL;
358	else
359		return configs[0];
360}
361
362void clearColorScreen(const glw::Functions& gl, float red, float green, float blue, float alpha)
363{
364	gl.clearColor(red, green, blue, alpha);
365	gl.clear(GL_COLOR_BUFFER_BIT);
366}
367
368void clearColorReference(tcu::Surface* ref, float red, float green, float blue, float alpha)
369{
370	tcu::clear(ref->getAccess(), tcu::Vec4(red, green, blue, alpha));
371}
372
373void readPixels (const glw::Functions& gl, tcu::Surface* screen)
374{
375	gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
376}
377
378void PreservingSwapTest::initEGLSurface (EGLConfig config)
379{
380	m_window		= m_eglTestCtx.createNativeWindow(m_eglTestCtx.getDisplay().getEGLDisplay(), config, DE_NULL, 480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine()));
381	m_eglSurface	= new tcu::egl::WindowSurface(m_eglTestCtx.getDisplay(), eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglTestCtx.getDisplay().getEGLDisplay(), config, DE_NULL));
382}
383
384void PreservingSwapTest::initEGLContext (EGLConfig config)
385{
386	const EGLint attribList[] =
387	{
388		EGL_CONTEXT_CLIENT_VERSION, 2,
389		EGL_NONE
390	};
391
392	m_eglContext = new tcu::egl::Context(m_eglTestCtx.getDisplay(), config, attribList, EGL_OPENGL_ES_API);
393}
394
395void PreservingSwapTest::init (void)
396{
397	m_eglConfig = getEGLConfig(m_eglTestCtx.getDisplay(), m_preserveColorbuffer);
398
399	if (m_eglConfig == DE_NULL)
400		throw tcu::NotSupportedError("No supported config found", "", __FILE__, __LINE__);
401
402	initEGLSurface(m_eglConfig);
403	initEGLContext(m_eglConfig);
404
405	m_eglContext->makeCurrent(*m_eglSurface, *m_eglSurface);
406
407	m_eglTestCtx.getGLFunctions(m_gl, glu::ApiType::es(2,0));
408
409	m_gles2Program	= new GLES2Program(m_gl);
410	m_refProgram	= new ReferenceProgram();
411}
412
413void PreservingSwapTest::deinit (void)
414{
415	delete m_refProgram;
416	m_refProgram = DE_NULL;
417
418	delete m_gles2Program;
419	m_gles2Program = DE_NULL;
420
421	delete m_eglContext;
422	m_eglContext = DE_NULL;
423
424	delete m_eglSurface;
425	m_eglSurface = DE_NULL;
426
427	delete m_window;
428	m_window = DE_NULL;
429}
430
431bool compareToReference (tcu::TestLog& log, const char* name, const char* description, const tcu::Surface& reference, const tcu::Surface& screen, int x, int y, int width, int height)
432{
433	return tcu::fuzzyCompare(log, name, description, reference.getSubAccess(x, y, width, height), screen.getSubAccess(x, y, width, height), 0.05f, tcu::COMPARE_LOG_RESULT);
434}
435
436bool comparePreAndPostSwapFramebuffers (tcu::TestLog& log, const tcu::Surface& preSwap, const tcu::Surface& postSwap)
437{
438	return tcu::pixelThresholdCompare(log, "Pre- / Post framebuffer compare", "Compare pre- and post-swap framebuffers", preSwap, postSwap, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
439}
440
441TestCase::IterateResult PreservingSwapTest::iterate (void)
442{
443	tcu::TestLog&	log				= m_testCtx.getLog();
444	de::Random		rnd(m_seed);
445
446	const int		width			= m_eglSurface->getWidth();
447	const int		height			= m_eglSurface->getHeight();
448
449	const float		clearRed		= rnd.getFloat();
450	const float		clearGreen		= rnd.getFloat();
451	const float		clearBlue		= rnd.getFloat();
452	const float		clearAlpha		= 1.0f;
453
454	const float		preSwapX1		= -0.9f * rnd.getFloat();
455	const float		preSwapY1		= -0.9f * rnd.getFloat();
456	const float		preSwapX2		= 0.9f * rnd.getFloat();
457	const float		preSwapY2		= 0.9f * rnd.getFloat();
458
459	const float		postSwapX1		= -0.9f * rnd.getFloat();
460	const float		postSwapY1		= -0.9f * rnd.getFloat();
461	const float		postSwapX2		= 0.9f * rnd.getFloat();
462	const float		postSwapY2		= 0.9f * rnd.getFloat();
463
464	tcu::Surface	postSwapFramebufferReference(width, height);
465	tcu::Surface	preSwapFramebufferReference(width, height);
466
467	tcu::Surface	postSwapFramebuffer(width, height);
468	tcu::Surface	preSwapFramebuffer(width, height);
469
470	if (m_preserveColorbuffer)
471		m_eglSurface->setAttribute(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
472
473	m_eglContext->makeCurrent(*m_eglSurface, *m_eglSurface);
474
475	clearColorScreen(m_gl, clearRed, clearGreen, clearBlue, clearAlpha);
476
477	if (m_readPixelsBeforeSwap)
478		clearColorReference(&preSwapFramebufferReference, clearRed, clearGreen, clearBlue, clearAlpha);
479
480	clearColorReference(&postSwapFramebufferReference, clearRed, clearGreen, clearBlue, clearAlpha);
481
482	if (m_preSwapDrawType != DRAWTYPE_NONE)
483	{
484		m_gles2Program->render(width, height, preSwapX1, preSwapY1, preSwapX2, preSwapY2, m_preSwapDrawType);
485		m_refProgram->render(&postSwapFramebufferReference, preSwapX1, preSwapY1, preSwapX2, preSwapY2, m_preSwapDrawType);
486	}
487
488	if (m_readPixelsBeforeSwap)
489	{
490		if (m_preSwapDrawType != DRAWTYPE_NONE)
491			m_refProgram->render(&preSwapFramebufferReference, preSwapX1, preSwapY1, preSwapX2, preSwapY2, m_preSwapDrawType);
492
493		readPixels(m_gl, &preSwapFramebuffer);
494	}
495
496	m_eglSurface->swapBuffers();
497
498	if (m_postSwapDrawType != DRAWTYPE_NONE)
499	{
500		m_refProgram->render(&postSwapFramebufferReference, postSwapX1, postSwapY1, postSwapX2, postSwapY2, m_postSwapDrawType);
501		m_gles2Program->render(width, height, postSwapX1, postSwapY1, postSwapX2, postSwapY2, m_postSwapDrawType);
502	}
503
504	readPixels(m_gl, &postSwapFramebuffer);
505
506	bool isOk = true;
507
508	if (m_preserveColorbuffer)
509	{
510		if (m_readPixelsBeforeSwap)
511			isOk = isOk && compareToReference(log, "Compare pre-swap framebuffer to reference", "Compare pre-swap framebuffer to reference", preSwapFramebufferReference, preSwapFramebuffer, 0, 0, width, height);
512
513		isOk = isOk && compareToReference(log, "Compare post-swap framebuffer to reference", "Compare post-swap framebuffer to reference", postSwapFramebufferReference, postSwapFramebuffer, 0, 0, width, height);
514
515		if (m_readPixelsBeforeSwap && m_postSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE)
516			isOk = isOk && comparePreAndPostSwapFramebuffers(log, preSwapFramebuffer, postSwapFramebuffer);
517	}
518	else
519	{
520		const int ox	= width/2;
521		const int oy	= height/2;
522
523		const int px	= width;
524		const int py	= height;
525
526		const int x1i	= (int)((px/2.0f) * postSwapX1 + ox);
527		const int y1i	= (int)((py/2.0f) * postSwapY1 + oy);
528
529		const int x2i	= (int)((px/2.0f) * postSwapX2 + ox);
530		const int y2i	= (int)((py/2.0f) * postSwapY2 + oy);
531
532		if (m_readPixelsBeforeSwap)
533			isOk = isOk && compareToReference(log, "Compare pre-swap framebuffer to reference", "Compare pre-swap framebuffer to reference", preSwapFramebufferReference, preSwapFramebuffer, 0, 0, width, height);
534
535		DE_ASSERT(m_postSwapDrawType != DRAWTYPE_NONE);
536		isOk = isOk && compareToReference(log, "Compare valid are of post-swap framebuffer to reference", "Compare valid area of post-swap framebuffer to reference", postSwapFramebufferReference, postSwapFramebuffer, x1i, y1i, x2i - x1i, y2i - y1i);
537	}
538
539	if (isOk)
540		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
541	else
542		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
543
544	return STOP;
545}
546
547string generateTestName (PreservingSwapTest::DrawType preSwapDrawType, PreservingSwapTest::DrawType postSwapDrawType)
548{
549	std::ostringstream stream;
550
551	if (preSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE && postSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE)
552		stream << "no_draw";
553	else
554	{
555		switch (preSwapDrawType)
556		{
557			case PreservingSwapTest::DRAWTYPE_NONE:
558				// Do nothing
559				break;
560
561			case PreservingSwapTest::DRAWTYPE_GLES2_RENDER:
562				stream << "pre_render";
563				break;
564
565			case PreservingSwapTest::DRAWTYPE_GLES2_CLEAR:
566				stream << "pre_clear";
567				break;
568
569			default:
570				DE_ASSERT(false);
571		}
572
573		if (preSwapDrawType != PreservingSwapTest::DRAWTYPE_NONE && postSwapDrawType != PreservingSwapTest::DRAWTYPE_NONE)
574			stream << "_";
575
576		switch (postSwapDrawType)
577		{
578			case PreservingSwapTest::DRAWTYPE_NONE:
579				// Do nothing
580				break;
581
582			case PreservingSwapTest::DRAWTYPE_GLES2_RENDER:
583				stream << "post_render";
584				break;
585
586			case PreservingSwapTest::DRAWTYPE_GLES2_CLEAR:
587				stream << "post_clear";
588				break;
589
590			default:
591				DE_ASSERT(false);
592		}
593	}
594
595	return stream.str();
596}
597
598} // anonymous
599
600PreservingSwapTests::PreservingSwapTests (EglTestContext& eglTestCtx)
601	: TestCaseGroup(eglTestCtx, "preserve_swap", "Color buffer preserving swap tests")
602{
603}
604
605void PreservingSwapTests::init (void)
606{
607	const PreservingSwapTest::DrawType preSwapDrawTypes[] =
608	{
609		PreservingSwapTest::DRAWTYPE_NONE,
610		PreservingSwapTest::DRAWTYPE_GLES2_CLEAR,
611		PreservingSwapTest::DRAWTYPE_GLES2_RENDER
612	};
613
614	const PreservingSwapTest::DrawType postSwapDrawTypes[] =
615	{
616		PreservingSwapTest::DRAWTYPE_NONE,
617		PreservingSwapTest::DRAWTYPE_GLES2_CLEAR,
618		PreservingSwapTest::DRAWTYPE_GLES2_RENDER
619	};
620
621	for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
622	{
623		const bool				preserve		= (preserveNdx == 0);
624		TestCaseGroup* const	preserveGroup	= new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
625
626		for (int readPixelsNdx = 0; readPixelsNdx < 2; readPixelsNdx++)
627		{
628			const bool				readPixelsBeforeSwap		= (readPixelsNdx == 1);
629			TestCaseGroup* const	readPixelsBeforeSwapGroup	= new TestCaseGroup(m_eglTestCtx, (readPixelsBeforeSwap ? "read_before_swap" : "no_read_before_swap"), "");
630
631			for (int preSwapDrawTypeNdx = 0; preSwapDrawTypeNdx < DE_LENGTH_OF_ARRAY(preSwapDrawTypes); preSwapDrawTypeNdx++)
632			{
633				const PreservingSwapTest::DrawType preSwapDrawType = preSwapDrawTypes[preSwapDrawTypeNdx];
634
635				for (int postSwapDrawTypeNdx = 0; postSwapDrawTypeNdx < DE_LENGTH_OF_ARRAY(postSwapDrawTypes); postSwapDrawTypeNdx++)
636				{
637					const PreservingSwapTest::DrawType postSwapDrawType = postSwapDrawTypes[postSwapDrawTypeNdx];
638
639					// If not preserving and rendering after swap, then there is nothing to verify
640					if (!preserve && postSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE)
641						continue;
642
643					const std::string name = generateTestName(preSwapDrawType, postSwapDrawType);
644
645					readPixelsBeforeSwapGroup->addChild(new PreservingSwapTest(m_eglTestCtx, preserve, readPixelsBeforeSwap, preSwapDrawType, postSwapDrawType, name.c_str(), ""));
646				}
647			}
648
649			preserveGroup->addChild(readPixelsBeforeSwapGroup);
650		}
651
652		addChild(preserveGroup);
653	}
654}
655
656} // egl
657} // deqp
658