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 "teglImageTests.hpp"
25
26#include "teglImageFormatTests.hpp"
27
28#include "egluNativeDisplay.hpp"
29#include "egluNativeWindow.hpp"
30#include "egluNativePixmap.hpp"
31#include "egluStrUtil.hpp"
32#include "egluUtil.hpp"
33
34#include "gluDefs.hpp"
35#include "gluStrUtil.hpp"
36
37#include "tcuTestLog.hpp"
38#include "tcuCommandLine.hpp"
39
40
41#include <algorithm>
42#include <sstream>
43#include <string>
44#include <vector>
45#include <set>
46
47#include <EGL/eglext.h>
48
49#include <GLES2/gl2.h>
50#include <GLES2/gl2ext.h>
51
52using tcu::TestLog;
53
54using std::string;
55using std::vector;
56using std::set;
57
58namespace deqp
59{
60namespace egl
61{
62
63namespace Image
64{
65
66bool checkExtensions (const tcu::egl::Display& dpy, const char** first, const char** last, vector<const char*>& unsupported)
67{
68	vector<string> extensions;
69	dpy.getExtensions(extensions);
70
71	set<string> extSet(extensions.begin(), extensions.end());
72
73	unsupported.clear();
74
75	for (const char** extIter = first; extIter != last; extIter++)
76	{
77		const char* ext = *extIter;
78
79		if (extSet.find(ext) == extSet.end())
80			unsupported.push_back(ext);
81	}
82
83	return unsupported.size() == 0;
84}
85
86string join (const vector<const char*>& parts, const char* separator)
87{
88	std::ostringstream str;
89	for (std::vector<const char*>::const_iterator i = parts.begin(); i != parts.end(); i++)
90	{
91		if (i != parts.begin())
92			str << separator;
93		str << *i;
94	}
95	return str.str();
96}
97
98void checkExtensions (const tcu::egl::Display& dpy, const char** first, const char** last)
99{
100	vector<const char*> unsupported;
101	if (!checkExtensions(dpy, first, last, unsupported))
102		throw tcu::NotSupportedError("Extension not supported", join(unsupported, " ").c_str(), __FILE__, __LINE__);
103}
104
105template <size_t N>
106void checkExtensions (const tcu::egl::Display& dpy, const char* (&extensions)[N])
107{
108	checkExtensions(dpy, &extensions[0], &extensions[N]);
109}
110
111#define CHECK_EXTENSIONS(EXTENSIONS) do { static const char* ext[] = EXTENSIONS; checkExtensions(m_eglTestCtx.getDisplay(), ext); } while (deGetFalse())
112
113template <typename RetVal>
114RetVal checkCallError (tcu::TestContext& testCtx, const char* call, RetVal returnValue, EGLint expectError)
115{
116	TestLog& log = testCtx.getLog();
117	log << TestLog::Message << call << TestLog::EndMessage;
118
119	EGLint error = eglGetError();
120
121	if (error != expectError)
122	{
123		log << TestLog::Message << "  Fail: Error code mismatch! Expected " << eglu::getErrorStr(expectError) << ", got " << eglu::getErrorStr(error) << TestLog::EndMessage;
124		log << TestLog::Message << "  " << returnValue << " was returned" << TestLog::EndMessage;
125
126		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
127			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error code");
128	}
129
130	return returnValue;
131}
132
133template <typename RetVal>
134void checkCallReturn (tcu::TestContext& testCtx, const char* call, RetVal returnValue, RetVal expectReturnValue, EGLint expectError)
135{
136	TestLog& log = testCtx.getLog();
137	log << TestLog::Message << call << TestLog::EndMessage;
138
139	EGLint error = eglGetError();
140
141	if (returnValue != expectReturnValue)
142	{
143		log << TestLog::Message << "  Fail: Return value mismatch! Expected " << expectReturnValue << ", got " << returnValue << TestLog::EndMessage;
144
145		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
146			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid return value");
147	}
148
149	if (error != expectError)
150	{
151		log << TestLog::Message << "  Fail: Error code mismatch! Expected " << eglu::getErrorStr(expectError) << ", got " << eglu::getErrorStr(error) << TestLog::EndMessage;
152
153		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
154			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error code");
155	}
156}
157
158void checkGLCall (tcu::TestContext& testCtx, const char* call, GLenum expectError)
159{
160	TestLog& log = testCtx.getLog();
161	log << TestLog::Message << call << TestLog::EndMessage;
162
163	GLenum error = glGetError();
164
165	if (error != expectError)
166	{
167		log << TestLog::Message << "  Fail: Error code mismatch! Expected " << glu::getErrorStr(expectError) << ", got " << glu::getErrorStr(error) << TestLog::EndMessage;
168
169		if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
170			testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error code");
171	}
172}
173
174// \note These macros expect "TestContext m_testCtx" and "ExtFuncTable efTable" variables to be defined.
175#define CHECK_EXT_CALL_RET(CALL, EXPECT_RETURN_VALUE, EXPECT_ERROR)	checkCallReturn(m_testCtx, #CALL, efTable.CALL, (EXPECT_RETURN_VALUE), (EXPECT_ERROR))
176#define CHECK_EXT_CALL_ERR(CALL, EXPECT_ERROR)						checkCallError(m_testCtx, #CALL, efTable.CALL, (EXPECT_ERROR))
177#define CHECK_GL_EXT_CALL(CALL, EXPECT_ERROR)						do { efTable.CALL; checkGLCall(m_testCtx, #CALL, (EXPECT_ERROR)); } while (deGetFalse())
178
179class ExtFuncTable
180{
181public:
182	PFNEGLCREATEIMAGEKHRPROC						eglCreateImageKHR;
183	PFNEGLDESTROYIMAGEKHRPROC						eglDestroyImageKHR;
184
185	PFNGLEGLIMAGETARGETTEXTURE2DOESPROC				glEGLImageTargetTexture2DOES;
186	PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC	glEGLImageTargetRenderbufferStorageOES;
187
188	ExtFuncTable (void)
189	{
190		// EGL_KHR_image_base
191		eglCreateImageKHR						= (PFNEGLCREATEIMAGEKHRPROC)						eglGetProcAddress("eglCreateImageKHR");
192		eglDestroyImageKHR						= (PFNEGLDESTROYIMAGEKHRPROC)						eglGetProcAddress("eglDestroyImageKHR");
193
194		// OES_EGL_image
195		glEGLImageTargetTexture2DOES			= (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)				eglGetProcAddress("glEGLImageTargetTexture2DOES");
196		glEGLImageTargetRenderbufferStorageOES	= (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)	eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES");
197	}
198};
199
200class InvalidCreateImage : public TestCase
201{
202public:
203	InvalidCreateImage (EglTestContext& eglTestCtx)
204		: TestCase(eglTestCtx, "invalid_create_image", "eglCreateImageKHR() with invalid arguments")
205	{
206	}
207
208	IterateResult iterate (void)
209	{
210		EGLDisplay		dpy = m_eglTestCtx.getDisplay().getEGLDisplay();
211		TestLog&		log	= m_testCtx.getLog();
212		ExtFuncTable	efTable;
213
214		CHECK_EXTENSIONS({ "EGL_KHR_image_base" });
215
216		// Initialize result to pass.
217		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
218
219		log << TestLog::Message << "Testing bad display (-1)..." << TestLog::EndMessage;
220		CHECK_EXT_CALL_RET(eglCreateImageKHR((EGLDisplay)-1, EGL_NO_CONTEXT, EGL_NONE, 0, DE_NULL),
221						   EGL_NO_IMAGE_KHR, EGL_BAD_DISPLAY);
222
223		log << TestLog::Message << "Testing bad context (-1)..." << TestLog::EndMessage;
224		CHECK_EXT_CALL_RET(eglCreateImageKHR(dpy, (EGLContext)-1, EGL_NONE, 0, DE_NULL),
225						   EGL_NO_IMAGE_KHR, EGL_BAD_CONTEXT);
226
227		log << TestLog::Message << "Testing bad parameter (-1).." << TestLog::EndMessage;
228		CHECK_EXT_CALL_RET(eglCreateImageKHR(dpy, EGL_NO_CONTEXT, (EGLenum)-1, 0, DE_NULL),
229						   EGL_NO_IMAGE_KHR, EGL_BAD_PARAMETER);
230
231		return STOP;
232	}
233};
234
235class GLES2Context
236{
237public:
238	GLES2Context (EglTestContext& eglTestCtx, EGLint configId, int width, int height)
239		: m_eglTestCtx	(eglTestCtx)
240		, m_config		(getConfigById(eglTestCtx.getDisplay(), configId))
241		, m_context		(eglTestCtx.getDisplay(), m_config, m_ctxAttrs, EGL_OPENGL_ES_API)
242		, m_window		(DE_NULL)
243		, m_pixmap		(DE_NULL)
244		, m_surface		(DE_NULL)
245	{
246		tcu::egl::Display&	dpy				= eglTestCtx.getDisplay();
247		EGLint				surfaceTypeBits	= dpy.getConfigAttrib(m_config, EGL_SURFACE_TYPE);
248
249		if (surfaceTypeBits & EGL_PBUFFER_BIT)
250		{
251			EGLint pbufferAttrs[] =
252			{
253				EGL_WIDTH,		width,
254				EGL_HEIGHT,		height,
255				EGL_NONE
256			};
257
258			m_surface = new tcu::egl::PbufferSurface(dpy, m_config, pbufferAttrs);
259		}
260		else if (surfaceTypeBits & EGL_WINDOW_BIT)
261		{
262			m_window	= eglTestCtx.createNativeWindow(dpy.getEGLDisplay(), m_config, DE_NULL, width, height, eglu::parseWindowVisibility(eglTestCtx.getTestContext().getCommandLine()));
263			m_surface	= new tcu::egl::WindowSurface(dpy, eglu::createWindowSurface(eglTestCtx.getNativeDisplay(), *m_window, dpy.getEGLDisplay(), m_config, DE_NULL));
264		}
265		else if (surfaceTypeBits & EGL_PIXMAP_BIT)
266		{
267			m_pixmap	= eglTestCtx.createNativePixmap(dpy.getEGLDisplay(), m_config, DE_NULL, width, height);
268			m_surface	= new tcu::egl::PixmapSurface(dpy, eglu::createPixmapSurface(eglTestCtx.getNativeDisplay(), *m_pixmap, dpy.getEGLDisplay(), m_config, DE_NULL));
269		}
270		else
271			TCU_FAIL("No valid surface types supported in config");
272
273		m_context.makeCurrent(*m_surface, *m_surface);
274	}
275
276	~GLES2Context (void)
277	{
278		eglMakeCurrent(m_eglTestCtx.getDisplay().getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
279
280		delete m_window;
281		delete m_pixmap;
282		delete m_surface;
283	}
284
285	EGLDisplay getEglDisplay (void)
286	{
287		return m_eglTestCtx.getDisplay().getEGLDisplay();
288	}
289
290	EGLContext getEglContext (void)
291	{
292		return m_context.getEGLContext();
293	}
294
295	// Helper for selecting config.
296	static EGLint getConfigIdForApi (const vector<eglu::ConfigInfo>& configInfos, EGLint apiBits)
297	{
298		EGLint	windowCfg	= 0;
299		EGLint	pixmapCfg	= 0;
300		EGLint	pbufferCfg	= 0;
301
302		for (vector<eglu::ConfigInfo>::const_iterator cfgIter = configInfos.begin(); cfgIter != configInfos.end(); cfgIter++)
303		{
304			if ((cfgIter->renderableType & apiBits) == 0)
305				continue;
306
307			if (windowCfg == 0 && (cfgIter->surfaceType & EGL_WINDOW_BIT) != 0)
308				windowCfg = cfgIter->configId;
309
310			if (pixmapCfg == 0 && (cfgIter->surfaceType & EGL_PIXMAP_BIT) != 0)
311				pixmapCfg = cfgIter->configId;
312
313			if (pbufferCfg == 0 && (cfgIter->surfaceType & EGL_PBUFFER_BIT) != 0)
314				pbufferCfg = cfgIter->configId;
315
316			if (windowCfg && pixmapCfg && pbufferCfg)
317				break;
318		}
319
320		// Prefer configs in order: pbuffer, window, pixmap
321		if (pbufferCfg)
322			return pbufferCfg;
323		else if (windowCfg)
324			return windowCfg;
325		else if (pixmapCfg)
326			return pixmapCfg;
327		else
328			throw tcu::NotSupportedError("No compatible EGL configs found", "", __FILE__, __LINE__);
329	}
330
331private:
332	static EGLConfig getConfigById (const tcu::egl::Display& dpy, EGLint configId)
333	{
334		EGLint attributes[] = { EGL_CONFIG_ID, configId, EGL_NONE };
335		vector<EGLConfig> configs;
336		dpy.chooseConfig(attributes, configs);
337		TCU_CHECK(configs.size() == 1);
338		return configs[0];
339	}
340
341	static const EGLint			m_ctxAttrs[];
342
343	EglTestContext&				m_eglTestCtx;
344	EGLConfig					m_config;
345	tcu::egl::Context			m_context;
346	eglu::NativeWindow*			m_window;
347	eglu::NativePixmap*			m_pixmap;
348	tcu::egl::Surface*			m_surface;
349
350								GLES2Context	(const GLES2Context&);
351	GLES2Context&				operator=		(const GLES2Context&);
352};
353
354const EGLint GLES2Context::m_ctxAttrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
355
356class CreateImageGLES2 : public TestCase
357{
358public:
359	static const char* getTargetName (EGLint target)
360	{
361		switch (target)
362		{
363			case EGL_GL_TEXTURE_2D_KHR:						return "tex2d";
364			case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:	return "cubemap_pos_x";
365			case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:	return "cubemap_neg_x";
366			case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:	return "cubemap_pos_y";
367			case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:	return "cubemap_neg_y";
368			case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:	return "cubemap_pos_z";
369			case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:	return "cubemap_neg_z";
370			case EGL_GL_RENDERBUFFER_KHR:					return "renderbuffer";
371			default:		DE_ASSERT(DE_FALSE);			return "";
372		}
373	}
374
375	static const char* getStorageName (GLenum storage)
376	{
377		switch (storage)
378		{
379			case GL_RGB:				return "rgb";
380			case GL_RGBA:				return "rgba";
381			case GL_DEPTH_COMPONENT16:	return "depth_component_16";
382			case GL_RGBA4:				return "rgba4";
383			case GL_RGB5_A1:			return "rgb5_a1";
384			case GL_RGB565:				return "rgb565";
385			case GL_STENCIL_INDEX8:		return "stencil_index8";
386			default:
387				DE_ASSERT(DE_FALSE);
388				return "";
389		}
390	}
391
392	CreateImageGLES2 (EglTestContext& eglTestCtx, EGLint target, GLenum storage, bool useTexLevel0 = false)
393		: TestCase			(eglTestCtx, (string("create_image_gles2_") + getTargetName(target) + "_" + getStorageName(storage) + (useTexLevel0 ? "_level0_only" : "")).c_str(), "Create EGLImage from GLES2 object")
394		, m_target			(target)
395		, m_storage			(storage)
396		, m_useTexLevel0	(useTexLevel0)
397	{
398	}
399
400	IterateResult iterate (void)
401	{
402		TestLog&		log	= m_testCtx.getLog();
403		ExtFuncTable	efTable;
404
405		if (m_target == EGL_GL_TEXTURE_2D_KHR)
406			CHECK_EXTENSIONS({"EGL_KHR_gl_texture_2D_image"});
407		else if (m_target == EGL_GL_RENDERBUFFER_KHR)
408			CHECK_EXTENSIONS({"EGL_KHR_gl_renderbuffer_image"});
409		else
410			CHECK_EXTENSIONS({"EGL_KHR_gl_texture_cubemap_image"});
411
412		// Initialize result.
413		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
414
415		// Create GLES2 context
416		EGLint configId = GLES2Context::getConfigIdForApi(m_eglTestCtx.getConfigs(), EGL_OPENGL_ES2_BIT);
417		log << TestLog::Message << "Using EGL config " << configId << TestLog::EndMessage;
418
419		GLES2Context context(m_eglTestCtx, configId, 64, 64);
420
421		switch (m_target)
422		{
423			case EGL_GL_TEXTURE_2D_KHR:
424			{
425				deUint32 tex = 1;
426				GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, tex));
427
428				// Specify mipmap level 0
429				GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_2D, 0, m_storage, 64, 64, 0, m_storage, GL_UNSIGNED_BYTE, DE_NULL));
430
431				if (!m_useTexLevel0)
432				{
433					// Set minification filter to linear. This makes the texture complete.
434					GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
435				}
436				// Else spec allows using incomplete texture when miplevel 0 is only used and specified.
437
438				// Create EGL image
439				EGLint		attribs[]	= { EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE };
440				EGLImageKHR	image		= CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(deUintptr)tex, attribs), EGL_SUCCESS);
441				if (image == EGL_NO_IMAGE_KHR)
442				{
443					log << TestLog::Message << "  Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
444
445					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
446						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
447				}
448
449				// Destroy image
450				CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
451
452				// Destroy texture object
453				GLU_CHECK_CALL(glDeleteTextures(1, &tex));
454
455				break;
456			}
457
458			case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
459			case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
460			case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
461			case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
462			case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
463			case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
464			{
465				deUint32 tex = 1;
466				GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, tex));
467
468				// Specify mipmap level 0 for all faces
469				GLenum faces[] =
470				{
471					GL_TEXTURE_CUBE_MAP_POSITIVE_X,
472					GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
473					GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
474					GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
475					GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
476					GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
477				};
478				for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); faceNdx++)
479					GLU_CHECK_CALL(glTexImage2D(faces[faceNdx], 0, m_storage, 64, 64, 0, m_storage, GL_UNSIGNED_BYTE, DE_NULL));
480
481				if (!m_useTexLevel0)
482				{
483					// Set minification filter to linear.
484					GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
485				}
486
487				// Create EGL image
488				EGLint		attribs[]	= { EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE };
489				EGLImageKHR	image		= CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), m_target, (EGLClientBuffer)(deUintptr)tex, attribs), EGL_SUCCESS);
490				if (image == EGL_NO_IMAGE_KHR)
491				{
492					log << TestLog::Message << "  Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
493
494					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
495						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
496				}
497
498				// Destroy image
499				CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
500
501				// Destroy texture object
502				GLU_CHECK_CALL(glDeleteTextures(1, &tex));
503
504				break;
505			}
506
507			case EGL_GL_RENDERBUFFER_KHR:
508			{
509				// Create renderbuffer.
510				deUint32 rbo = 1;
511				GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, rbo));
512
513				// Specify storage.
514				GLU_CHECK_CALL(glRenderbufferStorage(GL_RENDERBUFFER, m_storage, 64, 64));
515
516				// Create EGL image
517				EGLImageKHR image = CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), EGL_GL_RENDERBUFFER_KHR, (EGLClientBuffer)(deUintptr)rbo, DE_NULL), EGL_SUCCESS);
518				if (image == EGL_NO_IMAGE_KHR)
519				{
520					log << TestLog::Message << "  Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
521
522					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
523						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
524				}
525
526				// Destroy image
527				CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
528
529				// Destroy texture object
530				GLU_CHECK_CALL(glDeleteRenderbuffers(1, &rbo));
531
532				break;
533			}
534
535			default:
536				DE_ASSERT(DE_FALSE);
537				break;
538		}
539
540		return STOP;
541	}
542
543private:
544	EGLint	m_target;
545	GLenum	m_storage;
546	bool	m_useTexLevel0;
547};
548
549class ImageTargetGLES2 : public TestCase
550{
551public:
552	static const char* getTargetName (GLenum target)
553	{
554		switch (target)
555		{
556			case GL_TEXTURE_2D:		return "tex2d";
557			case GL_RENDERBUFFER:	return "renderbuffer";
558			default:
559				DE_ASSERT(DE_FALSE);
560				return "";
561		}
562	}
563
564	ImageTargetGLES2 (EglTestContext& eglTestCtx, GLenum target)
565		: TestCase	(eglTestCtx, (string("image_target_gles2_") + getTargetName(target)).c_str(), "Use EGLImage as GLES2 object")
566		, m_target	(target)
567	{
568	}
569
570	IterateResult iterate (void)
571	{
572		TestLog&		log	= m_testCtx.getLog();
573		ExtFuncTable	efTable;
574
575		// \todo [2011-07-21 pyry] Try all possible EGLImage sources
576		CHECK_EXTENSIONS({"EGL_KHR_gl_texture_2D_image"});
577
578		// Initialize result.
579		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
580
581		// Create GLES2 context
582		EGLint configId = GLES2Context::getConfigIdForApi(m_eglTestCtx.getConfigs(), EGL_OPENGL_ES2_BIT);
583		log << TestLog::Message << "Using EGL config " << configId << TestLog::EndMessage;
584
585		GLES2Context context(m_eglTestCtx, configId, 64, 64);
586
587		// Check for OES_EGL_image
588		{
589			const char* glExt = (const char*)glGetString(GL_EXTENSIONS);
590
591			if (string(glExt).find("GL_OES_EGL_image") == string::npos)
592				throw tcu::NotSupportedError("Extension not supported", "GL_OES_EGL_image", __FILE__, __LINE__);
593
594			TCU_CHECK(efTable.glEGLImageTargetTexture2DOES);
595			TCU_CHECK(efTable.glEGLImageTargetRenderbufferStorageOES);
596		}
597
598		// Create GL_TEXTURE_2D and EGLImage from it.
599		log << TestLog::Message << "Creating EGLImage using GL_TEXTURE_2D with GL_RGBA storage" << TestLog::EndMessage;
600
601		deUint32 srcTex = 1;
602		GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, srcTex));
603		GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL));
604		GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
605
606		// Create EGL image
607		EGLint		attribs[]	= { EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE };
608		EGLImageKHR	image		= CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(deUintptr)srcTex, attribs), EGL_SUCCESS);
609		if (image == EGL_NO_IMAGE_KHR)
610		{
611			log << TestLog::Message << "  Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
612
613			if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
614				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
615		}
616
617		// Create texture or renderbuffer
618		if (m_target == GL_TEXTURE_2D)
619		{
620			log << TestLog::Message << "Creating GL_TEXTURE_2D from EGLimage" << TestLog::EndMessage;
621
622			deUint32 dstTex = 2;
623			GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, dstTex));
624			CHECK_GL_EXT_CALL(glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image), GL_NO_ERROR);
625			GLU_CHECK_CALL(glDeleteTextures(1, &dstTex));
626		}
627		else
628		{
629			DE_ASSERT(m_target == GL_RENDERBUFFER);
630
631			log << TestLog::Message << "Creating GL_RENDERBUFFER from EGLimage" << TestLog::EndMessage;
632
633			deUint32 dstRbo = 2;
634			GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, dstRbo));
635			CHECK_GL_EXT_CALL(glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)image), GL_NO_ERROR);
636			GLU_CHECK_CALL(glDeleteRenderbuffers(1, &dstRbo));
637		}
638
639		// Destroy image
640		CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
641
642		// Destroy source texture object
643		GLU_CHECK_CALL(glDeleteTextures(1, &srcTex));
644
645		return STOP;
646	}
647
648private:
649	GLenum	m_target;
650};
651
652class ApiTests : public TestCaseGroup
653{
654public:
655	ApiTests (EglTestContext& eglTestCtx)
656		: TestCaseGroup(eglTestCtx, "api", "EGLImage API tests")
657	{
658	}
659
660	void init (void)
661	{
662		addChild(new Image::InvalidCreateImage(m_eglTestCtx));
663
664		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_2D_KHR, GL_RGB));
665		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_2D_KHR, GL_RGBA));
666		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_2D_KHR, GL_RGBA, true));
667
668		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, GL_RGB));
669		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, GL_RGBA));
670		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, GL_RGBA, true));
671
672		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR, GL_RGBA));
673		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR, GL_RGBA));
674		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR, GL_RGBA));
675		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR, GL_RGBA));
676		addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR, GL_RGBA));
677
678		static const GLenum rboStorages[] =
679		{
680			GL_DEPTH_COMPONENT16,
681			GL_RGBA4,
682			GL_RGB5_A1,
683			GL_RGB565,
684			GL_STENCIL_INDEX8
685		};
686		for (int storageNdx = 0; storageNdx < DE_LENGTH_OF_ARRAY(rboStorages); storageNdx++)
687			addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_RENDERBUFFER_KHR, rboStorages[storageNdx]));
688
689		addChild(new Image::ImageTargetGLES2(m_eglTestCtx, GL_TEXTURE_2D));
690		addChild(new Image::ImageTargetGLES2(m_eglTestCtx, GL_RENDERBUFFER));
691	}
692};
693
694} // Image
695
696ImageTests::ImageTests (EglTestContext& eglTestCtx)
697	: TestCaseGroup(eglTestCtx, "image", "EGLImage Tests")
698{
699}
700
701ImageTests::~ImageTests (void)
702{
703}
704
705void ImageTests::init (void)
706{
707	addChild(new Image::ApiTests(m_eglTestCtx));
708	addChild(new Image::SimpleCreationTests(m_eglTestCtx));
709	addChild(new Image::ModifyTests(m_eglTestCtx));
710	addChild(new Image::MultiContextRenderTests(m_eglTestCtx));
711}
712
713} // egl
714} // deqp
715