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 EGL image tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "teglImageFormatTests.hpp"
25
26#include "deStringUtil.hpp"
27#include "deSTLUtil.hpp"
28
29#include "tcuTestLog.hpp"
30#include "tcuSurface.hpp"
31#include "tcuTexture.hpp"
32#include "tcuTextureUtil.hpp"
33#include "tcuImageCompare.hpp"
34#include "tcuCommandLine.hpp"
35
36#include "egluNativeDisplay.hpp"
37#include "egluNativeWindow.hpp"
38#include "egluNativePixmap.hpp"
39#include "egluConfigFilter.hpp"
40#include "egluUnique.hpp"
41#include "egluUtil.hpp"
42
43#include "eglwLibrary.hpp"
44#include "eglwEnums.hpp"
45
46#include "gluCallLogWrapper.hpp"
47#include "gluShaderProgram.hpp"
48#include "gluStrUtil.hpp"
49#include "gluTexture.hpp"
50#include "gluPixelTransfer.hpp"
51#include "gluObjectWrapper.hpp"
52#include "gluTextureUtil.hpp"
53
54#include "glwEnums.hpp"
55#include "glwFunctions.hpp"
56
57#include "teglImageUtil.hpp"
58#include "teglAndroidUtil.hpp"
59
60#include <vector>
61#include <string>
62#include <set>
63
64using std::vector;
65using std::set;
66using std::string;
67
68using de::MovePtr;
69using de::UniquePtr;
70
71using glu::Framebuffer;
72using glu::Renderbuffer;
73using glu::Texture;
74
75using eglu::UniqueImage;
76
77using tcu::ConstPixelBufferAccess;
78
79using namespace glw;
80using namespace eglw;
81
82namespace deqp
83{
84namespace egl
85{
86
87namespace
88{
89
90glu::ProgramSources programSources (const string& vertexSource, const string& fragmentSource)
91{
92	glu::ProgramSources sources;
93
94	sources << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource);
95
96	return sources;
97}
98
99class Program : public glu::ShaderProgram
100{
101public:
102	Program (const glw::Functions& gl, const char* vertexSource, const char* fragmentSource)
103		: glu::ShaderProgram(gl, programSources(vertexSource, fragmentSource)) {}
104};
105
106} // anonymous
107
108namespace Image
109{
110
111class ImageApi;
112
113class IllegalRendererException : public std::exception
114{
115};
116
117class Action
118{
119public:
120	virtual			~Action					(void) {}
121	virtual bool	invoke					(ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& refImg) const = 0;
122	virtual string	getRequiredExtension	(void) const = 0;
123};
124
125struct TestSpec
126{
127	std::string name;
128	std::string desc;
129
130	enum ApiContext
131	{
132		API_GLES2 = 0,
133		//API_VG
134		//API_GLES1
135
136		API_LAST
137	};
138
139	struct Operation
140	{
141		Operation (int apiIndex_, const Action& action_) : apiIndex(apiIndex_), action(&action_) {}
142		int				apiIndex;
143		const Action*	action;
144	};
145
146	vector<ApiContext>	contexts;
147	vector<Operation>	operations;
148
149};
150
151class ImageApi
152{
153public:
154					ImageApi		(const Library& egl, int contextId, EGLDisplay display, EGLSurface surface);
155	virtual 		~ImageApi		(void) {}
156
157protected:
158	const Library&	m_egl;
159	int				m_contextId;
160	EGLDisplay		m_display;
161	EGLSurface		m_surface;
162};
163
164ImageApi::ImageApi (const Library& egl, int contextId, EGLDisplay display, EGLSurface surface)
165	: m_egl				(egl)
166	, m_contextId		(contextId)
167	, m_display			(display)
168	, m_surface			(surface)
169{
170}
171
172class GLES2ImageApi : public ImageApi, private glu::CallLogWrapper
173{
174public:
175	class GLES2Action : public Action
176	{
177	public:
178		bool				invoke					(ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const;
179		virtual bool		invokeGLES2				(GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const = 0;
180	};
181
182	class Create : public GLES2Action
183	{
184	public:
185								Create					(MovePtr<ImageSource> imgSource) : m_imgSource(imgSource) {}
186		string					getRequiredExtension	(void) const { return m_imgSource->getRequiredExtension(); }
187		bool					invokeGLES2				(GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const;
188		glw::GLenum				getEffectiveFormat		(void) const { return m_imgSource->getEffectiveFormat(); }
189
190	private:
191		UniquePtr<ImageSource>	m_imgSource;
192	};
193
194	class Render : public GLES2Action
195	{
196	public:
197		string				getRequiredExtension	(void) const { return "GL_OES_EGL_image"; }
198	};
199
200	class RenderTexture2D				: public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
201	class RenderTextureCubemap			: public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
202	class RenderReadPixelsRenderbuffer	: public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
203	class RenderDepthbuffer				: public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
204	class RenderStencilbuffer			: public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
205	class RenderTryAll					: public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
206
207	class Modify : public GLES2Action
208	{
209	public:
210		string				getRequiredExtension	(void) const { return "GL_OES_EGL_image"; }
211	};
212
213	class ModifyTexSubImage : public Modify
214	{
215	public:
216							ModifyTexSubImage		(GLenum format, GLenum type) : m_format(format), m_type(type) {}
217		bool				invokeGLES2				(GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const;
218		GLenum				getFormat				(void) const { return m_format; }
219		GLenum				getType					(void) const { return m_type; }
220
221	private:
222		GLenum				m_format;
223		GLenum				m_type;
224	};
225
226	class ModifyRenderbuffer : public Modify
227	{
228	public:
229		bool				invokeGLES2				(GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const;
230
231	protected:
232		virtual void		initializeRbo			(GLES2ImageApi& api, GLuint rbo, tcu::Texture2D& ref) const = 0;
233	};
234
235	class ModifyRenderbufferClearColor : public ModifyRenderbuffer
236	{
237	public:
238					ModifyRenderbufferClearColor	(tcu::Vec4 color) : m_color(color) {}
239
240	protected:
241		void		initializeRbo					(GLES2ImageApi& api, GLuint rbo, tcu::Texture2D& ref) const;
242
243		tcu::Vec4	m_color;
244	};
245
246	class ModifyRenderbufferClearDepth : public ModifyRenderbuffer
247	{
248	public:
249					ModifyRenderbufferClearDepth	(GLfloat depth) : m_depth(depth) {}
250
251	protected:
252		void		initializeRbo					(GLES2ImageApi& api, GLuint rbo, tcu::Texture2D& ref) const;
253
254		GLfloat		m_depth;
255	};
256
257	class ModifyRenderbufferClearStencil : public ModifyRenderbuffer
258	{
259	public:
260					ModifyRenderbufferClearStencil	(GLint stencil) : m_stencil(stencil) {}
261
262	protected:
263		void		initializeRbo					(GLES2ImageApi& api, GLuint rbo, tcu::Texture2D& ref) const;
264
265		GLint		m_stencil;
266	};
267
268					GLES2ImageApi					(const Library& egl, const glw::Functions& gl, int contextId, tcu::TestLog& log, EGLDisplay display, EGLSurface surface, EGLConfig config);
269					~GLES2ImageApi					(void);
270
271private:
272	EGLContext					m_context;
273	const glw::Functions&		m_gl;
274
275	MovePtr<UniqueImage>		createImage			(const ImageSource& source, const ClientBuffer& buffer) const;
276};
277
278GLES2ImageApi::GLES2ImageApi (const Library& egl, const glw::Functions& gl, int contextId, tcu::TestLog& log, EGLDisplay display, EGLSurface surface, EGLConfig config)
279	: ImageApi				(egl, contextId, display, surface)
280	, glu::CallLogWrapper	(gl, log)
281	, m_context				(DE_NULL)
282	, m_gl					(gl)
283{
284	const EGLint attriblist[] =
285	{
286		EGL_CONTEXT_CLIENT_VERSION, 2,
287		EGL_NONE
288	};
289
290	EGLint configId = -1;
291	EGLU_CHECK_CALL(m_egl, getConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId));
292	getLog() << tcu::TestLog::Message << "Creating gles2 context with config id: " << configId << " context: " << m_contextId << tcu::TestLog::EndMessage;
293	egl.bindAPI(EGL_OPENGL_ES_API);
294	m_context = m_egl.createContext(m_display, config, EGL_NO_CONTEXT, attriblist);
295	EGLU_CHECK_MSG(m_egl, "Failed to create GLES2 context");
296
297	egl.makeCurrent(display, m_surface, m_surface, m_context);
298	EGLU_CHECK_MSG(m_egl, "Failed to make context current");
299}
300
301GLES2ImageApi::~GLES2ImageApi (void)
302{
303	m_egl.makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
304	m_egl.destroyContext(m_display, m_context);
305}
306
307bool GLES2ImageApi::GLES2Action::invoke (ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const
308{
309	GLES2ImageApi& gles2Api = dynamic_cast<GLES2ImageApi&>(api);
310
311	gles2Api.m_egl.makeCurrent(gles2Api.m_display, gles2Api.m_surface, gles2Api.m_surface, gles2Api.m_context);
312	return invokeGLES2(gles2Api, image, ref);
313}
314
315
316bool GLES2ImageApi::Create::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const
317{
318	de::UniquePtr<ClientBuffer>	buffer	(m_imgSource->createBuffer(api.m_gl, &ref));
319	image = api.createImage(*m_imgSource, *buffer);
320	return true;
321}
322
323MovePtr<UniqueImage> GLES2ImageApi::createImage (const ImageSource& source, const ClientBuffer& buffer) const
324{
325	const EGLImageKHR image = source.createImage(m_egl, m_display, m_context, buffer.get());
326	return MovePtr<UniqueImage>(new UniqueImage(m_egl, m_display, image));
327}
328
329static void imageTargetTexture2D (const Library& egl, const glw::Functions& gl, GLeglImageOES img)
330{
331	gl.eglImageTargetTexture2DOES(GL_TEXTURE_2D, img);
332	{
333		const GLenum error = gl.getError();
334
335		if (error == GL_INVALID_OPERATION)
336			TCU_THROW(NotSupportedError, "Creating texture2D from EGLImage type not supported");
337
338		GLU_EXPECT_NO_ERROR(error, "glEGLImageTargetTexture2DOES()");
339		EGLU_CHECK_MSG(egl, "glEGLImageTargetTexture2DOES()");
340	}
341}
342
343static void imageTargetRenderbuffer (const Library& egl, const glw::Functions& gl, GLeglImageOES img)
344{
345	gl.eglImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, img);
346	{
347		const GLenum error = gl.getError();
348
349		if (error == GL_INVALID_OPERATION)
350			TCU_THROW(NotSupportedError, "Creating renderbuffer from EGLImage type not supported");
351
352		GLU_EXPECT_NO_ERROR(error, "glEGLImageTargetRenderbufferStorageOES()");
353		EGLU_CHECK_MSG(egl, "glEGLImageTargetRenderbufferStorageOES()");
354	}
355}
356
357static void framebufferRenderbuffer (const glw::Functions& gl, GLenum attachment, GLuint rbo)
358{
359	GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbo));
360	TCU_CHECK_AND_THROW(NotSupportedError,
361						gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
362						("EGLImage as " + string(glu::getFramebufferAttachmentName(attachment)) + " not supported").c_str());
363}
364
365static const float squareTriangleCoords[] =
366{
367	-1.0, -1.0,
368	1.0, -1.0,
369	1.0,  1.0,
370
371	1.0,  1.0,
372	-1.0,  1.0,
373	-1.0, -1.0
374};
375
376bool GLES2ImageApi::RenderTexture2D::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
377{
378	const glw::Functions&	gl		= api.m_gl;
379	tcu::TestLog&			log		= api.getLog();
380	Texture					srcTex	(gl);
381
382	// Branch only taken in TryAll case
383	if (reference.getFormat().order == tcu::TextureFormat::DS || reference.getFormat().order == tcu::TextureFormat::D)
384		throw IllegalRendererException(); // Skip, GLES2 does not support sampling depth textures
385	if (reference.getFormat().order == tcu::TextureFormat::S)
386		throw IllegalRendererException(); // Skip, GLES2 does not support sampling stencil textures
387
388	gl.clearColor(0.0, 0.0, 0.0, 0.0);
389	gl.viewport(0, 0, reference.getWidth(), reference.getHeight());
390	gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
391	gl.disable(GL_DEPTH_TEST);
392
393	log << tcu::TestLog::Message << "Rendering EGLImage as GL_TEXTURE_2D in context: " << api.m_contextId << tcu::TestLog::EndMessage;
394	TCU_CHECK(**img != EGL_NO_IMAGE_KHR);
395
396	GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, *srcTex));
397	imageTargetTexture2D(api.m_egl, gl, **img);
398
399	GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
400	GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
401	GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
402	GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
403
404	const char* const vertexShader =
405		"attribute highp vec2 a_coord;\n"
406		"varying mediump vec2 v_texCoord;\n"
407		"void main(void) {\n"
408		"\tv_texCoord = vec2((a_coord.x + 1.0) * 0.5, (a_coord.y + 1.0) * 0.5);\n"
409		"\tgl_Position = vec4(a_coord, -0.1, 1.0);\n"
410		"}\n";
411
412	const char* const fragmentShader =
413		"varying mediump vec2 v_texCoord;\n"
414		"uniform sampler2D u_sampler;\n"
415		"void main(void) {\n"
416		"\tmediump vec4 texColor = texture2D(u_sampler, v_texCoord);\n"
417		"\tgl_FragColor = vec4(texColor);\n"
418		"}";
419
420	Program program(gl, vertexShader, fragmentShader);
421	TCU_CHECK(program.isOk());
422
423	GLuint glProgram = program.getProgram();
424	GLU_CHECK_GLW_CALL(gl, useProgram(glProgram));
425
426	GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord");
427	TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord");
428
429	GLuint samplerLoc = gl.getUniformLocation(glProgram, "u_sampler");
430	TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform u_sampler");
431
432	GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, *srcTex));
433	GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc, 0));
434	GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc));
435	GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords));
436
437	GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6));
438	GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc));
439	GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, 0));
440
441	tcu::Surface refSurface	(reference.getWidth(), reference.getHeight());
442	tcu::Surface screen		(reference.getWidth(), reference.getHeight());
443	GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr()));
444
445	tcu::copy(refSurface.getAccess(), reference.getLevel(0));
446
447	float	threshold	= 0.05f;
448	bool	match		= tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface, screen, threshold, tcu::COMPARE_LOG_RESULT);
449
450	return match;
451}
452
453bool GLES2ImageApi::RenderDepthbuffer::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
454{
455	const glw::Functions&	gl					= api.m_gl;
456	tcu::TestLog&			log					= api.getLog();
457	Framebuffer				framebuffer			(gl);
458	Renderbuffer			renderbufferColor	(gl);
459	Renderbuffer			renderbufferDepth	(gl);
460	const tcu::RGBA			compareThreshold	(32, 32, 32, 32); // layer colors are far apart, large thresholds are ok
461
462	// Branch only taken in TryAll case
463	if (reference.getFormat().order != tcu::TextureFormat::DS && reference.getFormat().order != tcu::TextureFormat::D)
464		throw IllegalRendererException(); // Skip, interpreting non-depth data as depth data is not meaningful
465
466	log << tcu::TestLog::Message << "Rendering with depth buffer" << tcu::TestLog::EndMessage;
467
468	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer));
469
470	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferColor));
471	GLU_CHECK_GLW_CALL(gl, renderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, reference.getWidth(), reference.getHeight()));
472	framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, *renderbufferColor);
473
474	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferDepth));
475	imageTargetRenderbuffer(api.m_egl, gl, **img);
476	framebufferRenderbuffer(gl, GL_DEPTH_ATTACHMENT, *renderbufferDepth);
477	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0));
478
479	GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight()));
480
481	// Render
482	const char* vertexShader =
483		"attribute highp vec2 a_coord;\n"
484		"uniform highp float u_depth;\n"
485		"void main(void) {\n"
486		"\tgl_Position = vec4(a_coord, u_depth, 1.0);\n"
487		"}\n";
488
489	const char* fragmentShader =
490		"uniform mediump vec4 u_color;\n"
491		"void main(void) {\n"
492		"\tgl_FragColor = u_color;\n"
493		"}";
494
495	Program program(gl, vertexShader, fragmentShader);
496	TCU_CHECK(program.isOk());
497
498	GLuint glProgram = program.getProgram();
499	GLU_CHECK_GLW_CALL(gl, useProgram(glProgram));
500
501	GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord");
502	TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord");
503
504	GLuint colorLoc = gl.getUniformLocation(glProgram, "u_color");
505	TCU_CHECK_MSG((int)colorLoc != (int)-1, "Couldn't find uniform u_color");
506
507	GLuint depthLoc = gl.getUniformLocation(glProgram, "u_depth");
508	TCU_CHECK_MSG((int)depthLoc != (int)-1, "Couldn't find uniform u_depth");
509
510	GLU_CHECK_GLW_CALL(gl, clearColor(0.5f, 1.0f, 0.5f, 1.0f));
511	GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT));
512
513	tcu::Vec4 depthLevelColors[] = {
514		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
515		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
516		tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
517		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
518		tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f),
519
520		tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
521		tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
522		tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f),
523		tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f),
524		tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f)
525	};
526
527	GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc));
528	GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords));
529
530	GLU_CHECK_GLW_CALL(gl, enable(GL_DEPTH_TEST));
531	GLU_CHECK_GLW_CALL(gl, depthFunc(GL_LESS));
532	GLU_CHECK_GLW_CALL(gl, depthMask(GL_FALSE));
533
534	for (int level = 0; level < DE_LENGTH_OF_ARRAY(depthLevelColors); level++)
535	{
536		const tcu::Vec4	color		= depthLevelColors[level];
537		const float		clipDepth	= ((float)(level + 1) * 0.1f) * 2.0f - 1.0f; // depth in clip coords
538
539		GLU_CHECK_GLW_CALL(gl, uniform4f(colorLoc, color.x(), color.y(), color.z(), color.w()));
540		GLU_CHECK_GLW_CALL(gl, uniform1f(depthLoc, clipDepth));
541		GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6));
542	}
543
544	GLU_CHECK_GLW_CALL(gl, depthMask(GL_TRUE));
545	GLU_CHECK_GLW_CALL(gl, disable(GL_DEPTH_TEST));
546	GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc));
547
548	const ConstPixelBufferAccess&	refAccess		= reference.getLevel(0);
549	tcu::Surface					screen			(reference.getWidth(), reference.getHeight());
550	tcu::Surface					referenceScreen	(reference.getWidth(), reference.getHeight());
551
552	gl.readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr());
553
554	for (int y = 0; y < reference.getHeight(); y++)
555	{
556		for (int x = 0; x < reference.getWidth(); x++)
557		{
558			tcu::Vec4 result = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f);
559
560			for (int level = 0; level < DE_LENGTH_OF_ARRAY(depthLevelColors); level++)
561			{
562				if ((float)(level + 1) * 0.1f < refAccess.getPixDepth(x, y))
563					result = depthLevelColors[level];
564			}
565
566			referenceScreen.getAccess().setPixel(result, x, y);
567		}
568	}
569
570	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0));
571	GLU_CHECK_GLW_CALL(gl, finish());
572
573	return tcu::pixelThresholdCompare(log, "Depth buffer rendering result", "Result from rendering with depth buffer", referenceScreen, screen, compareThreshold, tcu::COMPARE_LOG_RESULT);
574}
575
576bool GLES2ImageApi::RenderStencilbuffer::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
577{
578	// Branch only taken in TryAll case
579	if (reference.getFormat().order != tcu::TextureFormat::DS && reference.getFormat().order != tcu::TextureFormat::S)
580		throw IllegalRendererException(); // Skip, interpreting non-stencil data as stencil data is not meaningful
581
582	const glw::Functions&	gl					= api.m_gl;
583	tcu::TestLog&			log					= api.getLog();
584	Framebuffer				framebuffer			(gl);
585	Renderbuffer			renderbufferColor	(gl);
586	Renderbuffer			renderbufferStencil (gl);
587	const tcu::RGBA			compareThreshold	(32, 32, 32, 32); // layer colors are far apart, large thresholds are ok
588	const deUint32			numStencilBits		= tcu::getTextureFormatBitDepth(tcu::getEffectiveDepthStencilTextureFormat(reference.getLevel(0).getFormat(), tcu::Sampler::MODE_STENCIL)).x();
589	const deUint32			maxStencil			= deBitMask32(0, numStencilBits);
590
591	log << tcu::TestLog::Message << "Rendering with stencil buffer" << tcu::TestLog::EndMessage;
592
593	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer));
594
595	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferColor));
596	GLU_CHECK_GLW_CALL(gl, renderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, reference.getWidth(), reference.getHeight()));
597	framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, *renderbufferColor);
598
599	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferStencil));
600	imageTargetRenderbuffer(api.m_egl, gl, **img);
601	framebufferRenderbuffer(gl, GL_STENCIL_ATTACHMENT, *renderbufferStencil);
602	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0));
603
604	GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight()));
605
606	// Render
607	const char* vertexShader =
608		"attribute highp vec2 a_coord;\n"
609		"void main(void) {\n"
610		"\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
611		"}\n";
612
613	const char* fragmentShader =
614		"uniform mediump vec4 u_color;\n"
615		"void main(void) {\n"
616		"\tgl_FragColor = u_color;\n"
617		"}";
618
619	Program program(gl, vertexShader, fragmentShader);
620	TCU_CHECK(program.isOk());
621
622	GLuint glProgram = program.getProgram();
623	GLU_CHECK_GLW_CALL(gl, useProgram(glProgram));
624
625	GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord");
626	TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord");
627
628	GLuint colorLoc = gl.getUniformLocation(glProgram, "u_color");
629	TCU_CHECK_MSG((int)colorLoc != (int)-1, "Couldn't find uniform u_color");
630
631	GLU_CHECK_GLW_CALL(gl, clearColor(0.5f, 1.0f, 0.5f, 1.0f));
632	GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT));
633
634	tcu::Vec4 stencilLevelColors[] = {
635		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
636		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
637		tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
638		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
639		tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f),
640
641		tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
642		tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
643		tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f),
644		tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f),
645		tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f)
646	};
647
648	GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc));
649	GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords));
650
651	GLU_CHECK_GLW_CALL(gl, enable(GL_STENCIL_TEST));
652	GLU_CHECK_GLW_CALL(gl, stencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
653
654	for (int level = 0; level < DE_LENGTH_OF_ARRAY(stencilLevelColors); level++)
655	{
656		const tcu::Vec4	color	= stencilLevelColors[level];
657		const int		stencil	= (int)(((float)(level + 1) * 0.1f) * (float)maxStencil);
658
659		GLU_CHECK_GLW_CALL(gl, stencilFunc(GL_LESS, stencil, 0xFFFFFFFFu));
660		GLU_CHECK_GLW_CALL(gl, uniform4f(colorLoc, color.x(), color.y(), color.z(), color.w()));
661		GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6));
662	}
663
664	GLU_CHECK_GLW_CALL(gl, disable(GL_STENCIL_TEST));
665	GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc));
666
667	const ConstPixelBufferAccess&	refAccess		= reference.getLevel(0);
668	tcu::Surface					screen			(reference.getWidth(), reference.getHeight());
669	tcu::Surface					referenceScreen	(reference.getWidth(), reference.getHeight());
670
671	gl.readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr());
672
673	for (int y = 0; y < reference.getHeight(); y++)
674	for (int x = 0; x < reference.getWidth(); x++)
675	{
676		tcu::Vec4 result = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f);
677
678		for (int level = 0; level < DE_LENGTH_OF_ARRAY(stencilLevelColors); level++)
679		{
680			const int levelStencil = (int)(((float)(level + 1) * 0.1f) * (float)maxStencil);
681			if (levelStencil < refAccess.getPixStencil(x, y))
682				result = stencilLevelColors[level];
683		}
684
685		referenceScreen.getAccess().setPixel(result, x, y);
686	}
687
688	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0));
689	GLU_CHECK_GLW_CALL(gl, finish());
690
691	return tcu::pixelThresholdCompare(log, "StencilResult", "Result from rendering with stencil buffer", referenceScreen, screen, compareThreshold, tcu::COMPARE_LOG_RESULT);
692}
693
694bool GLES2ImageApi::RenderReadPixelsRenderbuffer::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
695{
696	const glw::Functions&	gl				= api.m_gl;
697	const tcu::IVec4		bitDepth		= tcu::getTextureFormatMantissaBitDepth(reference.getFormat());
698	const tcu::IVec4		threshold		(2 * (tcu::IVec4(1) << (tcu::IVec4(8) - bitDepth)));
699	const tcu::RGBA			threshold8		((deUint8)(de::clamp(threshold[0], 0, 255)), (deUint8)(de::clamp(threshold[1], 0, 255)), (deUint8)(de::clamp(threshold[2], 0, 255)), (deUint8)(de::clamp(threshold[3], 0, 255)));
700	tcu::TestLog&			log				= api.getLog();
701	Framebuffer				framebuffer		(gl);
702	Renderbuffer			renderbuffer	(gl);
703	tcu::Surface			screen			(reference.getWidth(), reference.getHeight());
704	tcu::Surface			refSurface		(reference.getWidth(), reference.getHeight());
705
706	// Branch only taken in TryAll case
707	if (reference.getFormat().order == tcu::TextureFormat::DS || reference.getFormat().order == tcu::TextureFormat::D)
708		throw IllegalRendererException(); // Skip, GLES2 does not support ReadPixels for depth attachments
709	if (reference.getFormat().order == tcu::TextureFormat::S)
710		throw IllegalRendererException(); // Skip, GLES2 does not support ReadPixels for stencil attachments
711
712	log << tcu::TestLog::Message << "Reading with ReadPixels from renderbuffer" << tcu::TestLog::EndMessage;
713
714	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer));
715	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer));
716	imageTargetRenderbuffer(api.m_egl, gl, **img);
717	framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, *renderbuffer);
718
719	GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight()));
720
721	gl.readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr());
722
723	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0));
724	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0));
725	GLU_CHECK_GLW_CALL(gl, finish());
726
727	tcu::copy(refSurface.getAccess(), reference.getLevel(0));
728
729	return tcu::pixelThresholdCompare(log, "Renderbuffer read", "Result from reading renderbuffer", refSurface, screen, threshold8, tcu::COMPARE_LOG_RESULT);
730
731}
732
733bool GLES2ImageApi::RenderTryAll::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
734{
735	bool										foundSupported			= false;
736	tcu::TestLog&								log						= api.getLog();
737	GLES2ImageApi::RenderTexture2D				renderTex2D;
738	GLES2ImageApi::RenderReadPixelsRenderbuffer	renderReadPixels;
739	GLES2ImageApi::RenderDepthbuffer			renderDepth;
740	GLES2ImageApi::RenderStencilbuffer			renderStencil;
741	Action*										actions[] 				= { &renderTex2D, &renderReadPixels, &renderDepth, &renderStencil };
742
743	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(actions); ++ndx)
744	{
745		try
746		{
747			if (!actions[ndx]->invoke(api, img, reference))
748				return false;
749
750			foundSupported = true;
751		}
752		catch (const tcu::NotSupportedError& error)
753		{
754			log << tcu::TestLog::Message << error.what() << tcu::TestLog::EndMessage;
755		}
756		catch (const IllegalRendererException&)
757		{
758			// not valid renderer
759		}
760	}
761
762	if (!foundSupported)
763		throw tcu::NotSupportedError("Rendering not supported", "", __FILE__, __LINE__);
764
765	return true;
766}
767
768bool GLES2ImageApi::ModifyTexSubImage::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
769{
770	const glw::Functions&	gl		= api.m_gl;
771	tcu::TestLog&			log		= api.getLog();
772	glu::Texture			srcTex	(gl);
773	const int				xOffset	= 8;
774	const int				yOffset	= 16;
775	const int				xSize	= de::clamp(16, 0, reference.getWidth() - xOffset);
776	const int				ySize	= de::clamp(16, 0, reference.getHeight() - yOffset);
777	tcu::Texture2D			src		(glu::mapGLTransferFormat(m_format, m_type), xSize, ySize);
778
779	log << tcu::TestLog::Message << "Modifying EGLImage with gl.texSubImage2D" << tcu::TestLog::EndMessage;
780
781	src.allocLevel(0);
782	tcu::fillWithComponentGradients(src.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
783
784	GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, *srcTex));
785	imageTargetTexture2D(api.m_egl, gl, **img);
786	GLU_CHECK_GLW_CALL(gl, texSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, src.getWidth(), src.getHeight(), m_format, m_type, src.getLevel(0).getDataPtr()));
787	GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, 0));
788	GLU_CHECK_GLW_CALL(gl, finish());
789
790	tcu::copy(tcu::getSubregion(reference.getLevel(0), xOffset, yOffset, 0, xSize, ySize, 1), src.getLevel(0));
791
792	return true;
793}
794
795bool GLES2ImageApi::ModifyRenderbuffer::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
796{
797	const glw::Functions&	gl				= api.m_gl;
798	tcu::TestLog&			log				= api.getLog();
799	glu::Framebuffer		framebuffer		(gl);
800	glu::Renderbuffer		renderbuffer	(gl);
801
802	log << tcu::TestLog::Message << "Modifying EGLImage with glClear to renderbuffer" << tcu::TestLog::EndMessage;
803
804	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer));
805	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer));
806
807	imageTargetRenderbuffer(api.m_egl, gl, **img);
808
809	initializeRbo(api, *renderbuffer, reference);
810
811	GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0));
812	GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0));
813
814	GLU_CHECK_GLW_CALL(gl, finish());
815
816	return true;
817}
818
819void GLES2ImageApi::ModifyRenderbufferClearColor::initializeRbo (GLES2ImageApi& api, GLuint renderbuffer, tcu::Texture2D& reference) const
820{
821	const glw::Functions&	gl		= api.m_gl;
822
823	framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, renderbuffer);
824
825	GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight()));
826	GLU_CHECK_GLW_CALL(gl, clearColor(m_color.x(), m_color.y(), m_color.z(), m_color.w()));
827	GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT));
828
829	tcu::clear(reference.getLevel(0), m_color);
830}
831
832void GLES2ImageApi::ModifyRenderbufferClearDepth::initializeRbo (GLES2ImageApi& api, GLuint renderbuffer, tcu::Texture2D& reference) const
833{
834	const glw::Functions&	gl		= api.m_gl;
835
836	framebufferRenderbuffer(gl, GL_DEPTH_ATTACHMENT, renderbuffer);
837
838	GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight()));
839	GLU_CHECK_GLW_CALL(gl, clearDepthf(m_depth));
840	GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT));
841
842	tcu::clearDepth(reference.getLevel(0), m_depth);
843}
844
845void GLES2ImageApi::ModifyRenderbufferClearStencil::initializeRbo (GLES2ImageApi& api, GLuint renderbuffer, tcu::Texture2D& reference) const
846{
847	const glw::Functions&	gl		= api.m_gl;
848
849	framebufferRenderbuffer(gl, GL_STENCIL_ATTACHMENT, renderbuffer);
850
851	GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight()));
852	GLU_CHECK_GLW_CALL(gl, clearStencil(m_stencil));
853	GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT));
854
855	tcu::clearStencil(reference.getLevel(0), m_stencil);
856}
857
858class ImageFormatCase : public TestCase, private glu::CallLogWrapper
859{
860public:
861						ImageFormatCase		(EglTestContext& eglTestCtx, const TestSpec& spec);
862						~ImageFormatCase	(void);
863
864	void				init				(void);
865	void				deinit				(void);
866	IterateResult		iterate				(void);
867	void				checkExtensions		(void);
868
869private:
870	EGLConfig			getConfig			(void);
871
872	const TestSpec		m_spec;
873
874	vector<ImageApi*>	m_apiContexts;
875
876	EGLDisplay			m_display;
877	eglu::NativeWindow*	m_window;
878	EGLSurface			m_surface;
879	EGLConfig			m_config;
880	int					m_curIter;
881	MovePtr<UniqueImage>m_img;
882	tcu::Texture2D		m_refImg;
883	glw::Functions		m_gl;
884};
885
886EGLConfig ImageFormatCase::getConfig (void)
887{
888	const EGLint attribList[] =
889	{
890		EGL_RENDERABLE_TYPE, 	EGL_OPENGL_ES2_BIT,
891		EGL_SURFACE_TYPE,	 	EGL_WINDOW_BIT,
892		EGL_RED_SIZE,			8,
893		EGL_BLUE_SIZE,			8,
894		EGL_GREEN_SIZE,			8,
895		EGL_ALPHA_SIZE,			8,
896		EGL_DEPTH_SIZE,			8,
897		EGL_NONE
898	};
899
900	return eglu::chooseSingleConfig(m_eglTestCtx.getLibrary(), m_display, attribList);
901}
902
903ImageFormatCase::ImageFormatCase (EglTestContext& eglTestCtx, const TestSpec& spec)
904	: TestCase				(eglTestCtx, spec.name.c_str(), spec.desc.c_str())
905	, glu::CallLogWrapper	(m_gl, eglTestCtx.getTestContext().getLog())
906	, m_spec				(spec)
907	, m_display				(EGL_NO_DISPLAY)
908	, m_window				(DE_NULL)
909	, m_surface				(EGL_NO_SURFACE)
910	, m_config				(0)
911	, m_curIter				(0)
912	, m_refImg				(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1)
913{
914}
915
916ImageFormatCase::~ImageFormatCase (void)
917{
918	deinit();
919}
920
921void ImageFormatCase::checkExtensions (void)
922{
923	const Library&			egl		= m_eglTestCtx.getLibrary();
924	const EGLDisplay		dpy		= m_display;
925	set<string>				exts;
926	const vector<string>	glExts	= de::splitString((const char*) m_gl.getString(GL_EXTENSIONS));
927	const vector<string>	eglExts	= eglu::getDisplayExtensions(egl, dpy);
928
929	exts.insert(glExts.begin(), glExts.end());
930	exts.insert(eglExts.begin(), eglExts.end());
931
932	if (eglu::getVersion(egl, dpy) >= eglu::Version(1, 5))
933	{
934		// EGL 1.5 has built-in support for EGLImage and GL sources
935		exts.insert("EGL_KHR_image_base");
936		exts.insert("EGL_KHR_gl_texture_2D_image");
937		exts.insert("EGL_KHR_gl_texture_cubemap_image");
938		exts.insert("EGL_KHR_gl_renderbuffer_image");
939	}
940
941	if (!de::contains(exts, "EGL_KHR_image_base") && !de::contains(exts, "EGL_KHR_image"))
942	{
943		getLog() << tcu::TestLog::Message
944				 << "EGL version is under 1.5 and neither EGL_KHR_image nor EGL_KHR_image_base is supported."
945				 << "One should be supported."
946				 << tcu::TestLog::EndMessage;
947		TCU_THROW(NotSupportedError, "Extension not supported: EGL_KHR_image_base");
948	}
949
950	for (int operationNdx = 0; operationNdx < (int)m_spec.operations.size(); operationNdx++)
951	{
952		const TestSpec::Operation&	op	= m_spec.operations[operationNdx];
953		const string				ext	= op.action->getRequiredExtension();
954
955		if (!de::contains(exts, ext))
956			TCU_THROW_EXPR(NotSupportedError, "Extension not supported", ext.c_str());
957	}
958}
959
960void ImageFormatCase::init (void)
961{
962	const Library&						egl				= m_eglTestCtx.getLibrary();
963	const eglu::NativeWindowFactory&	windowFactory	= eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
964
965	try
966	{
967		m_display	= eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
968		m_config	= getConfig();
969		m_window	= windowFactory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_display, m_config, DE_NULL, eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
970		m_surface	= eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_display, m_config, DE_NULL);
971
972		{
973			const char* extensions[] = { "GL_OES_EGL_image" };
974			m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2, 0), DE_LENGTH_OF_ARRAY(extensions), &extensions[0]);
975		}
976
977		for (int contextNdx = 0; contextNdx < (int)m_spec.contexts.size(); contextNdx++)
978		{
979			ImageApi* api = DE_NULL;
980			switch (m_spec.contexts[contextNdx])
981			{
982				case TestSpec::API_GLES2:
983				{
984					api = new GLES2ImageApi(egl, m_gl, contextNdx, getLog(), m_display, m_surface, m_config);
985					break;
986				}
987
988				default:
989					DE_ASSERT(false);
990					break;
991			}
992			m_apiContexts.push_back(api);
993		}
994		checkExtensions();
995	}
996	catch (...)
997	{
998		deinit();
999		throw;
1000	}
1001}
1002
1003void ImageFormatCase::deinit (void)
1004{
1005	const Library& egl = m_eglTestCtx.getLibrary();
1006
1007	for (int contexNdx = 0 ; contexNdx < (int)m_apiContexts.size(); contexNdx++)
1008		delete m_apiContexts[contexNdx];
1009
1010	m_apiContexts.clear();
1011
1012	if (m_surface != EGL_NO_SURFACE)
1013	{
1014		egl.destroySurface(m_display, m_surface);
1015		m_surface = EGL_NO_SURFACE;
1016	}
1017
1018	delete m_window;
1019	m_window = DE_NULL;
1020
1021	if (m_display != EGL_NO_DISPLAY)
1022	{
1023		egl.terminate(m_display);
1024		m_display = EGL_NO_DISPLAY;
1025	}
1026}
1027
1028TestCase::IterateResult ImageFormatCase::iterate (void)
1029{
1030	const TestSpec::Operation&	op		= m_spec.operations[m_curIter++];
1031	ImageApi&					api		= *m_apiContexts[op.apiIndex];
1032	const bool					isOk	= op.action->invoke(api, m_img, m_refImg);
1033
1034	if (isOk && m_curIter < (int)m_spec.operations.size())
1035		return CONTINUE;
1036	else if (isOk)
1037		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1038	else
1039		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1040
1041	return STOP;
1042}
1043
1044struct LabeledAction
1045{
1046	string			label;
1047	MovePtr<Action>	action;
1048};
1049
1050// A simple vector mockup that we need because MovePtr isn't copy-constructible.
1051struct LabeledActions
1052{
1053					LabeledActions	(void) : m_numActions(0){}
1054	LabeledAction&	operator[]		(int ndx)				{ DE_ASSERT(0 <= ndx && ndx < m_numActions); return m_actions[ndx]; }
1055	void			add				(const string& label, MovePtr<Action> action);
1056	int				size			(void) const			{ return m_numActions; }
1057private:
1058	LabeledAction	m_actions[32];
1059	int				m_numActions;
1060};
1061
1062void LabeledActions::add (const string& label, MovePtr<Action> action)
1063{
1064	DE_ASSERT(m_numActions < DE_LENGTH_OF_ARRAY(m_actions));
1065	m_actions[m_numActions].label = label;
1066	m_actions[m_numActions].action = action;
1067	++m_numActions;
1068}
1069
1070class ImageTests : public TestCaseGroup
1071{
1072protected:
1073					ImageTests						(EglTestContext& eglTestCtx, const string& name, const string& desc)
1074						: TestCaseGroup(eglTestCtx, name.c_str(), desc.c_str()) {}
1075
1076	void			addCreateTexture				(const string& name, EGLenum source, GLenum internalFormat, GLenum format, GLenum type);
1077	void			addCreateRenderbuffer			(const string& name, GLenum format);
1078	void			addCreateAndroidNative			(const string& name, GLenum format);
1079	void			addCreateTexture2DActions		(const string& prefix);
1080	void			addCreateTextureCubemapActions	(const string& suffix, GLenum internalFormat, GLenum format, GLenum type);
1081	void			addCreateRenderbufferActions	(void);
1082	void			addCreateAndroidNativeActions	(void);
1083
1084	LabeledActions	m_createActions;
1085};
1086
1087void ImageTests::addCreateTexture (const string& name, EGLenum source, GLenum internalFormat, GLenum format, GLenum type)
1088{
1089	m_createActions.add(name, MovePtr<Action>(new GLES2ImageApi::Create(createTextureImageSource(source, internalFormat, format, type))));
1090}
1091
1092void ImageTests::addCreateRenderbuffer (const string& name, GLenum format)
1093{
1094	m_createActions.add(name, MovePtr<Action>(new GLES2ImageApi::Create(createRenderbufferImageSource(format))));
1095}
1096
1097void ImageTests::addCreateAndroidNative (const string& name, GLenum format)
1098{
1099	m_createActions.add(name, MovePtr<Action>(new GLES2ImageApi::Create(createAndroidNativeImageSource(format))));
1100}
1101
1102void ImageTests::addCreateTexture2DActions (const string& prefix)
1103{
1104	addCreateTexture(prefix + "rgb8", 		EGL_GL_TEXTURE_2D_KHR,	GL_RGB,		GL_RGB,		GL_UNSIGNED_BYTE);
1105	addCreateTexture(prefix + "rgb565",		EGL_GL_TEXTURE_2D_KHR,	GL_RGB,		GL_RGB,		GL_UNSIGNED_SHORT_5_6_5);
1106	addCreateTexture(prefix + "rgba8",		EGL_GL_TEXTURE_2D_KHR,	GL_RGBA,	GL_RGBA,	GL_UNSIGNED_BYTE);
1107	addCreateTexture(prefix + "rgb5_a1",	EGL_GL_TEXTURE_2D_KHR,	GL_RGBA,	GL_RGBA,	GL_UNSIGNED_SHORT_5_5_5_1);
1108	addCreateTexture(prefix + "rgba4",		EGL_GL_TEXTURE_2D_KHR,	GL_RGBA,	GL_RGBA,	GL_UNSIGNED_SHORT_4_4_4_4);
1109}
1110
1111void ImageTests::addCreateTextureCubemapActions (const string& suffix, GLenum internalFormat, GLenum format, GLenum type)
1112{
1113	addCreateTexture("cubemap_positive_x" + suffix,	EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, internalFormat,	format,	type);
1114	addCreateTexture("cubemap_positive_y" + suffix,	EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR, internalFormat,	format,	type);
1115	addCreateTexture("cubemap_positive_z" + suffix,	EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR, internalFormat,	format,	type);
1116	addCreateTexture("cubemap_negative_x" + suffix,	EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR, internalFormat,	format,	type);
1117	addCreateTexture("cubemap_negative_y" + suffix,	EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR, internalFormat,	format,	type);
1118	addCreateTexture("cubemap_negative_z" + suffix,	EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR, internalFormat,	format,	type);
1119}
1120
1121void ImageTests::addCreateRenderbufferActions (void)
1122{
1123	addCreateRenderbuffer("renderbuffer_rgba4",		GL_RGBA4);
1124	addCreateRenderbuffer("renderbuffer_rgb5_a1",	GL_RGB5_A1);
1125	addCreateRenderbuffer("renderbuffer_rgb565",	GL_RGB565);
1126	addCreateRenderbuffer("renderbuffer_depth16",	GL_DEPTH_COMPONENT16);
1127	addCreateRenderbuffer("renderbuffer_stencil",	GL_STENCIL_INDEX8);
1128}
1129
1130void ImageTests::addCreateAndroidNativeActions (void)
1131{
1132	addCreateAndroidNative("android_native_rgb565",		GL_RGB565);
1133	addCreateAndroidNative("android_native_rgb8",		GL_RGB8);
1134	addCreateAndroidNative("android_native_rgba4",		GL_RGBA4);
1135	addCreateAndroidNative("android_native_rgb5_a1",	GL_RGB5_A1);
1136	addCreateAndroidNative("android_native_rgba8",		GL_RGBA8);
1137}
1138
1139class RenderTests : public ImageTests
1140{
1141protected:
1142											RenderTests				(EglTestContext& eglTestCtx, const string& name, const string& desc)
1143												: ImageTests			(eglTestCtx, name, desc) {}
1144
1145	void									addRenderActions		(void);
1146	LabeledActions							m_renderActions;
1147};
1148
1149void RenderTests::addRenderActions (void)
1150{
1151	m_renderActions.add("texture",			MovePtr<Action>(new GLES2ImageApi::RenderTexture2D()));
1152	m_renderActions.add("read_pixels",		MovePtr<Action>(new GLES2ImageApi::RenderReadPixelsRenderbuffer()));
1153	m_renderActions.add("depth_buffer",		MovePtr<Action>(new GLES2ImageApi::RenderDepthbuffer()));
1154	m_renderActions.add("stencil_buffer",	MovePtr<Action>(new GLES2ImageApi::RenderStencilbuffer()));
1155}
1156
1157class SimpleCreationTests : public RenderTests
1158{
1159public:
1160			SimpleCreationTests		(EglTestContext& eglTestCtx, const string& name, const string& desc) : RenderTests(eglTestCtx, name, desc) {}
1161	void	init					(void);
1162};
1163
1164bool isDepthFormat (GLenum format)
1165{
1166	switch (format)
1167	{
1168		case GL_RGB:
1169		case GL_RGB8:
1170		case GL_RGB565:
1171		case GL_RGBA:
1172		case GL_RGBA4:
1173		case GL_RGBA8:
1174		case GL_RGB5_A1:
1175			return false;
1176
1177		case GL_DEPTH_COMPONENT16:
1178			return true;
1179
1180		case GL_STENCIL_INDEX8:
1181			return false;
1182
1183		default:
1184			DE_ASSERT(false);
1185			return false;
1186	}
1187}
1188
1189bool isStencilFormat (GLenum format)
1190{
1191	switch (format)
1192	{
1193		case GL_RGB:
1194		case GL_RGB8:
1195		case GL_RGB565:
1196		case GL_RGBA:
1197		case GL_RGBA4:
1198		case GL_RGBA8:
1199		case GL_RGB5_A1:
1200			return false;
1201
1202		case GL_DEPTH_COMPONENT16:
1203			return false;
1204
1205		case GL_STENCIL_INDEX8:
1206			return true;
1207
1208		default:
1209			DE_ASSERT(false);
1210			return false;
1211	}
1212}
1213
1214bool isCompatibleCreateAndRenderActions (const Action& create, const Action& render)
1215{
1216	if (const GLES2ImageApi::Create* gles2Create = dynamic_cast<const GLES2ImageApi::Create*>(&create))
1217	{
1218		const GLenum createFormat = gles2Create->getEffectiveFormat();
1219
1220		if (dynamic_cast<const GLES2ImageApi::RenderTexture2D*>(&render))
1221		{
1222			// GLES2 does not have depth or stencil textures
1223			if (isDepthFormat(createFormat) || isStencilFormat(createFormat))
1224				return false;
1225		}
1226
1227		if (dynamic_cast<const GLES2ImageApi::RenderReadPixelsRenderbuffer*>(&render))
1228		{
1229			// GLES2 does not support readPixels for depth or stencil
1230			if (isDepthFormat(createFormat) || isStencilFormat(createFormat))
1231				return false;
1232		}
1233
1234		if (dynamic_cast<const GLES2ImageApi::RenderDepthbuffer*>(&render))
1235		{
1236			// Copying non-depth data to depth renderbuffer and expecting meaningful
1237			// results just doesn't make any sense.
1238			if (!isDepthFormat(createFormat))
1239				return false;
1240		}
1241
1242		if (dynamic_cast<const GLES2ImageApi::RenderStencilbuffer*>(&render))
1243		{
1244			// Copying non-stencil data to stencil renderbuffer and expecting meaningful
1245			// results just doesn't make any sense.
1246			if (!isStencilFormat(createFormat))
1247				return false;
1248		}
1249
1250		return true;
1251	}
1252	else
1253		DE_ASSERT(false);
1254
1255	return false;
1256}
1257
1258void SimpleCreationTests::init (void)
1259{
1260	addCreateTexture2DActions("texture_");
1261	addCreateTextureCubemapActions("_rgba", GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1262	addCreateTextureCubemapActions("_rgb", GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);
1263	addCreateRenderbufferActions();
1264	addCreateAndroidNativeActions();
1265	addRenderActions();
1266
1267	for (int createNdx = 0; createNdx < m_createActions.size(); createNdx++)
1268	{
1269		const LabeledAction& createAction = m_createActions[createNdx];
1270
1271		for (int renderNdx = 0; renderNdx < m_renderActions.size(); renderNdx++)
1272		{
1273			const LabeledAction&	renderAction	= m_renderActions[renderNdx];
1274			TestSpec				spec;
1275
1276			if (!isCompatibleCreateAndRenderActions(*createAction.action, *renderAction.action))
1277				continue;
1278
1279			spec.name = std::string("gles2_") + createAction.label + "_" + renderAction.label;
1280			spec.desc = spec.name;
1281			spec.contexts.push_back(TestSpec::API_GLES2);
1282			spec.operations.push_back(TestSpec::Operation(0, *createAction.action));
1283			spec.operations.push_back(TestSpec::Operation(0, *renderAction.action));
1284
1285			addChild(new ImageFormatCase(m_eglTestCtx, spec));
1286		}
1287	}
1288}
1289
1290TestCaseGroup* createSimpleCreationTests (EglTestContext& eglTestCtx, const string& name, const string& desc)
1291{
1292	return new SimpleCreationTests(eglTestCtx, name, desc);
1293}
1294
1295bool isCompatibleFormats (GLenum createFormat, GLenum modifyFormat, GLenum modifyType)
1296{
1297	switch (modifyFormat)
1298	{
1299		case GL_RGB:
1300			switch (modifyType)
1301			{
1302				case GL_UNSIGNED_BYTE:
1303					return createFormat == GL_RGB
1304							|| createFormat == GL_RGB8
1305							|| createFormat == GL_RGB565
1306							|| createFormat == GL_SRGB8;
1307
1308				case GL_BYTE:
1309					return createFormat == GL_RGB8_SNORM;
1310
1311				case GL_UNSIGNED_SHORT_5_6_5:
1312					return createFormat == GL_RGB
1313							|| createFormat == GL_RGB565;
1314
1315				case GL_UNSIGNED_INT_10F_11F_11F_REV:
1316					return createFormat == GL_R11F_G11F_B10F;
1317
1318				case GL_UNSIGNED_INT_5_9_9_9_REV:
1319					return createFormat == GL_RGB9_E5;
1320
1321				case GL_HALF_FLOAT:
1322					return createFormat == GL_RGB16F
1323							|| createFormat == GL_R11F_G11F_B10F
1324							|| createFormat == GL_RGB9_E5;
1325
1326				case GL_FLOAT:
1327					return createFormat == GL_RGB16F
1328							|| createFormat == GL_RGB32F
1329							|| createFormat == GL_R11F_G11F_B10F
1330							|| createFormat == GL_RGB9_E5;
1331
1332				default:
1333					DE_FATAL("Unknown modify type");
1334					return false;
1335			}
1336
1337		case GL_RGBA:
1338			switch (modifyType)
1339			{
1340				case GL_UNSIGNED_BYTE:
1341					return createFormat == GL_RGBA8
1342						|| createFormat == GL_RGB5_A1
1343						|| createFormat == GL_RGBA4
1344						|| createFormat == GL_SRGB8_ALPHA8
1345						|| createFormat == GL_RGBA;
1346
1347				case GL_UNSIGNED_SHORT_4_4_4_4:
1348					return createFormat == GL_RGBA4
1349						|| createFormat == GL_RGBA;
1350
1351				case GL_UNSIGNED_SHORT_5_5_5_1:
1352					return createFormat == GL_RGB5_A1
1353						|| createFormat == GL_RGBA;
1354
1355				case GL_UNSIGNED_INT_2_10_10_10_REV:
1356					return createFormat == GL_RGB10_A2
1357						|| createFormat == GL_RGB5_A1;
1358
1359				case GL_HALF_FLOAT:
1360					return createFormat == GL_RGBA16F;
1361
1362				case GL_FLOAT:
1363					return createFormat == GL_RGBA16F
1364						|| createFormat == GL_RGBA32F;
1365
1366				default:
1367					DE_FATAL("Unknown modify type");
1368					return false;
1369			};
1370
1371		default:
1372			DE_FATAL("Unknown modify format");
1373			return false;
1374	}
1375}
1376
1377bool isCompatibleCreateAndModifyActions (const Action& create, const Action& modify)
1378{
1379	if (const GLES2ImageApi::Create* gles2Create = dynamic_cast<const GLES2ImageApi::Create*>(&create))
1380	{
1381		const GLenum createFormat = gles2Create->getEffectiveFormat();
1382
1383		if (const GLES2ImageApi::ModifyTexSubImage* gles2TexSubImageModify = dynamic_cast<const GLES2ImageApi::ModifyTexSubImage*>(&modify))
1384		{
1385			const GLenum modifyFormat 	= gles2TexSubImageModify->getFormat();
1386			const GLenum modifyType		= gles2TexSubImageModify->getType();
1387
1388			return isCompatibleFormats(createFormat, modifyFormat, modifyType);
1389		}
1390
1391		if (dynamic_cast<const GLES2ImageApi::ModifyRenderbufferClearColor*>(&modify))
1392		{
1393			// reintepreting color as non-color is not meaningful
1394			if (isDepthFormat(createFormat) || isStencilFormat(createFormat))
1395				return false;
1396		}
1397
1398		if (dynamic_cast<const GLES2ImageApi::ModifyRenderbufferClearDepth*>(&modify))
1399		{
1400			// reintepreting depth as non-depth is not meaningful
1401			if (!isDepthFormat(createFormat))
1402				return false;
1403		}
1404
1405		if (dynamic_cast<const GLES2ImageApi::ModifyRenderbufferClearStencil*>(&modify))
1406		{
1407			// reintepreting stencil as non-stencil is not meaningful
1408			if (!isStencilFormat(createFormat))
1409				return false;
1410		}
1411
1412		return true;
1413	}
1414	else
1415		DE_ASSERT(false);
1416
1417	return false;
1418}
1419
1420class MultiContextRenderTests : public RenderTests
1421{
1422public:
1423					MultiContextRenderTests		(EglTestContext& eglTestCtx, const string& name, const string& desc);
1424	void			init						(void);
1425	void			addClearActions				(void);
1426private:
1427	LabeledActions	m_clearActions;
1428};
1429
1430MultiContextRenderTests::MultiContextRenderTests (EglTestContext& eglTestCtx, const string& name, const string& desc)
1431	: RenderTests	(eglTestCtx, name, desc)
1432{
1433}
1434
1435void MultiContextRenderTests::addClearActions (void)
1436{
1437	m_clearActions.add("renderbuffer_clear_color",		MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearColor(tcu::Vec4(0.8f, 0.2f, 0.9f, 1.0f))));
1438	m_clearActions.add("renderbuffer_clear_depth",		MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearDepth(0.75f)));
1439	m_clearActions.add("renderbuffer_clear_stencil",	MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearStencil(97)));
1440}
1441
1442void MultiContextRenderTests::init (void)
1443{
1444	addCreateTexture2DActions("texture_");
1445	addCreateTextureCubemapActions("_rgba8", GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1446	addCreateTextureCubemapActions("_rgb8", GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);
1447	addCreateRenderbufferActions();
1448	addCreateAndroidNativeActions();
1449	addRenderActions();
1450	addClearActions();
1451
1452	for (int createNdx = 0; createNdx < m_createActions.size(); createNdx++)
1453	for (int renderNdx = 0; renderNdx < m_renderActions.size(); renderNdx++)
1454	for (int clearNdx = 0; clearNdx < m_clearActions.size(); clearNdx++)
1455	{
1456		const LabeledAction&	createAction	= m_createActions[createNdx];
1457		const LabeledAction&	renderAction	= m_renderActions[renderNdx];
1458		const LabeledAction&	clearAction		= m_clearActions[clearNdx];
1459		TestSpec				spec;
1460
1461		if (!isCompatibleCreateAndRenderActions(*createAction.action, *renderAction.action))
1462			continue;
1463		if (!isCompatibleCreateAndModifyActions(*createAction.action, *clearAction.action))
1464			continue;
1465
1466		spec.name = std::string("gles2_") + createAction.label + "_" + renderAction.label;
1467		spec.desc = spec.name;
1468
1469		spec.contexts.push_back(TestSpec::API_GLES2);
1470		spec.contexts.push_back(TestSpec::API_GLES2);
1471
1472		spec.operations.push_back(TestSpec::Operation(0, *createAction.action));
1473		spec.operations.push_back(TestSpec::Operation(0, *renderAction.action));
1474		spec.operations.push_back(TestSpec::Operation(0, *clearAction.action));
1475		spec.operations.push_back(TestSpec::Operation(1, *createAction.action));
1476		spec.operations.push_back(TestSpec::Operation(0, *renderAction.action));
1477		spec.operations.push_back(TestSpec::Operation(1, *renderAction.action));
1478
1479		addChild(new ImageFormatCase(m_eglTestCtx, spec));
1480	}
1481}
1482
1483TestCaseGroup* createMultiContextRenderTests (EglTestContext& eglTestCtx, const string& name, const string& desc)
1484{
1485	return new MultiContextRenderTests(eglTestCtx, name, desc);
1486}
1487
1488class ModifyTests : public ImageTests
1489{
1490public:
1491								ModifyTests		(EglTestContext& eglTestCtx, const string& name, const string& desc)
1492									: ImageTests(eglTestCtx, name, desc) {}
1493
1494	void						init			(void);
1495
1496protected:
1497	void						addModifyActions(void);
1498
1499	LabeledActions				m_modifyActions;
1500	GLES2ImageApi::RenderTryAll	m_renderAction;
1501};
1502
1503void ModifyTests::addModifyActions (void)
1504{
1505	m_modifyActions.add("tex_subimage_rgb8",			MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGB,	GL_UNSIGNED_BYTE)));
1506	m_modifyActions.add("tex_subimage_rgb565",			MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGB, 	GL_UNSIGNED_SHORT_5_6_5)));
1507	m_modifyActions.add("tex_subimage_rgba8",			MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGBA,	GL_UNSIGNED_BYTE)));
1508	m_modifyActions.add("tex_subimage_rgb5_a1",			MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGBA,	GL_UNSIGNED_SHORT_5_5_5_1)));
1509	m_modifyActions.add("tex_subimage_rgba4",			MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGBA,	GL_UNSIGNED_SHORT_4_4_4_4)));
1510
1511	m_modifyActions.add("renderbuffer_clear_color",		MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearColor(tcu::Vec4(0.3f, 0.5f, 0.3f, 1.0f))));
1512	m_modifyActions.add("renderbuffer_clear_depth",		MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearDepth(0.7f)));
1513	m_modifyActions.add("renderbuffer_clear_stencil",	MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearStencil(78)));
1514}
1515
1516void ModifyTests::init (void)
1517{
1518	addCreateTexture2DActions("tex_");
1519	addCreateRenderbufferActions();
1520	addCreateAndroidNativeActions();
1521	addModifyActions();
1522
1523	for (int createNdx = 0; createNdx < m_createActions.size(); createNdx++)
1524	{
1525		LabeledAction& createAction = m_createActions[createNdx];
1526
1527		for (int modifyNdx = 0; modifyNdx < m_modifyActions.size(); modifyNdx++)
1528		{
1529			LabeledAction& modifyAction = m_modifyActions[modifyNdx];
1530
1531			if (!isCompatibleCreateAndModifyActions(*createAction.action, *modifyAction.action))
1532				continue;
1533
1534			TestSpec spec;
1535			spec.name = createAction.label + "_" + modifyAction.label;
1536			spec.desc = "gles2_tex_sub_image";
1537
1538			spec.contexts.push_back(TestSpec::API_GLES2);
1539
1540			spec.operations.push_back(TestSpec::Operation(0, *createAction.action));
1541			spec.operations.push_back(TestSpec::Operation(0, m_renderAction));
1542			spec.operations.push_back(TestSpec::Operation(0, *modifyAction.action));
1543			spec.operations.push_back(TestSpec::Operation(0, m_renderAction));
1544
1545			addChild(new ImageFormatCase(m_eglTestCtx, spec));
1546		}
1547	}
1548}
1549
1550TestCaseGroup* createModifyTests (EglTestContext& eglTestCtx, const string& name, const string& desc)
1551{
1552	return new ModifyTests(eglTestCtx, name, desc);
1553}
1554
1555} // Image
1556} // egl
1557} // deqp
1558