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