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 Common utilities for EGL images.
22 *//*--------------------------------------------------------------------*/
23
24
25#include "teglImageUtil.hpp"
26
27#include "tcuTexture.hpp"
28#include "tcuTextureUtil.hpp"
29
30#include "egluGLUtil.hpp"
31#include "egluNativeWindow.hpp"
32#include "egluNativePixmap.hpp"
33
34#include "eglwLibrary.hpp"
35#include "eglwEnums.hpp"
36
37#include "glwEnums.hpp"
38
39#include "gluObjectWrapper.hpp"
40#include "gluTextureUtil.hpp"
41
42namespace deqp
43{
44namespace egl
45{
46namespace Image
47{
48
49using std::string;
50using std::vector;
51
52using de::UniquePtr;
53using de::MovePtr;
54
55using tcu::TextureFormat;
56using tcu::Texture2D;
57using tcu::Vec4;
58
59using glu::Framebuffer;
60using glu::Texture;
61
62using eglu::AttribMap;
63using eglu::UniqueSurface;
64using eglu::NativeDisplay;
65using eglu::NativeWindow;
66using eglu::NativePixmap;
67using eglu::NativeDisplayFactory;
68using eglu::NativeWindowFactory;
69using eglu::NativePixmapFactory;
70using eglu::WindowParams;
71
72using namespace glw;
73using namespace eglw;
74
75enum {
76	IMAGE_WIDTH		= 64,
77	IMAGE_HEIGHT	= 64,
78};
79
80
81template <typename T>
82struct NativeSurface : public ManagedSurface
83{
84public:
85	explicit		NativeSurface	(MovePtr<UniqueSurface>	surface,
86									 MovePtr<T>				native)
87						: ManagedSurface	(surface)
88						, m_native			(native) {}
89
90private:
91	UniquePtr<T>	m_native;
92};
93
94typedef NativeSurface<NativeWindow> NativeWindowSurface;
95typedef NativeSurface<NativePixmap> NativePixmapSurface;
96
97MovePtr<ManagedSurface> createSurface (EglTestContext& eglTestCtx, EGLDisplay dpy, EGLConfig config, int width, int height)
98{
99	const Library&				egl				= eglTestCtx.getLibrary();
100	EGLint						surfaceTypeBits	= eglu::getConfigAttribInt(egl, dpy, config, EGL_SURFACE_TYPE);
101	const NativeDisplayFactory&	displayFactory	= eglTestCtx.getNativeDisplayFactory();
102	NativeDisplay&				nativeDisplay	= eglTestCtx.getNativeDisplay();
103
104	if (surfaceTypeBits & EGL_PBUFFER_BIT)
105	{
106		static const EGLint attribs[]	= { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE };
107		const EGLSurface	surface		= egl.createPbufferSurface(dpy, config, attribs);
108
109		EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()");
110
111		return de::newMovePtr<ManagedSurface>(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)));
112	}
113	else if (surfaceTypeBits & EGL_WINDOW_BIT)
114	{
115		const NativeWindowFactory&	windowFactory	= selectNativeWindowFactory(displayFactory, eglTestCtx.getTestContext().getCommandLine());
116
117		MovePtr<NativeWindow>		window	(windowFactory.createWindow(&nativeDisplay, dpy, config, DE_NULL, WindowParams(width, height, WindowParams::VISIBILITY_DONT_CARE)));
118		const EGLSurface			surface	= eglu::createWindowSurface(nativeDisplay, *window, dpy, config, DE_NULL);
119
120		return MovePtr<ManagedSurface>(new NativeWindowSurface(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)), window));
121	}
122	else if (surfaceTypeBits & EGL_PIXMAP_BIT)
123	{
124		const NativePixmapFactory&	pixmapFactory	= selectNativePixmapFactory(displayFactory, eglTestCtx.getTestContext().getCommandLine());
125
126		MovePtr<NativePixmap>	pixmap	(pixmapFactory.createPixmap(&nativeDisplay, dpy, config, DE_NULL, width, height));
127		const EGLSurface		surface	= eglu::createPixmapSurface(eglTestCtx.getNativeDisplay(), *pixmap, dpy, config, DE_NULL);
128
129		return MovePtr<ManagedSurface>(new NativePixmapSurface(MovePtr<UniqueSurface>(new UniqueSurface(egl, dpy, surface)), pixmap));
130	}
131	else
132		TCU_FAIL("No valid surface types supported in config");
133}
134
135class GLClientBuffer : public ClientBuffer
136{
137	EGLClientBuffer	get		(void) const { return reinterpret_cast<EGLClientBuffer>(static_cast<deUintptr>(getName())); }
138
139protected:
140	virtual GLuint	getName	(void) const = 0;
141};
142
143class TextureClientBuffer : public GLClientBuffer
144{
145public:
146						TextureClientBuffer	(const glw::Functions& gl) : m_texture (gl) {}
147	GLuint				getName				(void) const { return *m_texture; }
148
149private:
150	glu::Texture		m_texture;
151};
152
153class GLImageSource : public ImageSource
154{
155public:
156	EGLImageKHR			createImage			(const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const;
157
158protected:
159	virtual AttribMap	getCreateAttribs	(void) const = 0;
160	virtual EGLenum		getSource			(void) const = 0;
161};
162
163EGLImageKHR GLImageSource::createImage (const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const
164{
165	AttribMap				attribMap	= getCreateAttribs();
166
167	attribMap[EGL_IMAGE_PRESERVED_KHR] = EGL_TRUE;
168
169	{
170		const vector<EGLint>	attribs	= eglu::attribMapToList(attribMap);
171		const EGLImageKHR		image	= egl.createImageKHR(dpy, ctx, getSource(),
172															 clientBuffer, &attribs.front());
173		EGLU_CHECK_MSG(egl, "eglCreateImageKHR()");
174		return image;
175	}
176}
177
178class TextureImageSource : public GLImageSource
179{
180public:
181							TextureImageSource	(GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0) : m_internalFormat(internalFormat), m_format(format), m_type(type), m_useTexLevel0(useTexLevel0) {}
182	MovePtr<ClientBuffer>	createBuffer		(const glw::Functions& gl, Texture2D* reference) const;
183	GLenum					getEffectiveFormat	(void) const;
184	GLenum					getInternalFormat	(void) const { return m_internalFormat; }
185
186protected:
187	AttribMap				getCreateAttribs	(void) const;
188	virtual void			initTexture			(const glw::Functions& gl) const = 0;
189	virtual GLenum			getGLTarget			(void) const = 0;
190
191	const GLenum			m_internalFormat;
192	const GLenum			m_format;
193	const GLenum			m_type;
194	const bool				m_useTexLevel0;
195};
196
197bool isSizedFormat (GLenum format)
198{
199	try
200	{
201		glu::mapGLInternalFormat(format);
202		return true;
203	}
204	catch (const tcu::InternalError&)
205	{
206		return false;
207	}
208}
209
210GLenum getEffectiveFormat (GLenum format, GLenum type)
211{
212	return glu::getInternalFormat(glu::mapGLTransferFormat(format, type));
213}
214
215GLenum TextureImageSource::getEffectiveFormat (void) const
216{
217	if (isSizedFormat(m_internalFormat))
218		return m_internalFormat;
219	else
220		return deqp::egl::Image::getEffectiveFormat(m_format, m_type);
221}
222
223AttribMap TextureImageSource::getCreateAttribs (void) const
224{
225	AttribMap ret;
226
227	ret[EGL_GL_TEXTURE_LEVEL_KHR] = 0;
228
229	return ret;
230}
231
232MovePtr<ClientBuffer> TextureImageSource::createBuffer (const glw::Functions& gl, Texture2D* ref) const
233{
234	MovePtr<TextureClientBuffer>	clientBuffer	(new TextureClientBuffer(gl));
235	const GLuint					texture			= clientBuffer->getName();
236	const GLenum					target			= getGLTarget();
237
238	GLU_CHECK_GLW_CALL(gl, bindTexture(target, texture));
239	initTexture(gl);
240
241	if (!m_useTexLevel0)
242	{
243		// Set minification filter to linear. This makes the texture complete.
244		GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
245	}
246
247	if (ref != DE_NULL)
248	{
249		GLenum		imgTarget	= eglu::getImageGLTarget(getSource());
250
251		*ref = Texture2D(glu::mapGLTransferFormat(m_format, m_type), IMAGE_WIDTH, IMAGE_HEIGHT);
252		ref->allocLevel(0);
253		tcu::fillWithComponentGradients(ref->getLevel(0),
254										tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
255										tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
256
257		GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
258		GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
259		GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
260		GLU_CHECK_GLW_CALL(gl, texParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
261
262		GLU_CHECK_GLW_CALL(gl, texImage2D(imgTarget, 0, m_internalFormat, IMAGE_WIDTH, IMAGE_HEIGHT,
263										  0, m_format, m_type, ref->getLevel(0).getDataPtr()));
264	}
265	GLU_CHECK_GLW_CALL(gl, bindTexture(target, 0));
266	return MovePtr<ClientBuffer>(clientBuffer);
267}
268
269class Texture2DImageSource : public TextureImageSource
270{
271public:
272					Texture2DImageSource	(GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0) : TextureImageSource(internalFormat, format, type, useTexLevel0) {}
273	EGLenum			getSource				(void) const { return EGL_GL_TEXTURE_2D_KHR; }
274	string			getRequiredExtension	(void) const { return "EGL_KHR_gl_texture_2D_image"; }
275	GLenum			getGLTarget				(void) const { return GL_TEXTURE_2D; }
276
277protected:
278	void			initTexture				(const glw::Functions& gl) const;
279};
280
281void Texture2DImageSource::initTexture (const glw::Functions& gl) const
282{
283	// Specify mipmap level 0
284	GLU_CHECK_CALL_ERROR(gl.texImage2D(GL_TEXTURE_2D, 0, m_internalFormat, IMAGE_WIDTH, IMAGE_HEIGHT, 0, m_format, m_type, DE_NULL),
285						 gl.getError());
286}
287
288class TextureCubeMapImageSource : public TextureImageSource
289{
290public:
291					TextureCubeMapImageSource	(EGLenum source, GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0) : TextureImageSource(internalFormat, format, type, useTexLevel0), m_source(source) {}
292	EGLenum			getSource					(void) const { return m_source; }
293	string			getRequiredExtension		(void) const { return "EGL_KHR_gl_texture_cubemap_image"; }
294	GLenum			getGLTarget					(void) const { return GL_TEXTURE_CUBE_MAP; }
295
296protected:
297	void			initTexture					(const glw::Functions& gl) const;
298
299	EGLenum			m_source;
300};
301
302void TextureCubeMapImageSource::initTexture (const glw::Functions& gl) const
303{
304	// Specify mipmap level 0 for all faces
305	static const GLenum faces[] =
306	{
307		GL_TEXTURE_CUBE_MAP_POSITIVE_X,
308		GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
309		GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
310		GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
311		GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
312		GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
313	};
314
315	for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); faceNdx++)
316		GLU_CHECK_GLW_CALL(gl, texImage2D(faces[faceNdx], 0, m_internalFormat, IMAGE_WIDTH, IMAGE_HEIGHT, 0, m_format, m_type, DE_NULL));
317}
318
319class RenderbufferClientBuffer : public GLClientBuffer
320{
321public:
322						RenderbufferClientBuffer	(const glw::Functions& gl) : m_rbo (gl) {}
323	GLuint				getName						(void) const { return *m_rbo; }
324
325private:
326	glu::Renderbuffer	m_rbo;
327};
328
329class RenderbufferImageSource : public GLImageSource
330{
331public:
332							RenderbufferImageSource	(GLenum format) : m_format(format) {}
333
334	string					getRequiredExtension	(void) const	{ return "EGL_KHR_gl_renderbuffer_image"; }
335	MovePtr<ClientBuffer>	createBuffer			(const glw::Functions& gl, Texture2D* reference) const;
336	GLenum					getEffectiveFormat		(void) const { return m_format; }
337
338protected:
339	EGLenum					getSource				(void) const	{ return EGL_GL_RENDERBUFFER_KHR; }
340	AttribMap				getCreateAttribs		(void) const	{ return AttribMap(); }
341
342	GLenum					m_format;
343};
344
345void initializeStencilRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref)
346{
347	static const deUint32 stencilValues[] =
348	{
349		0xBF688C11u,
350		0xB43D2922u,
351		0x055D5FFBu,
352		0x9300655Eu,
353		0x63BE0DF2u,
354		0x0345C13Bu,
355		0x1C184832u,
356		0xD107040Fu,
357		0x9B91569Fu,
358		0x0F0CFDC7u,
359	};
360
361	const deUint32 numStencilBits	= tcu::getTextureFormatBitDepth(tcu::getEffectiveDepthStencilTextureFormat(ref.getLevel(0).getFormat(), tcu::Sampler::MODE_STENCIL)).x();
362	const deUint32 stencilMask		= deBitMask32(0, numStencilBits);
363
364	GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
365												   GL_RENDERBUFFER, rbo));
366	GLU_CHECK_GLW_CALL(gl, clearStencil(0));
367	GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT));
368	tcu::clearStencil(ref.getLevel(0), 0);
369
370	// create a pattern
371	GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST));
372	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stencilValues); ++ndx)
373	{
374		const deUint32		stencil	= stencilValues[ndx] & stencilMask;
375		const tcu::IVec2	size	= tcu::IVec2((int)((float)(DE_LENGTH_OF_ARRAY(stencilValues) - ndx) * ((float)ref.getWidth() / float(DE_LENGTH_OF_ARRAY(stencilValues)))),
376												 (int)((float)(DE_LENGTH_OF_ARRAY(stencilValues) - ndx) * ((float)ref.getHeight() / float(DE_LENGTH_OF_ARRAY(stencilValues) + 4)))); // not symmetric
377
378		if (size.x() == 0 || size.y() == 0)
379			break;
380
381		GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y()));
382		GLU_CHECK_GLW_CALL(gl, clearStencil(stencil));
383		GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT));
384
385		tcu::clearStencil(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), stencil);
386	}
387
388	GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST));
389	GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
390												   GL_RENDERBUFFER, 0));
391}
392
393void initializeDepthRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref)
394{
395	const int NUM_STEPS = 13;
396
397	GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
398												   GL_RENDERBUFFER, rbo));
399
400	GLU_CHECK_GLW_CALL(gl, clearDepthf(0.0f));
401	GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT));
402	tcu::clearDepth(ref.getLevel(0), 0.0f);
403
404	// create a pattern
405	GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST));
406	for (int ndx = 0; ndx < NUM_STEPS; ++ndx)
407	{
408		const float			depth	= (float)ndx / float(NUM_STEPS);
409		const tcu::IVec2	size	= tcu::IVec2((int)((float)(NUM_STEPS - ndx) * ((float)ref.getWidth() / float(NUM_STEPS))),
410												 (int)((float)(NUM_STEPS - ndx) * ((float)ref.getHeight() / float(NUM_STEPS + 4)))); // not symmetric
411
412		if (size.x() == 0 || size.y() == 0)
413			break;
414
415		GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y()));
416		GLU_CHECK_GLW_CALL(gl, clearDepthf(depth));
417		GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT));
418
419		tcu::clearDepth(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), depth);
420	}
421
422	GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST));
423	GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
424												   GL_RENDERBUFFER, 0));
425
426}
427
428void initializeColorRbo(const glw::Functions& gl, GLuint rbo, Texture2D& ref)
429{
430	static const tcu::Vec4 colorValues[] =
431	{
432		tcu::Vec4(0.9f, 0.5f, 0.65f, 1.0f),
433		tcu::Vec4(0.5f, 0.7f, 0.65f, 1.0f),
434		tcu::Vec4(0.2f, 0.5f, 0.65f, 1.0f),
435		tcu::Vec4(0.3f, 0.1f, 0.5f, 1.0f),
436		tcu::Vec4(0.8f, 0.2f, 0.3f, 1.0f),
437		tcu::Vec4(0.9f, 0.4f, 0.8f, 1.0f),
438	};
439
440	GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
441												   GL_RENDERBUFFER, rbo));
442	GLU_CHECK_GLW_CALL(gl, clearColor(1.0f, 1.0f, 0.0f, 1.0f));
443	GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT));
444	tcu::clear(ref.getLevel(0), Vec4(1.0f, 1.0f, 0.0f, 1.0f));
445
446	// create a pattern
447	GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST));
448	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorValues); ++ndx)
449	{
450		const tcu::IVec2	size	= tcu::IVec2((int)((float)(DE_LENGTH_OF_ARRAY(colorValues) - ndx) * ((float)ref.getWidth() / float(DE_LENGTH_OF_ARRAY(colorValues)))),
451												 (int)((float)(DE_LENGTH_OF_ARRAY(colorValues) - ndx) * ((float)ref.getHeight() / float(DE_LENGTH_OF_ARRAY(colorValues) + 4)))); // not symmetric
452
453		if (size.x() == 0 || size.y() == 0)
454			break;
455
456		GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y()));
457		GLU_CHECK_GLW_CALL(gl, clearColor(colorValues[ndx].x(), colorValues[ndx].y(), colorValues[ndx].z(), colorValues[ndx].w()));
458		GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT));
459
460		tcu::clear(tcu::getSubregion(ref.getLevel(0), 0, 0, size.x(), size.y()), colorValues[ndx]);
461	}
462
463	GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST));
464	GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
465												   GL_RENDERBUFFER, 0));
466}
467
468MovePtr<ClientBuffer> RenderbufferImageSource::createBuffer (const glw::Functions& gl, Texture2D* ref) const
469{
470	MovePtr<RenderbufferClientBuffer>	buffer	(new RenderbufferClientBuffer(gl));
471	const GLuint						rbo		= buffer->getName();
472
473	GLU_CHECK_CALL_ERROR(gl.bindRenderbuffer(GL_RENDERBUFFER, rbo), gl.getError());
474
475	// Specify storage.
476	GLU_CHECK_CALL_ERROR(gl.renderbufferStorage(GL_RENDERBUFFER, m_format, 64, 64), gl.getError());
477
478	if (ref != DE_NULL)
479	{
480		Framebuffer			fbo			(gl);
481		const TextureFormat	texFormat	= glu::mapGLInternalFormat(m_format);
482
483		*ref = tcu::Texture2D(texFormat, 64, 64);
484		ref->allocLevel(0);
485
486		gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
487		switch (m_format)
488		{
489			case GL_STENCIL_INDEX8:
490				initializeStencilRbo(gl, rbo, *ref);
491				break;
492			case GL_DEPTH_COMPONENT16:
493				initializeDepthRbo(gl, rbo, *ref);
494				break;
495			case GL_RGBA4:
496				initializeColorRbo(gl, rbo, *ref);
497				break;
498			case GL_RGB5_A1:
499				initializeColorRbo(gl, rbo, *ref);
500				break;
501			case GL_RGB565:
502				initializeColorRbo(gl, rbo, *ref);
503				break;
504			default:
505				DE_FATAL("Impossible");
506		}
507
508		gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
509	}
510
511	return MovePtr<ClientBuffer>(buffer);
512}
513
514class UnsupportedImageSource : public ImageSource
515{
516public:
517							UnsupportedImageSource	(const string& message, GLenum format) : m_message(message), m_format(format) {}
518	string					getRequiredExtension	(void) const { fail(); return ""; }
519	MovePtr<ClientBuffer>	createBuffer			(const glw::Functions&, tcu::Texture2D*) const { fail(); return de::MovePtr<ClientBuffer>(); }
520	EGLImageKHR				createImage				(const Library& egl, EGLDisplay dpy, EGLContext ctx, EGLClientBuffer clientBuffer) const;
521	GLenum					getEffectiveFormat		(void) const { return m_format; }
522
523private:
524	const string			m_message;
525	GLenum					m_format;
526
527	void					fail					(void) const { TCU_THROW(NotSupportedError, m_message.c_str()); }
528};
529
530EGLImageKHR	UnsupportedImageSource::createImage (const Library&, EGLDisplay, EGLContext, EGLClientBuffer) const
531{
532	fail();
533	return EGL_NO_IMAGE_KHR;
534}
535
536MovePtr<ImageSource> createTextureImageSource (EGLenum source, GLenum internalFormat, GLenum format, GLenum type, bool useTexLevel0)
537{
538	if (source == EGL_GL_TEXTURE_2D_KHR)
539		return MovePtr<ImageSource>(new Texture2DImageSource(internalFormat, format, type, useTexLevel0));
540	else
541		return MovePtr<ImageSource>(new TextureCubeMapImageSource(source, internalFormat, format, type, useTexLevel0));
542}
543
544MovePtr<ImageSource> createRenderbufferImageSource (GLenum format)
545{
546	return MovePtr<ImageSource>(new RenderbufferImageSource(format));
547}
548
549MovePtr<ImageSource> createUnsupportedImageSource (const string& message, GLenum format)
550{
551	return MovePtr<ImageSource>(new UnsupportedImageSource(message, format));
552}
553
554} // Image
555} // egl
556} // deqp
557