1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 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 Texture specification tests.
22 *
23 * \todo [pyry] Following tests are missing:
24 *  - Specify mipmap incomplete texture, use without mipmaps, re-specify
25 *    as complete and render.
26 *  - Randomly re-specify levels to eventually reach mipmap-complete texture.
27 *//*--------------------------------------------------------------------*/
28
29#include "es2fTextureSpecificationTests.hpp"
30#include "tcuTestLog.hpp"
31#include "tcuImageCompare.hpp"
32#include "gluTextureUtil.hpp"
33#include "sglrContextUtil.hpp"
34#include "sglrContextWrapper.hpp"
35#include "sglrGLContext.hpp"
36#include "sglrReferenceContext.hpp"
37#include "glsTextureTestUtil.hpp"
38#include "tcuTextureUtil.hpp"
39#include "tcuFormatUtil.hpp"
40#include "tcuVectorUtil.hpp"
41#include "deRandom.hpp"
42#include "deStringUtil.hpp"
43
44#include "glwEnums.hpp"
45#include "glwFunctions.hpp"
46
47namespace deqp
48{
49namespace gles2
50{
51namespace Functional
52{
53
54using std::string;
55using std::vector;
56using std::pair;
57using tcu::TestLog;
58using tcu::Vec4;
59using tcu::IVec4;
60using tcu::UVec4;
61
62tcu::TextureFormat mapGLUnsizedInternalFormat (deUint32 internalFormat)
63{
64	using tcu::TextureFormat;
65	switch (internalFormat)
66	{
67		case GL_ALPHA:				return TextureFormat(TextureFormat::A,		TextureFormat::UNORM_INT8);
68		case GL_LUMINANCE:			return TextureFormat(TextureFormat::L,		TextureFormat::UNORM_INT8);
69		case GL_LUMINANCE_ALPHA:	return TextureFormat(TextureFormat::LA,		TextureFormat::UNORM_INT8);
70		case GL_RGB:				return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT8);
71		case GL_RGBA:				return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
72		default:
73			throw tcu::InternalError(string("Can't map GL unsized internal format (") + tcu::toHex(internalFormat).toString() + ") to texture format");
74	}
75}
76
77template <int Size>
78static tcu::Vector<float, Size> randomVector (de::Random& rnd, const tcu::Vector<float, Size>& minVal = tcu::Vector<float, Size>(0.0f), const tcu::Vector<float, Size>& maxVal = tcu::Vector<float, Size>(1.0f))
79{
80	tcu::Vector<float, Size> res;
81	for (int ndx = 0; ndx < Size; ndx++)
82		res[ndx] = rnd.getFloat(minVal[ndx], maxVal[ndx]);
83	return res;
84}
85
86static tcu::IVec4 getPixelFormatCompareDepth (const tcu::PixelFormat& pixelFormat, tcu::TextureFormat textureFormat)
87{
88	switch (textureFormat.order)
89	{
90		case tcu::TextureFormat::L:
91		case tcu::TextureFormat::LA:
92			return tcu::IVec4(pixelFormat.redBits, pixelFormat.redBits, pixelFormat.redBits, pixelFormat.alphaBits);
93		default:
94			return tcu::IVec4(pixelFormat.redBits, pixelFormat.greenBits, pixelFormat.blueBits, pixelFormat.alphaBits);
95	}
96}
97
98static tcu::UVec4 computeCompareThreshold (const tcu::PixelFormat& pixelFormat, tcu::TextureFormat textureFormat)
99{
100	const IVec4		texFormatBits		= tcu::getTextureFormatBitDepth(textureFormat);
101	const IVec4		pixelFormatBits		= getPixelFormatCompareDepth(pixelFormat, textureFormat);
102	const IVec4		accurateFmtBits		= min(pixelFormatBits, texFormatBits);
103	const IVec4		compareBits			= select(accurateFmtBits, IVec4(8), greaterThan(accurateFmtBits, IVec4(0))) - 1;
104
105	return (IVec4(1) << (8-compareBits)).asUint();
106}
107
108class GradientShader : public sglr::ShaderProgram
109{
110public:
111	GradientShader (void)
112		: ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
113					<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
114					<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
115					<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
116					<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
117					<< sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
118												"attribute mediump vec2 a_coord;\n"
119												"varying mediump vec2 v_coord;\n"
120												"void main (void)\n"
121												"{\n"
122												"	gl_Position = a_position;\n"
123												"	v_coord = a_coord;\n"
124												"}\n")
125					<< sglr::pdec::FragmentSource("varying mediump vec2 v_coord;\n"
126												  "void main (void)\n"
127												  "{\n"
128												  "	mediump float x = v_coord.x;\n"
129												  "	mediump float y = v_coord.y;\n"
130												  "	mediump float f0 = (x + y) * 0.5;\n"
131												  "	mediump float f1 = 0.5 + (x - y) * 0.5;\n"
132												  "	gl_FragColor = vec4(f0, f1, 1.0-f0, 1.0-f1);\n"
133												  "}\n"))
134	{
135	}
136
137	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
138	{
139		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
140		{
141			rr::VertexPacket& packet = *packets[packetNdx];
142
143			packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
144			packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
145		}
146	}
147
148	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
149	{
150		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
151		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
152		{
153			const tcu::Vec4		coord	= rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
154			const float			x		= coord.x();
155			const float			y		= coord.y();
156			const float			f0		= (x + y) * 0.5f;
157			const float			f1		= 0.5f + (x - y) * 0.5f;
158			const tcu::Vec4		fv		= Vec4(f0, f1, 1.0f-f0, 1.0f-f1);
159
160			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(f0, f1, 1.0f-f0, 1.0f-f1));
161		}
162	}
163};
164
165class Tex2DShader : public sglr::ShaderProgram
166{
167public:
168	Tex2DShader (void)
169		: ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
170					<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
171					<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
172					<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
173					<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
174					<< sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_2D)
175					<< sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
176												"attribute mediump vec2 a_coord;\n"
177												"varying mediump vec2 v_coord;\n"
178												"void main (void)\n"
179												"{\n"
180												"	gl_Position = a_position;\n"
181												"	v_coord = a_coord;\n"
182												"}\n")
183					<< sglr::pdec::FragmentSource("uniform sampler2D u_sampler0;\n"
184												  "varying mediump vec2 v_coord;\n"
185												  "void main (void)\n"
186												  "{\n"
187												  "	gl_FragColor = texture2D(u_sampler0, v_coord);\n"
188												  "}\n"))
189	{
190	}
191
192	void setUniforms (sglr::Context& ctx, deUint32 program) const
193	{
194		ctx.useProgram(program);
195		ctx.uniform1i(ctx.getUniformLocation(program, "u_sampler0"), 0);
196	}
197
198	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
199	{
200		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
201		{
202			rr::VertexPacket& packet = *packets[packetNdx];
203
204			packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
205			packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
206		}
207	}
208
209	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
210	{
211		tcu::Vec2 texCoords[4];
212		tcu::Vec4 colors[4];
213
214		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
215		{
216			// setup tex coords
217			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
218			{
219				const tcu::Vec4	coord = rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
220				texCoords[fragNdx] = tcu::Vec2(coord.x(), coord.y());
221			}
222
223			// Sample
224			m_uniforms[0].sampler.tex2D->sample4(colors, texCoords);
225
226			// Write out
227			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
228				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, colors[fragNdx]);
229		}
230	}
231};
232
233static const char* s_cubeSwizzles[] =
234{
235	"vec3(-1, -y, +x)",
236	"vec3(+1, -y, -x)",
237	"vec3(+x, -1, -y)",
238	"vec3(+x, +1, +y)",
239	"vec3(-x, -y, -1)",
240	"vec3(+x, -y, +1)"
241};
242
243class TexCubeShader : public sglr::ShaderProgram
244{
245public:
246	TexCubeShader (tcu::CubeFace face)
247		: ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
248					<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
249					<< sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
250					<< sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
251					<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
252					<< sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_CUBE)
253					<< sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
254												"attribute mediump vec2 a_coord;\n"
255												"varying mediump vec2 v_coord;\n"
256												"void main (void)\n"
257												"{\n"
258												"	gl_Position = a_position;\n"
259												"	v_coord = a_coord;\n"
260												"}\n")
261					<< sglr::pdec::FragmentSource(string("") +
262												  "uniform samplerCube u_sampler0;\n"
263												  "varying mediump vec2 v_coord;\n"
264												  "void main (void)\n"
265												  "{\n"
266												  "	mediump float x = v_coord.x*2.0 - 1.0;\n"
267												  "	mediump float y = v_coord.y*2.0 - 1.0;\n"
268												  "	gl_FragColor = textureCube(u_sampler0, " + s_cubeSwizzles[face] + ");\n"
269												  "}\n"))
270		, m_face(face)
271	{
272	}
273
274	void setUniforms (sglr::Context& ctx, deUint32 program) const
275	{
276		ctx.useProgram(program);
277		ctx.uniform1i(ctx.getUniformLocation(program, "u_sampler0"), 0);
278	}
279
280	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
281	{
282		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
283		{
284			rr::VertexPacket& packet = *packets[packetNdx];
285
286			packet.position		= rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
287			packet.outputs[0]	= rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
288		}
289	}
290
291	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
292	{
293		tcu::Vec3 texCoords[4];
294		tcu::Vec4 colors[4];
295
296		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
297		{
298			// setup tex coords
299			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
300			{
301				const tcu::Vec4	coord	= rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx);
302				const float		x		= coord.x()*2.0f - 1.0f;
303				const float		y		= coord.y()*2.0f - 1.0f;
304
305				// Swizzle tex coords
306				switch (m_face)
307				{
308					case tcu::CUBEFACE_NEGATIVE_X:	texCoords[fragNdx] = tcu::Vec3(-1.0f,    -y,    +x);		break;
309					case tcu::CUBEFACE_POSITIVE_X:	texCoords[fragNdx] = tcu::Vec3(+1.0f,    -y,    -x);		break;
310					case tcu::CUBEFACE_NEGATIVE_Y:	texCoords[fragNdx] = tcu::Vec3(   +x, -1.0f,    -y);		break;
311					case tcu::CUBEFACE_POSITIVE_Y:	texCoords[fragNdx] = tcu::Vec3(   +x, +1.0f,    +y);		break;
312					case tcu::CUBEFACE_NEGATIVE_Z:	texCoords[fragNdx] = tcu::Vec3(   -x,    -y, -1.0f);		break;
313					case tcu::CUBEFACE_POSITIVE_Z:	texCoords[fragNdx] = tcu::Vec3(   +x,    -y, +1.0f);		break;
314					default:
315						DE_ASSERT(false);
316				}
317			}
318
319			// Sample
320			m_uniforms[0].sampler.texCube->sample4(colors, texCoords);
321
322			// Write out
323			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
324				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, colors[fragNdx]);
325		}
326	}
327private:
328	tcu::CubeFace m_face;
329};
330
331enum TextureType
332{
333	TEXTURETYPE_2D = 0,
334	TEXTURETYPE_CUBE,
335
336	TEXTURETYPE_LAST
337};
338
339enum Flags
340{
341	MIPMAPS		= (1<<0)
342};
343
344static const deUint32 s_cubeMapFaces[] =
345{
346	GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
347	GL_TEXTURE_CUBE_MAP_POSITIVE_X,
348	GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
349	GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
350	GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
351	GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
352};
353
354class TextureSpecCase : public TestCase, public sglr::ContextWrapper
355{
356public:
357								TextureSpecCase		(Context& context, const char* name, const char* desc, const TextureType type, const tcu::TextureFormat format, const deUint32 flags, int width, int height);
358								~TextureSpecCase	(void);
359
360	IterateResult				iterate				(void);
361
362protected:
363	virtual void				createTexture		(void) = DE_NULL;
364
365	const TextureType			m_texType;
366	const tcu::TextureFormat	m_texFormat;
367	const deUint32				m_flags;
368	const int					m_width;
369	const int					m_height;
370
371private:
372								TextureSpecCase		(const TextureSpecCase& other);
373	TextureSpecCase&			operator=			(const TextureSpecCase& other);
374
375	void						verifyTex2D			(sglr::GLContext& gles2Context, sglr::ReferenceContext& refContext);
376	void						verifyTexCube		(sglr::GLContext& gles2Context, sglr::ReferenceContext& refContext);
377
378	void						renderTex2D			(tcu::Surface& dst, int width, int height);
379	void						renderTexCube		(tcu::Surface& dst, int width, int height, tcu::CubeFace face);
380
381	void						readPixels			(tcu::Surface& dst, int x, int y, int width, int height);
382
383	// \todo [2012-03-27 pyry] Renderer should be extended to allow custom attributes, that would clean up this cubemap mess.
384	Tex2DShader					m_tex2DShader;
385	TexCubeShader				m_texCubeNegXShader;
386	TexCubeShader				m_texCubePosXShader;
387	TexCubeShader				m_texCubeNegYShader;
388	TexCubeShader				m_texCubePosYShader;
389	TexCubeShader				m_texCubeNegZShader;
390	TexCubeShader				m_texCubePosZShader;
391};
392
393TextureSpecCase::TextureSpecCase (Context& context, const char* name, const char* desc, const TextureType type, const tcu::TextureFormat format, const deUint32 flags, int width, int height)
394	: TestCase				(context, name, desc)
395	, m_texType				(type)
396	, m_texFormat			(format)
397	, m_flags				(flags)
398	, m_width				(width)
399	, m_height				(height)
400	, m_texCubeNegXShader	(tcu::CUBEFACE_NEGATIVE_X)
401	, m_texCubePosXShader	(tcu::CUBEFACE_POSITIVE_X)
402	, m_texCubeNegYShader	(tcu::CUBEFACE_NEGATIVE_Y)
403	, m_texCubePosYShader	(tcu::CUBEFACE_POSITIVE_Y)
404	, m_texCubeNegZShader	(tcu::CUBEFACE_NEGATIVE_Z)
405	, m_texCubePosZShader	(tcu::CUBEFACE_POSITIVE_Z)
406{
407}
408
409TextureSpecCase::~TextureSpecCase (void)
410{
411}
412
413TextureSpecCase::IterateResult TextureSpecCase::iterate (void)
414{
415	glu::RenderContext&			renderCtx				= TestCase::m_context.getRenderContext();
416	const tcu::RenderTarget&	renderTarget			= renderCtx.getRenderTarget();
417	tcu::TestLog&				log						= m_testCtx.getLog();
418
419	DE_ASSERT(m_width <= 256 && m_height <= 256);
420	if (renderTarget.getWidth() < m_width || renderTarget.getHeight() < m_height)
421		throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
422
423	// Context size, and viewport for GLES2
424	de::Random		rnd			(deStringHash(getName()));
425	int				width		= deMin32(renderTarget.getWidth(),	256);
426	int				height		= deMin32(renderTarget.getHeight(),	256);
427	int				x			= rnd.getInt(0, renderTarget.getWidth()		- width);
428	int				y			= rnd.getInt(0, renderTarget.getHeight()	- height);
429
430	// Contexts.
431	sglr::GLContext					gles2Context	(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(x, y, width, height));
432	sglr::ReferenceContextBuffers	refBuffers		(tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), 0 /* depth */, 0 /* stencil */, width, height);
433	sglr::ReferenceContext			refContext		(sglr::ReferenceContextLimits(renderCtx), refBuffers.getColorbuffer(), refBuffers.getDepthbuffer(), refBuffers.getStencilbuffer());
434
435	// Clear color buffer.
436	for (int ndx = 0; ndx < 2; ndx++)
437	{
438		setContext(ndx ? (sglr::Context*)&refContext : (sglr::Context*)&gles2Context);
439		glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
440		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
441	}
442
443	// Construct texture using both GLES2 and reference contexts.
444	for (int ndx = 0; ndx < 2; ndx++)
445	{
446		setContext(ndx ? (sglr::Context*)&refContext : (sglr::Context*)&gles2Context);
447		createTexture();
448		TCU_CHECK(glGetError() == GL_NO_ERROR);
449	}
450
451	// Setup texture filtering state.
452	for (int ndx = 0; ndx < 2; ndx++)
453	{
454		setContext(ndx ? (sglr::Context*)&refContext : (sglr::Context*)&gles2Context);
455
456		deUint32 texTarget = m_texType == TEXTURETYPE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP;
457		glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER,	(m_flags & MIPMAPS) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
458		glTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
459		glTexParameteri(texTarget, GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
460		glTexParameteri(texTarget, GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
461	}
462
463	// Initialize case result to pass.
464	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
465
466	// Disable logging.
467	gles2Context.enableLogging(0);
468
469	// Verify results.
470	switch (m_texType)
471	{
472		case TEXTURETYPE_2D:	verifyTex2D		(gles2Context, refContext);	break;
473		case TEXTURETYPE_CUBE:	verifyTexCube	(gles2Context, refContext);	break;
474		default:
475			DE_ASSERT(false);
476	}
477
478	return STOP;
479}
480
481void TextureSpecCase::verifyTex2D (sglr::GLContext& gles2Context, sglr::ReferenceContext& refContext)
482{
483	int numLevels = (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
484
485	DE_ASSERT(m_texType == TEXTURETYPE_2D);
486
487	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
488	{
489		int				levelW		= de::max(1, m_width >> levelNdx);
490		int				levelH		= de::max(1, m_height >> levelNdx);
491		tcu::Surface	reference;
492		tcu::Surface	result;
493
494		if (levelW <= 2 || levelH <= 2)
495			continue; // Don't bother checking.
496
497		// Render with GLES2
498		setContext(&gles2Context);
499		renderTex2D(result, levelW, levelH);
500
501		// Render reference.
502		setContext(&refContext);
503		renderTex2D(reference, levelW, levelH);
504
505		{
506			tcu::UVec4	threshold	= computeCompareThreshold(m_context.getRenderTarget().getPixelFormat(), m_texFormat);
507			bool		isOk		= tcu::intThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold,
508															   levelNdx == 0 ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
509
510			if (!isOk)
511			{
512				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
513				break;
514			}
515		}
516	}
517}
518
519void TextureSpecCase::verifyTexCube (sglr::GLContext& gles2Context, sglr::ReferenceContext& refContext)
520{
521	int numLevels = (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
522
523	DE_ASSERT(m_texType == TEXTURETYPE_CUBE);
524
525	for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
526	{
527		int		levelW	= de::max(1, m_width >> levelNdx);
528		int		levelH	= de::max(1, m_height >> levelNdx);
529		bool	isOk	= true;
530
531		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
532		{
533			tcu::Surface	reference;
534			tcu::Surface	result;
535
536			if (levelW <= 2 || levelH <= 2)
537				continue; // Don't bother checking.
538
539			// Render with GLES2
540			setContext(&gles2Context);
541			renderTexCube(result, levelW, levelH, (tcu::CubeFace)face);
542
543			// Render reference.
544			setContext(&refContext);
545			renderTexCube(reference, levelW, levelH, (tcu::CubeFace)face);
546
547			const float	threshold	= 0.02f;
548			isOk = tcu::fuzzyCompare(m_testCtx.getLog(), "Result", (string("Image comparison result: ") + de::toString((tcu::CubeFace)face)).c_str(), reference, result, threshold,
549									 levelNdx == 0 ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
550
551			if (!isOk)
552			{
553				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
554				break;
555			}
556		}
557
558		if (!isOk)
559			break;
560	}
561}
562
563void TextureSpecCase::renderTex2D (tcu::Surface& dst, int width, int height)
564{
565	int			targetW		= getWidth();
566	int			targetH		= getHeight();
567
568	float		w			= (float)width	/ (float)targetW;
569	float		h			= (float)height	/ (float)targetH;
570
571	deUint32	shaderID	= getCurrentContext()->createProgram(&m_tex2DShader);
572
573	m_tex2DShader.setUniforms(*getCurrentContext(), shaderID);
574	sglr::drawQuad(*getCurrentContext(), shaderID, tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(-1.0f + w*2.0f, -1.0f + h*2.0f, 0.0f));
575
576	// Read pixels back.
577	readPixels(dst, 0, 0, width, height);
578}
579
580void TextureSpecCase::renderTexCube (tcu::Surface& dst, int width, int height, tcu::CubeFace face)
581{
582	int		targetW		= getWidth();
583	int		targetH		= getHeight();
584
585	float	w			= (float)width	/ (float)targetW;
586	float	h			= (float)height	/ (float)targetH;
587
588	TexCubeShader* shaders[] =
589	{
590		&m_texCubeNegXShader,
591		&m_texCubePosXShader,
592		&m_texCubeNegYShader,
593		&m_texCubePosYShader,
594		&m_texCubeNegZShader,
595		&m_texCubePosZShader
596	};
597
598	deUint32	shaderID	= getCurrentContext()->createProgram(shaders[face]);
599
600	shaders[face]->setUniforms(*getCurrentContext(), shaderID);
601	sglr::drawQuad(*getCurrentContext(), shaderID, tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(-1.0f + w*2.0f, -1.0f + h*2.0f, 0.0f));
602
603	// Read pixels back.
604	readPixels(dst, 0, 0, width, height);
605}
606
607void TextureSpecCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height)
608{
609	dst.setSize(width, height);
610	glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, dst.getAccess().getDataPtr());
611}
612
613// Basic TexImage2D() with 2D texture usage
614class BasicTexImage2DCase : public TextureSpecCase
615{
616public:
617	BasicTexImage2DCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
618		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, glu::mapGLTransferFormat(format, dataType), flags, width, height)
619		, m_format			(format)
620		, m_dataType		(dataType)
621	{
622	}
623
624protected:
625	void createTexture (void)
626	{
627		tcu::TextureFormat	fmt			= m_texFormat;
628		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
629		deUint32			tex			= 0;
630		tcu::TextureLevel	levelData	(fmt);
631		de::Random			rnd			(deStringHash(getName()));
632
633		glGenTextures(1, &tex);
634		glBindTexture(GL_TEXTURE_2D, tex);
635		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
636
637		for (int ndx = 0; ndx < numLevels; ndx++)
638		{
639			int		levelW		= de::max(1, m_width >> ndx);
640			int		levelH		= de::max(1, m_height >> ndx);
641			Vec4	gMin		= randomVector<4>(rnd);
642			Vec4	gMax		= randomVector<4>(rnd);
643
644			levelData.setSize(levelW, levelH);
645			tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax);
646
647			glTexImage2D(GL_TEXTURE_2D, ndx, m_format, levelW, levelH, 0, m_format, m_dataType, levelData.getAccess().getDataPtr());
648		}
649	}
650
651	deUint32	m_format;
652	deUint32	m_dataType;
653};
654
655// Basic TexImage2D() with cubemap usage
656class BasicTexImageCubeCase : public TextureSpecCase
657{
658public:
659	BasicTexImageCubeCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
660		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, glu::mapGLTransferFormat(format, dataType), flags, width, height)
661		, m_format			(format)
662		, m_dataType		(dataType)
663	{
664	}
665
666protected:
667	void createTexture (void)
668	{
669		tcu::TextureFormat	fmt			= m_texFormat;
670		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
671		deUint32			tex			= 0;
672		tcu::TextureLevel	levelData	(fmt);
673		de::Random			rnd			(deStringHash(getName()));
674
675		DE_ASSERT(m_width == m_height); // Non-square cubemaps are not supported by GLES2.
676
677		glGenTextures(1, &tex);
678		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
679		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
680
681		for (int ndx = 0; ndx < numLevels; ndx++)
682		{
683			int		levelW		= de::max(1, m_width >> ndx);
684			int		levelH		= de::max(1, m_height >> ndx);
685
686			levelData.setSize(levelW, levelH);
687
688			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
689			{
690				Vec4 gMin = randomVector<4>(rnd);
691				Vec4 gMax = randomVector<4>(rnd);
692
693				tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax);
694
695				glTexImage2D(s_cubeMapFaces[face], ndx, m_format, levelW, levelH, 0, m_format, m_dataType, levelData.getAccess().getDataPtr());
696			}
697		}
698	}
699
700	deUint32	m_format;
701	deUint32	m_dataType;
702};
703
704// Randomized 2D texture specification using TexImage2D
705class RandomOrderTexImage2DCase : public TextureSpecCase
706{
707public:
708	RandomOrderTexImage2DCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
709		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, glu::mapGLTransferFormat(format, dataType), flags, width, height)
710		, m_format			(format)
711		, m_dataType		(dataType)
712	{
713	}
714
715protected:
716	void createTexture (void)
717	{
718		tcu::TextureFormat	fmt			= m_texFormat;
719		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
720		deUint32			tex			= 0;
721		tcu::TextureLevel	levelData	(fmt);
722		de::Random			rnd			(deStringHash(getName()));
723
724		glGenTextures(1, &tex);
725		glBindTexture(GL_TEXTURE_2D, tex);
726		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
727
728		vector<int>			levels		(numLevels);
729
730		for (int i = 0; i < numLevels; i++)
731			levels[i] = i;
732		rnd.shuffle(levels.begin(), levels.end());
733
734		for (int ndx = 0; ndx < numLevels; ndx++)
735		{
736			int		levelNdx	= levels[ndx];
737			int		levelW		= de::max(1, m_width	>> levelNdx);
738			int		levelH		= de::max(1, m_height	>> levelNdx);
739			Vec4	gMin		= randomVector<4>(rnd);
740			Vec4	gMax		= randomVector<4>(rnd);
741
742			levelData.setSize(levelW, levelH);
743			tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax);
744
745			glTexImage2D(GL_TEXTURE_2D, levelNdx, m_format, levelW, levelH, 0, m_format, m_dataType, levelData.getAccess().getDataPtr());
746		}
747	}
748
749	deUint32	m_format;
750	deUint32	m_dataType;
751};
752
753// Randomized cubemap texture specification using TexImage2D
754class RandomOrderTexImageCubeCase : public TextureSpecCase
755{
756public:
757	RandomOrderTexImageCubeCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
758		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, glu::mapGLTransferFormat(format, dataType), flags, width, height)
759		, m_format			(format)
760		, m_dataType		(dataType)
761	{
762	}
763
764protected:
765	void createTexture (void)
766	{
767		tcu::TextureFormat	fmt			= m_texFormat;
768		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
769		deUint32			tex			= 0;
770		tcu::TextureLevel	levelData	(fmt);
771		de::Random			rnd			(deStringHash(getName()));
772
773		DE_ASSERT(m_width == m_height); // Non-square cubemaps are not supported by GLES2.
774
775		glGenTextures(1, &tex);
776		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
777		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
778
779		// Level-face pairs.
780		vector<pair<int, tcu::CubeFace> >	images	(numLevels*6);
781
782		for (int ndx = 0; ndx < numLevels; ndx++)
783			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
784				images[ndx*6 + face] = std::make_pair(ndx, (tcu::CubeFace)face);
785
786		rnd.shuffle(images.begin(), images.end());
787
788		for (int ndx = 0; ndx < (int)images.size(); ndx++)
789		{
790			int				levelNdx	= images[ndx].first;
791			tcu::CubeFace	face		= images[ndx].second;
792			int				levelW		= de::max(1, m_width >> levelNdx);
793			int				levelH		= de::max(1, m_height >> levelNdx);
794			Vec4			gMin		= randomVector<4>(rnd);
795			Vec4			gMax		= randomVector<4>(rnd);
796
797			levelData.setSize(levelW, levelH);
798			tcu::fillWithComponentGradients(levelData.getAccess(), gMin, gMax);
799
800			glTexImage2D(s_cubeMapFaces[face], levelNdx, m_format, levelW, levelH, 0, m_format, m_dataType, levelData.getAccess().getDataPtr());
801		}
802	}
803
804	deUint32	m_format;
805	deUint32	m_dataType;
806};
807
808static inline int getRowPitch (const tcu::TextureFormat& transferFmt, int rowLen, int alignment)
809{
810	int basePitch = transferFmt.getPixelSize()*rowLen;
811	return alignment*(basePitch/alignment + ((basePitch % alignment) ? 1 : 0));
812}
813
814// TexImage2D() unpack alignment case.
815class TexImage2DAlignCase : public TextureSpecCase
816{
817public:
818	TexImage2DAlignCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height, int alignment)
819		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, glu::mapGLTransferFormat(format, dataType), flags, width, height)
820		, m_format			(format)
821		, m_dataType		(dataType)
822		, m_alignment		(alignment)
823	{
824	}
825
826protected:
827	void createTexture (void)
828	{
829		tcu::TextureFormat	fmt			= m_texFormat;
830		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
831		deUint32			tex			= 0;
832		vector<deUint8>		data;
833
834		glGenTextures(1, &tex);
835		glBindTexture(GL_TEXTURE_2D, tex);
836		glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment);
837
838		for (int ndx = 0; ndx < numLevels; ndx++)
839		{
840			int		levelW		= de::max(1, m_width >> ndx);
841			int		levelH		= de::max(1, m_height >> ndx);
842			Vec4	colorA		(1.0f, 0.0f, 0.0f, 1.0f);
843			Vec4	colorB		(0.0f, 1.0f, 0.0f, 1.0f);
844			int		rowPitch	= getRowPitch(fmt, levelW, m_alignment);
845			int		cellSize	= de::max(1, de::min(levelW >> 2, levelH >> 2));
846
847			data.resize(rowPitch*levelH);
848			tcu::fillWithGrid(tcu::PixelBufferAccess(fmt, levelW, levelH, 1, rowPitch, 0, &data[0]), cellSize, colorA, colorB);
849
850			glTexImage2D(GL_TEXTURE_2D, ndx, m_format, levelW, levelH, 0, m_format, m_dataType, &data[0]);
851		}
852	}
853
854	deUint32	m_format;
855	deUint32	m_dataType;
856	int			m_alignment;
857};
858
859// TexImage2D() unpack alignment case.
860class TexImageCubeAlignCase : public TextureSpecCase
861{
862public:
863	TexImageCubeAlignCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height, int alignment)
864		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, glu::mapGLTransferFormat(format, dataType), flags, width, height)
865		, m_format			(format)
866		, m_dataType		(dataType)
867		, m_alignment		(alignment)
868	{
869	}
870
871protected:
872	void createTexture (void)
873	{
874		tcu::TextureFormat	fmt			= m_texFormat;
875		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
876		deUint32			tex			= 0;
877		vector<deUint8>		data;
878
879		DE_ASSERT(m_width == m_height); // Non-square cubemaps are not supported by GLES2.
880
881		glGenTextures(1, &tex);
882		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
883		glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment);
884
885		for (int ndx = 0; ndx < numLevels; ndx++)
886		{
887			int		levelW		= de::max(1, m_width >> ndx);
888			int		levelH		= de::max(1, m_height >> ndx);
889			int		rowPitch	= getRowPitch(fmt, levelW, m_alignment);
890			Vec4	colorA		(1.0f, 0.0f, 0.0f, 1.0f);
891			Vec4	colorB		(0.0f, 1.0f, 0.0f, 1.0f);
892			int		cellSize	= de::max(1, de::min(levelW >> 2, levelH >> 2));
893
894			data.resize(rowPitch*levelH);
895			tcu::fillWithGrid(tcu::PixelBufferAccess(fmt, levelW, levelH, 1, rowPitch, 0, &data[0]), cellSize, colorA, colorB);
896
897			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
898				glTexImage2D(s_cubeMapFaces[face], ndx, m_format, levelW, levelH, 0, m_format, m_dataType, &data[0]);
899		}
900	}
901
902	deUint32	m_format;
903	deUint32	m_dataType;
904	int			m_alignment;
905};
906
907// Basic TexSubImage2D() with 2D texture usage
908class BasicTexSubImage2DCase : public TextureSpecCase
909{
910public:
911	BasicTexSubImage2DCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
912		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, glu::mapGLTransferFormat(format, dataType), flags, width, height)
913		, m_format			(format)
914		, m_dataType		(dataType)
915	{
916	}
917
918protected:
919	void createTexture (void)
920	{
921		tcu::TextureFormat	fmt			= m_texFormat;
922		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
923		deUint32			tex			= 0;
924		tcu::TextureLevel	data		(fmt);
925		de::Random			rnd			(deStringHash(getName()));
926
927		glGenTextures(1, &tex);
928		glBindTexture(GL_TEXTURE_2D, tex);
929		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
930
931		// First specify full texture.
932		for (int ndx = 0; ndx < numLevels; ndx++)
933		{
934			int		levelW		= de::max(1, m_width >> ndx);
935			int		levelH		= de::max(1, m_height >> ndx);
936			Vec4	gMin		= randomVector<4>(rnd);
937			Vec4	gMax		= randomVector<4>(rnd);
938
939			data.setSize(levelW, levelH);
940			tcu::fillWithComponentGradients(data.getAccess(), gMin, gMax);
941
942			glTexImage2D(GL_TEXTURE_2D, ndx, m_format, levelW, levelH, 0, m_format, m_dataType, data.getAccess().getDataPtr());
943		}
944
945		// Re-specify parts of each level.
946		for (int ndx = 0; ndx < numLevels; ndx++)
947		{
948			int		levelW		= de::max(1, m_width >> ndx);
949			int		levelH		= de::max(1, m_height >> ndx);
950
951			int		w			= rnd.getInt(1, levelW);
952			int		h			= rnd.getInt(1, levelH);
953			int		x			= rnd.getInt(0, levelW-w);
954			int		y			= rnd.getInt(0, levelH-h);
955
956			Vec4	colorA		= randomVector<4>(rnd);
957			Vec4	colorB		= randomVector<4>(rnd);
958			int		cellSize	= rnd.getInt(2, 16);
959
960			data.setSize(w, h);
961			tcu::fillWithGrid(data.getAccess(), cellSize, colorA, colorB);
962
963			glTexSubImage2D(GL_TEXTURE_2D, ndx, x, y, w, h, m_format, m_dataType, data.getAccess().getDataPtr());
964		}
965	}
966
967	deUint32	m_format;
968	deUint32	m_dataType;
969};
970
971// Basic TexSubImage2D() with cubemap usage
972class BasicTexSubImageCubeCase : public TextureSpecCase
973{
974public:
975	BasicTexSubImageCubeCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
976		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, glu::mapGLTransferFormat(format, dataType), flags, width, height)
977		, m_format			(format)
978		, m_dataType		(dataType)
979	{
980	}
981
982protected:
983	void createTexture (void)
984	{
985		tcu::TextureFormat	fmt			= m_texFormat;
986		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
987		deUint32			tex			= 0;
988		tcu::TextureLevel	data		(fmt);
989		de::Random			rnd			(deStringHash(getName()));
990
991		DE_ASSERT(m_width == m_height); // Non-square cubemaps are not supported by GLES2.
992
993		glGenTextures(1, &tex);
994		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
995		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
996
997		for (int ndx = 0; ndx < numLevels; ndx++)
998		{
999			int		levelW		= de::max(1, m_width >> ndx);
1000			int		levelH		= de::max(1, m_height >> ndx);
1001
1002			data.setSize(levelW, levelH);
1003
1004			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
1005			{
1006				Vec4 gMin = randomVector<4>(rnd);
1007				Vec4 gMax = randomVector<4>(rnd);
1008
1009				tcu::fillWithComponentGradients(data.getAccess(), gMin, gMax);
1010
1011				glTexImage2D(s_cubeMapFaces[face], ndx, m_format, levelW, levelH, 0, m_format, m_dataType, data.getAccess().getDataPtr());
1012			}
1013		}
1014
1015		// Re-specify parts of each face and level.
1016		for (int ndx = 0; ndx < numLevels; ndx++)
1017		{
1018			int		levelW		= de::max(1, m_width >> ndx);
1019			int		levelH		= de::max(1, m_height >> ndx);
1020
1021			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
1022			{
1023				int		w			= rnd.getInt(1, levelW);
1024				int		h			= rnd.getInt(1, levelH);
1025				int		x			= rnd.getInt(0, levelW-w);
1026				int		y			= rnd.getInt(0, levelH-h);
1027
1028				Vec4	colorA		= randomVector<4>(rnd);
1029				Vec4	colorB		= randomVector<4>(rnd);
1030				int		cellSize	= rnd.getInt(2, 16);
1031
1032				data.setSize(w, h);
1033				tcu::fillWithGrid(data.getAccess(), cellSize, colorA, colorB);
1034
1035				glTexSubImage2D(s_cubeMapFaces[face], ndx, x, y, w, h, m_format, m_dataType, data.getAccess().getDataPtr());
1036			}
1037		}
1038	}
1039
1040	deUint32	m_format;
1041	deUint32	m_dataType;
1042};
1043
1044// TexSubImage2D() to texture initialized with empty data
1045class TexSubImage2DEmptyTexCase : public TextureSpecCase
1046{
1047public:
1048	TexSubImage2DEmptyTexCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
1049		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, glu::mapGLTransferFormat(format, dataType), flags, width, height)
1050		, m_format			(format)
1051		, m_dataType		(dataType)
1052	{
1053	}
1054
1055protected:
1056	void createTexture (void)
1057	{
1058		tcu::TextureFormat	fmt			= m_texFormat;
1059		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
1060		deUint32			tex			= 0;
1061		tcu::TextureLevel	data		(fmt);
1062		de::Random			rnd			(deStringHash(getName()));
1063
1064		glGenTextures(1, &tex);
1065		glBindTexture(GL_TEXTURE_2D, tex);
1066		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1067
1068		// First allocate storage for each level.
1069		for (int ndx = 0; ndx < numLevels; ndx++)
1070		{
1071			int		levelW		= de::max(1, m_width >> ndx);
1072			int		levelH		= de::max(1, m_height >> ndx);
1073
1074			glTexImage2D(GL_TEXTURE_2D, ndx, m_format, levelW, levelH, 0, m_format, m_dataType, DE_NULL);
1075		}
1076
1077		// Specify pixel data to all levels using glTexSubImage2D()
1078		for (int ndx = 0; ndx < numLevels; ndx++)
1079		{
1080			int		levelW		= de::max(1, m_width >> ndx);
1081			int		levelH		= de::max(1, m_height >> ndx);
1082			Vec4	gMin		= randomVector<4>(rnd);
1083			Vec4	gMax		= randomVector<4>(rnd);
1084
1085			data.setSize(levelW, levelH);
1086			tcu::fillWithComponentGradients(data.getAccess(), gMin, gMax);
1087
1088			glTexSubImage2D(GL_TEXTURE_2D, ndx, 0, 0, levelW, levelH, m_format, m_dataType, data.getAccess().getDataPtr());
1089		}
1090	}
1091
1092	deUint32	m_format;
1093	deUint32	m_dataType;
1094};
1095
1096// TexSubImage2D() to empty cubemap texture
1097class TexSubImageCubeEmptyTexCase : public TextureSpecCase
1098{
1099public:
1100	TexSubImageCubeEmptyTexCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
1101		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, glu::mapGLTransferFormat(format, dataType), flags, width, height)
1102		, m_format			(format)
1103		, m_dataType		(dataType)
1104	{
1105	}
1106
1107protected:
1108	void createTexture (void)
1109	{
1110		tcu::TextureFormat	fmt			= m_texFormat;
1111		int					numLevels	= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
1112		deUint32			tex			= 0;
1113		tcu::TextureLevel	data		(fmt);
1114		de::Random			rnd			(deStringHash(getName()));
1115
1116		DE_ASSERT(m_width == m_height); // Non-square cubemaps are not supported by GLES2.
1117
1118		glGenTextures(1, &tex);
1119		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
1120		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1121
1122		// Specify storage for each level.
1123		for (int ndx = 0; ndx < numLevels; ndx++)
1124		{
1125			int		levelW		= de::max(1, m_width >> ndx);
1126			int		levelH		= de::max(1, m_height >> ndx);
1127
1128			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
1129				glTexImage2D(s_cubeMapFaces[face], ndx, m_format, levelW, levelH, 0, m_format, m_dataType, DE_NULL);
1130		}
1131
1132		// Specify data using glTexSubImage2D()
1133		for (int ndx = 0; ndx < numLevels; ndx++)
1134		{
1135			int		levelW		= de::max(1, m_width >> ndx);
1136			int		levelH		= de::max(1, m_height >> ndx);
1137
1138			data.setSize(levelW, levelH);
1139
1140			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
1141			{
1142				Vec4 gMin = randomVector<4>(rnd);
1143				Vec4 gMax = randomVector<4>(rnd);
1144
1145				tcu::fillWithComponentGradients(data.getAccess(), gMin, gMax);
1146
1147				glTexSubImage2D(s_cubeMapFaces[face], ndx, 0, 0, levelW, levelH, m_format, m_dataType, data.getAccess().getDataPtr());
1148			}
1149		}
1150	}
1151
1152	deUint32	m_format;
1153	deUint32	m_dataType;
1154};
1155
1156// TexSubImage2D() unpack alignment with 2D texture
1157class TexSubImage2DAlignCase : public TextureSpecCase
1158{
1159public:
1160	TexSubImage2DAlignCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, int width, int height, int subX, int subY, int subW, int subH, int alignment)
1161		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, glu::mapGLTransferFormat(format, dataType), 0 /* Mipmaps are never used */, width, height)
1162		, m_format			(format)
1163		, m_dataType		(dataType)
1164		, m_subX			(subX)
1165		, m_subY			(subY)
1166		, m_subW			(subW)
1167		, m_subH			(subH)
1168		, m_alignment		(alignment)
1169	{
1170	}
1171
1172protected:
1173	void createTexture (void)
1174	{
1175		tcu::TextureFormat	fmt			= m_texFormat;
1176		deUint32			tex			= 0;
1177		vector<deUint8>		data;
1178
1179		glGenTextures(1, &tex);
1180		glBindTexture(GL_TEXTURE_2D, tex);
1181
1182		// Specify base level.
1183		data.resize(fmt.getPixelSize()*m_width*m_height);
1184		tcu::fillWithComponentGradients(tcu::PixelBufferAccess(fmt, m_width, m_height, 1, &data[0]), Vec4(0.0f), Vec4(1.0f));
1185
1186		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1187		glTexImage2D(GL_TEXTURE_2D, 0, m_format, m_width, m_height, 0, m_format, m_dataType, &data[0]);
1188
1189		// Re-specify subrectangle.
1190		int rowPitch = getRowPitch(fmt, m_subW, m_alignment);
1191		data.resize(rowPitch*m_subH);
1192		tcu::fillWithGrid(tcu::PixelBufferAccess(fmt, m_subW, m_subH, 1, rowPitch, 0, &data[0]), 4, Vec4(1.0f, 0.0f, 0.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1193
1194		glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment);
1195		glTexSubImage2D(GL_TEXTURE_2D, 0, m_subX, m_subY, m_subW, m_subH, m_format, m_dataType, &data[0]);
1196	}
1197
1198	deUint32	m_format;
1199	deUint32	m_dataType;
1200	int			m_subX;
1201	int			m_subY;
1202	int			m_subW;
1203	int			m_subH;
1204	int			m_alignment;
1205};
1206
1207// TexSubImage2D() unpack alignment with cubemap texture
1208class TexSubImageCubeAlignCase : public TextureSpecCase
1209{
1210public:
1211	TexSubImageCubeAlignCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, int width, int height, int subX, int subY, int subW, int subH, int alignment)
1212		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, glu::mapGLTransferFormat(format, dataType), 0 /* Mipmaps are never used */, width, height)
1213		, m_format			(format)
1214		, m_dataType		(dataType)
1215		, m_subX			(subX)
1216		, m_subY			(subY)
1217		, m_subW			(subW)
1218		, m_subH			(subH)
1219		, m_alignment		(alignment)
1220	{
1221	}
1222
1223protected:
1224	void createTexture (void)
1225	{
1226		tcu::TextureFormat	fmt			= m_texFormat;
1227		deUint32			tex			= 0;
1228		vector<deUint8>		data;
1229
1230		DE_ASSERT(m_width == m_height);
1231
1232		glGenTextures(1, &tex);
1233		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
1234
1235		// Specify base level.
1236		data.resize(fmt.getPixelSize()*m_width*m_height);
1237		tcu::fillWithComponentGradients(tcu::PixelBufferAccess(fmt, m_width, m_height, 1, &data[0]), Vec4(0.0f), Vec4(1.0f));
1238
1239		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1240		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1241			glTexImage2D(s_cubeMapFaces[face], 0, m_format, m_width, m_height, 0, m_format, m_dataType, &data[0]);
1242
1243		// Re-specify subrectangle.
1244		int rowPitch = getRowPitch(fmt, m_subW, m_alignment);
1245		data.resize(rowPitch*m_subH);
1246		tcu::fillWithGrid(tcu::PixelBufferAccess(fmt, m_subW, m_subH, 1, rowPitch, 0, &data[0]), 4, Vec4(1.0f, 0.0f, 0.0f, 1.0f), Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1247
1248		glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment);
1249		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1250			glTexSubImage2D(s_cubeMapFaces[face], 0, m_subX, m_subY, m_subW, m_subH, m_format, m_dataType, &data[0]);
1251	}
1252
1253	deUint32	m_format;
1254	deUint32	m_dataType;
1255	int			m_subX;
1256	int			m_subY;
1257	int			m_subW;
1258	int			m_subH;
1259	int			m_alignment;
1260};
1261
1262
1263
1264// Basic CopyTexImage2D() with 2D texture usage
1265class BasicCopyTexImage2DCase : public TextureSpecCase
1266{
1267public:
1268	BasicCopyTexImage2DCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, deUint32 flags, int width, int height)
1269		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, mapGLUnsizedInternalFormat(internalFormat), flags, width, height)
1270		, m_internalFormat	(internalFormat)
1271	{
1272	}
1273
1274protected:
1275	void createTexture (void)
1276	{
1277		const tcu::RenderTarget&	renderTarget	= TestCase::m_context.getRenderContext().getRenderTarget();
1278		bool						targetHasRGB	= renderTarget.getPixelFormat().redBits > 0 && renderTarget.getPixelFormat().greenBits > 0 && renderTarget.getPixelFormat().blueBits > 0;
1279		bool						targetHasAlpha	= renderTarget.getPixelFormat().alphaBits > 0;
1280		tcu::TextureFormat			fmt				= m_texFormat;
1281		bool						texHasRGB		= fmt.order != tcu::TextureFormat::A;
1282		bool						texHasAlpha		= fmt.order == tcu::TextureFormat::RGBA || fmt.order == tcu::TextureFormat::LA || fmt.order == tcu::TextureFormat::A;
1283		int							numLevels		= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
1284		deUint32					tex				= 0;
1285		de::Random					rnd				(deStringHash(getName()));
1286		GradientShader				shader;
1287		deUint32					shaderID		= getCurrentContext()->createProgram(&shader);
1288
1289		if ((texHasRGB && !targetHasRGB) || (texHasAlpha && !targetHasAlpha))
1290			throw tcu::NotSupportedError("Copying from current framebuffer is not supported", "", __FILE__, __LINE__);
1291
1292		// Fill render target with gradient.
1293		sglr::drawQuad(*getCurrentContext(), shaderID, tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 0.0f));
1294
1295		glGenTextures(1, &tex);
1296		glBindTexture(GL_TEXTURE_2D, tex);
1297
1298		for (int ndx = 0; ndx < numLevels; ndx++)
1299		{
1300			int		levelW		= de::max(1, m_width >> ndx);
1301			int		levelH		= de::max(1, m_height >> ndx);
1302			int		x			= rnd.getInt(0, getWidth()	- levelW);
1303			int		y			= rnd.getInt(0, getHeight()	- levelH);
1304
1305			glCopyTexImage2D(GL_TEXTURE_2D, ndx, m_internalFormat, x, y, levelW, levelH, 0);
1306		}
1307	}
1308
1309	deUint32 m_internalFormat;
1310};
1311
1312// Basic CopyTexImage2D() with cubemap usage
1313class BasicCopyTexImageCubeCase : public TextureSpecCase
1314{
1315public:
1316	BasicCopyTexImageCubeCase (Context& context, const char* name, const char* desc, deUint32 internalFormat, deUint32 flags, int width, int height)
1317		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, mapGLUnsizedInternalFormat(internalFormat), flags, width, height)
1318		, m_internalFormat	(internalFormat)
1319	{
1320	}
1321
1322protected:
1323	void createTexture (void)
1324	{
1325		const tcu::RenderTarget&	renderTarget	= TestCase::m_context.getRenderContext().getRenderTarget();
1326		bool						targetHasRGB	= renderTarget.getPixelFormat().redBits > 0 && renderTarget.getPixelFormat().greenBits > 0 && renderTarget.getPixelFormat().blueBits > 0;
1327		bool						targetHasAlpha	= renderTarget.getPixelFormat().alphaBits > 0;
1328		tcu::TextureFormat			fmt				= m_texFormat;
1329		bool						texHasRGB		= fmt.order != tcu::TextureFormat::A;
1330		bool						texHasAlpha		= fmt.order == tcu::TextureFormat::RGBA || fmt.order == tcu::TextureFormat::LA || fmt.order == tcu::TextureFormat::A;
1331		int							numLevels		= (m_flags & MIPMAPS) ? deLog2Floor32(m_width)+1 : 1;
1332		deUint32					tex				= 0;
1333		de::Random					rnd				(deStringHash(getName()));
1334		GradientShader				shader;
1335		deUint32					shaderID		= getCurrentContext()->createProgram(&shader);
1336
1337		DE_ASSERT(m_width == m_height); // Non-square cubemaps are not supported by GLES2.
1338
1339		if ((texHasRGB && !targetHasRGB) || (texHasAlpha && !targetHasAlpha))
1340			throw tcu::NotSupportedError("Copying from current framebuffer is not supported", "", __FILE__, __LINE__);
1341
1342		// Fill render target with gradient.
1343		sglr::drawQuad(*getCurrentContext(), shaderID, tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 0.0f));
1344
1345		glGenTextures(1, &tex);
1346		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
1347
1348		for (int ndx = 0; ndx < numLevels; ndx++)
1349		{
1350			int levelW = de::max(1, m_width >> ndx);
1351			int levelH = de::max(1, m_height >> ndx);
1352
1353			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
1354			{
1355				int x = rnd.getInt(0, getWidth()	- levelW);
1356				int y = rnd.getInt(0, getHeight()	- levelH);
1357
1358				glCopyTexImage2D(s_cubeMapFaces[face], ndx, m_internalFormat, x, y, levelW, levelH, 0);
1359			}
1360		}
1361	}
1362
1363	deUint32 m_internalFormat;
1364};
1365
1366
1367
1368// Basic CopyTexSubImage2D() with 2D texture usage
1369class BasicCopyTexSubImage2DCase : public TextureSpecCase
1370{
1371public:
1372	BasicCopyTexSubImage2DCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
1373		: TextureSpecCase	(context, name, desc, TEXTURETYPE_2D, glu::mapGLTransferFormat(format, dataType), flags, width, height)
1374		, m_format			(format)
1375		, m_dataType		(dataType)
1376	{
1377	}
1378
1379protected:
1380	void createTexture (void)
1381	{
1382		const tcu::RenderTarget&	renderTarget	= TestCase::m_context.getRenderContext().getRenderTarget();
1383		bool						targetHasRGB	= renderTarget.getPixelFormat().redBits > 0 && renderTarget.getPixelFormat().greenBits > 0 && renderTarget.getPixelFormat().blueBits > 0;
1384		bool						targetHasAlpha	= renderTarget.getPixelFormat().alphaBits > 0;
1385		tcu::TextureFormat			fmt				= m_texFormat;
1386		bool						texHasRGB		= fmt.order != tcu::TextureFormat::A;
1387		bool						texHasAlpha		= fmt.order == tcu::TextureFormat::RGBA || fmt.order == tcu::TextureFormat::LA || fmt.order == tcu::TextureFormat::A;
1388		int							numLevels		= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
1389		deUint32					tex				= 0;
1390		tcu::TextureLevel			data			(fmt);
1391		de::Random					rnd				(deStringHash(getName()));
1392		GradientShader				shader;
1393		deUint32					shaderID		= getCurrentContext()->createProgram(&shader);
1394
1395		if ((texHasRGB && !targetHasRGB) || (texHasAlpha && !targetHasAlpha))
1396			throw tcu::NotSupportedError("Copying from current framebuffer is not supported", "", __FILE__, __LINE__);
1397
1398		glGenTextures(1, &tex);
1399		glBindTexture(GL_TEXTURE_2D, tex);
1400		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1401
1402		// First specify full texture.
1403		for (int ndx = 0; ndx < numLevels; ndx++)
1404		{
1405			int		levelW		= de::max(1, m_width >> ndx);
1406			int		levelH		= de::max(1, m_height >> ndx);
1407
1408			Vec4	colorA		= randomVector<4>(rnd);
1409			Vec4	colorB		= randomVector<4>(rnd);
1410			int		cellSize	= rnd.getInt(2, 16);
1411
1412			data.setSize(levelW, levelH);
1413			tcu::fillWithGrid(data.getAccess(), cellSize, colorA, colorB);
1414
1415			glTexImage2D(GL_TEXTURE_2D, ndx, m_format, levelW, levelH, 0, m_format, m_dataType, data.getAccess().getDataPtr());
1416		}
1417
1418		// Fill render target with gradient.
1419		sglr::drawQuad(*getCurrentContext(), shaderID, tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 0.0f));
1420
1421		// Re-specify parts of each level.
1422		for (int ndx = 0; ndx < numLevels; ndx++)
1423		{
1424			int		levelW		= de::max(1, m_width >> ndx);
1425			int		levelH		= de::max(1, m_height >> ndx);
1426
1427			int		w			= rnd.getInt(1, levelW);
1428			int		h			= rnd.getInt(1, levelH);
1429			int		xo			= rnd.getInt(0, levelW-w);
1430			int		yo			= rnd.getInt(0, levelH-h);
1431
1432			int		x			= rnd.getInt(0, getWidth() - w);
1433			int		y			= rnd.getInt(0, getHeight() - h);
1434
1435			glCopyTexSubImage2D(GL_TEXTURE_2D, ndx, xo, yo, x, y, w, h);
1436		}
1437	}
1438
1439	deUint32	m_format;
1440	deUint32	m_dataType;
1441};
1442
1443// Basic CopyTexSubImage2D() with cubemap usage
1444class BasicCopyTexSubImageCubeCase : public TextureSpecCase
1445{
1446public:
1447	BasicCopyTexSubImageCubeCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 flags, int width, int height)
1448		: TextureSpecCase	(context, name, desc, TEXTURETYPE_CUBE, glu::mapGLTransferFormat(format, dataType), flags, width, height)
1449		, m_format			(format)
1450		, m_dataType		(dataType)
1451	{
1452	}
1453
1454protected:
1455	void createTexture (void)
1456	{
1457		const tcu::RenderTarget&	renderTarget	= TestCase::m_context.getRenderContext().getRenderTarget();
1458		bool						targetHasRGB	= renderTarget.getPixelFormat().redBits > 0 && renderTarget.getPixelFormat().greenBits > 0 && renderTarget.getPixelFormat().blueBits > 0;
1459		bool						targetHasAlpha	= renderTarget.getPixelFormat().alphaBits > 0;
1460		tcu::TextureFormat			fmt				= m_texFormat;
1461		bool						texHasRGB		= fmt.order != tcu::TextureFormat::A;
1462		bool						texHasAlpha		= fmt.order == tcu::TextureFormat::RGBA || fmt.order == tcu::TextureFormat::LA || fmt.order == tcu::TextureFormat::A;
1463		int							numLevels		= (m_flags & MIPMAPS) ? de::max(deLog2Floor32(m_width), deLog2Floor32(m_height))+1 : 1;
1464		deUint32					tex				= 0;
1465		tcu::TextureLevel			data			(fmt);
1466		de::Random					rnd				(deStringHash(getName()));
1467		GradientShader				shader;
1468		deUint32					shaderID		= getCurrentContext()->createProgram(&shader);
1469
1470		DE_ASSERT(m_width == m_height); // Non-square cubemaps are not supported by GLES2.
1471
1472		if ((texHasRGB && !targetHasRGB) || (texHasAlpha && !targetHasAlpha))
1473			throw tcu::NotSupportedError("Copying from current framebuffer is not supported", "", __FILE__, __LINE__);
1474
1475		glGenTextures(1, &tex);
1476		glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
1477		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1478
1479		for (int ndx = 0; ndx < numLevels; ndx++)
1480		{
1481			int		levelW		= de::max(1, m_width >> ndx);
1482			int		levelH		= de::max(1, m_height >> ndx);
1483
1484			data.setSize(levelW, levelH);
1485
1486			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
1487			{
1488				Vec4	colorA		= randomVector<4>(rnd);
1489				Vec4	colorB		= randomVector<4>(rnd);
1490				int		cellSize	= rnd.getInt(2, 16);
1491
1492				tcu::fillWithGrid(data.getAccess(), cellSize, colorA, colorB);
1493				glTexImage2D(s_cubeMapFaces[face], ndx, m_format, levelW, levelH, 0, m_format, m_dataType, data.getAccess().getDataPtr());
1494			}
1495		}
1496
1497		// Fill render target with gradient.
1498		sglr::drawQuad(*getCurrentContext(), shaderID, tcu::Vec3(-1.0f, -1.0f, 0.0f), tcu::Vec3(1.0f, 1.0f, 0.0f));
1499
1500		// Re-specify parts of each face and level.
1501		for (int ndx = 0; ndx < numLevels; ndx++)
1502		{
1503			int		levelW		= de::max(1, m_width >> ndx);
1504			int		levelH		= de::max(1, m_height >> ndx);
1505
1506			for (int face = 0; face < DE_LENGTH_OF_ARRAY(s_cubeMapFaces); face++)
1507			{
1508				int		w			= rnd.getInt(1, levelW);
1509				int		h			= rnd.getInt(1, levelH);
1510				int		xo			= rnd.getInt(0, levelW-w);
1511				int		yo			= rnd.getInt(0, levelH-h);
1512
1513				int		x			= rnd.getInt(0, getWidth() - w);
1514				int		y			= rnd.getInt(0, getHeight() - h);
1515
1516				glCopyTexSubImage2D(s_cubeMapFaces[face], ndx, xo, yo, x, y, w, h);
1517			}
1518		}
1519	}
1520
1521	deUint32	m_format;
1522	deUint32	m_dataType;
1523};
1524
1525TextureSpecificationTests::TextureSpecificationTests (Context& context)
1526	: TestCaseGroup(context, "specification", "Texture Specification Tests")
1527{
1528}
1529
1530TextureSpecificationTests::~TextureSpecificationTests (void)
1531{
1532}
1533
1534void TextureSpecificationTests::init (void)
1535{
1536	struct
1537	{
1538		const char*	name;
1539		deUint32	format;
1540		deUint32	dataType;
1541	} texFormats[] =
1542	{
1543		{ "a8",			GL_ALPHA,			GL_UNSIGNED_BYTE },
1544		{ "l8",			GL_LUMINANCE,		GL_UNSIGNED_BYTE },
1545		{ "la88",		GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
1546		{ "rgb565",		GL_RGB,				GL_UNSIGNED_SHORT_5_6_5 },
1547		{ "rgb888",		GL_RGB,				GL_UNSIGNED_BYTE },
1548		{ "rgba4444",	GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
1549		{ "rgba5551",	GL_RGBA,			GL_UNSIGNED_SHORT_5_5_5_1 },
1550		{ "rgba8888",	GL_RGBA,			GL_UNSIGNED_BYTE }
1551	};
1552
1553	// Basic TexImage2D usage.
1554	{
1555		tcu::TestCaseGroup* basicTexImageGroup = new tcu::TestCaseGroup(m_testCtx, "basic_teximage2d", "Basic glTexImage2D() usage");
1556		addChild(basicTexImageGroup);
1557		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(texFormats); formatNdx++)
1558		{
1559			const char*	fmtName		= texFormats[formatNdx].name;
1560			deUint32	format		= texFormats[formatNdx].format;
1561			deUint32	dataType	= texFormats[formatNdx].dataType;
1562			const int	tex2DWidth	= 64;
1563			const int	tex2DHeight	= 128;
1564			const int	texCubeSize	= 64;
1565
1566			basicTexImageGroup->addChild(new BasicTexImage2DCase	(m_context,	(string(fmtName) + "_2d").c_str(),		"",	format, dataType, MIPMAPS, tex2DWidth, tex2DHeight));
1567			basicTexImageGroup->addChild(new BasicTexImageCubeCase	(m_context,	(string(fmtName) + "_cube").c_str(),	"",	format, dataType, MIPMAPS, texCubeSize, texCubeSize));
1568		}
1569	}
1570
1571	// Randomized TexImage2D order.
1572	{
1573		tcu::TestCaseGroup* randomTexImageGroup = new tcu::TestCaseGroup(m_testCtx, "random_teximage2d", "Randomized glTexImage2D() usage");
1574		addChild(randomTexImageGroup);
1575
1576		de::Random rnd(9);
1577
1578		// 2D cases.
1579		for (int ndx = 0; ndx < 10; ndx++)
1580		{
1581			int		formatNdx	= rnd.getInt(0, DE_LENGTH_OF_ARRAY(texFormats)-1);
1582			int		width		= 1 << rnd.getInt(2, 8);
1583			int		height		= 1 << rnd.getInt(2, 8);
1584
1585			randomTexImageGroup->addChild(new RandomOrderTexImage2DCase(m_context, (string("2d_") + de::toString(ndx)).c_str(), "", texFormats[formatNdx].format, texFormats[formatNdx].dataType, MIPMAPS, width, height));
1586		}
1587
1588		// Cubemap cases.
1589		for (int ndx = 0; ndx < 10; ndx++)
1590		{
1591			int		formatNdx	= rnd.getInt(0, DE_LENGTH_OF_ARRAY(texFormats)-1);
1592			int		size		= 1 << rnd.getInt(2, 8);
1593
1594			randomTexImageGroup->addChild(new RandomOrderTexImageCubeCase(m_context, (string("cube_") + de::toString(ndx)).c_str(), "", texFormats[formatNdx].format, texFormats[formatNdx].dataType, MIPMAPS, size, size));
1595		}
1596	}
1597
1598	// TexImage2D unpack alignment.
1599	{
1600		tcu::TestCaseGroup* alignGroup = new tcu::TestCaseGroup(m_testCtx, "teximage2d_align", "glTexImage2D() unpack alignment tests");
1601		addChild(alignGroup);
1602
1603		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_l8_4_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			MIPMAPS,	 4, 8, 8));
1604		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_l8_63_1",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 30, 1));
1605		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_l8_63_2",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 30, 2));
1606		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_l8_63_4",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 30, 4));
1607		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_l8_63_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 30, 8));
1608		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba4444_51_1",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 30, 1));
1609		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba4444_51_2",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 30, 2));
1610		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba4444_51_4",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 30, 4));
1611		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba4444_51_8",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 30, 8));
1612		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgb888_39_1",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 43, 1));
1613		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgb888_39_2",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 43, 2));
1614		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgb888_39_4",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 43, 4));
1615		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgb888_39_8",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 43, 8));
1616		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba8888_47_1",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 27, 1));
1617		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba8888_47_2",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 27, 2));
1618		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba8888_47_4",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 27, 4));
1619		alignGroup->addChild(new TexImage2DAlignCase	(m_context, "2d_rgba8888_47_8",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 27, 8));
1620
1621		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_l8_4_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			MIPMAPS,	 4, 4, 8));
1622		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_l8_63_1",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 63, 1));
1623		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_l8_63_2",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 63, 2));
1624		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_l8_63_4",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 63, 4));
1625		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_l8_63_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			0,			63, 63, 8));
1626		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba4444_51_1",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 51, 1));
1627		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba4444_51_2",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 51, 2));
1628		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba4444_51_4",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 51, 4));
1629		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba4444_51_8",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	0,			51, 51, 8));
1630		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgb888_39_1",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 39, 1));
1631		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgb888_39_2",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 39, 2));
1632		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgb888_39_4",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 39, 4));
1633		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgb888_39_8",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			0,			39, 39, 8));
1634		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba8888_47_1",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 47, 1));
1635		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba8888_47_2",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 47, 2));
1636		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba8888_47_4",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 47, 4));
1637		alignGroup->addChild(new TexImageCubeAlignCase	(m_context, "cube_rgba8888_47_8",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			0,			47, 47, 8));
1638	}
1639
1640	// Basic TexSubImage2D usage.
1641	{
1642		tcu::TestCaseGroup* basicTexSubImageGroup = new tcu::TestCaseGroup(m_testCtx, "basic_texsubimage2d", "Basic glTexSubImage2D() usage");
1643		addChild(basicTexSubImageGroup);
1644		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(texFormats); formatNdx++)
1645		{
1646			const char*	fmtName		= texFormats[formatNdx].name;
1647			deUint32	format		= texFormats[formatNdx].format;
1648			deUint32	dataType	= texFormats[formatNdx].dataType;
1649			const int	tex2DWidth	= 64;
1650			const int	tex2DHeight	= 128;
1651			const int	texCubeSize	= 64;
1652
1653			basicTexSubImageGroup->addChild(new BasicTexSubImage2DCase		(m_context,	(string(fmtName) + "_2d").c_str(),		"",	format, dataType, MIPMAPS, tex2DWidth, tex2DHeight));
1654			basicTexSubImageGroup->addChild(new BasicTexSubImageCubeCase	(m_context,	(string(fmtName) + "_cube").c_str(),	"",	format, dataType, MIPMAPS, texCubeSize, texCubeSize));
1655		}
1656	}
1657
1658	// TexSubImage2D to empty texture.
1659	{
1660		tcu::TestCaseGroup* texSubImageEmptyTexGroup = new tcu::TestCaseGroup(m_testCtx, "texsubimage2d_empty_tex", "glTexSubImage2D() to texture that has storage but no data");
1661		addChild(texSubImageEmptyTexGroup);
1662		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(texFormats); formatNdx++)
1663		{
1664			const char*	fmtName		= texFormats[formatNdx].name;
1665			deUint32	format		= texFormats[formatNdx].format;
1666			deUint32	dataType	= texFormats[formatNdx].dataType;
1667			const int	tex2DWidth	= 64;
1668			const int	tex2DHeight	= 32;
1669			const int	texCubeSize	= 32;
1670
1671			texSubImageEmptyTexGroup->addChild(new TexSubImage2DEmptyTexCase	(m_context,	(string(fmtName) + "_2d").c_str(),		"",	format, dataType, MIPMAPS, tex2DWidth, tex2DHeight));
1672			texSubImageEmptyTexGroup->addChild(new TexSubImageCubeEmptyTexCase	(m_context,	(string(fmtName) + "_cube").c_str(),	"",	format, dataType, MIPMAPS, texCubeSize, texCubeSize));
1673		}
1674	}
1675
1676	// TexSubImage2D alignment cases.
1677	{
1678		tcu::TestCaseGroup* alignGroup = new tcu::TestCaseGroup(m_testCtx, "texsubimage2d_align", "glTexSubImage2D() unpack alignment tests");
1679		addChild(alignGroup);
1680
1681		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_1_1",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 1));
1682		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_1_2",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 2));
1683		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_1_4",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 4));
1684		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_1_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 8));
1685		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_63_1",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 1));
1686		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_63_2",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 2));
1687		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_63_4",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 4));
1688		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_l8_63_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 8));
1689		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba4444_51_1",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 1));
1690		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba4444_51_2",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 2));
1691		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba4444_51_4",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 4));
1692		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba4444_51_8",		"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 8));
1693		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgb888_39_1",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 1));
1694		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgb888_39_2",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 2));
1695		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgb888_39_4",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 4));
1696		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgb888_39_8",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 8));
1697		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba8888_47_1",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 1));
1698		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba8888_47_2",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 2));
1699		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba8888_47_4",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 4));
1700		alignGroup->addChild(new TexSubImage2DAlignCase		(m_context, "2d_rgba8888_47_8",		"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 8));
1701
1702		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_1_1",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 1));
1703		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_1_2",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 2));
1704		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_1_4",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 4));
1705		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_1_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64, 13, 17,  1,  6, 8));
1706		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_63_1",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 1));
1707		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_63_2",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 2));
1708		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_63_4",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 4));
1709		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_l8_63_8",			"",	GL_LUMINANCE,	GL_UNSIGNED_BYTE,			64, 64,  1,  9, 63, 30, 8));
1710		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba4444_51_1",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 1));
1711		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba4444_51_2",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 2));
1712		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba4444_51_4",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 4));
1713		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba4444_51_8",	"",	GL_RGBA,		GL_UNSIGNED_SHORT_4_4_4_4,	64, 64,  7, 29, 51, 30, 8));
1714		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgb888_39_1",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 1));
1715		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgb888_39_2",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 2));
1716		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgb888_39_4",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 4));
1717		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgb888_39_8",		"",	GL_RGB,			GL_UNSIGNED_BYTE,			64, 64, 11,  8, 39, 43, 8));
1718		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba8888_47_1",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 1));
1719		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba8888_47_2",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 2));
1720		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba8888_47_4",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 4));
1721		alignGroup->addChild(new TexSubImageCubeAlignCase	(m_context, "cube_rgba8888_47_8",	"",	GL_RGBA,		GL_UNSIGNED_BYTE,			64, 64, 10,  1, 47, 27, 8));
1722	}
1723
1724	// Basic glCopyTexImage2D() cases
1725	{
1726		tcu::TestCaseGroup* copyTexImageGroup = new tcu::TestCaseGroup(m_testCtx, "basic_copyteximage2d", "Basic glCopyTexImage2D() usage");
1727		addChild(copyTexImageGroup);
1728
1729		copyTexImageGroup->addChild(new BasicCopyTexImage2DCase		(m_context, "2d_alpha",				"",	GL_ALPHA,			MIPMAPS,	128, 64));
1730		copyTexImageGroup->addChild(new BasicCopyTexImage2DCase		(m_context, "2d_luminance",			"",	GL_LUMINANCE,		MIPMAPS,	128, 64));
1731		copyTexImageGroup->addChild(new BasicCopyTexImage2DCase		(m_context, "2d_luminance_alpha",	"",	GL_LUMINANCE_ALPHA,	MIPMAPS,	128, 64));
1732		copyTexImageGroup->addChild(new BasicCopyTexImage2DCase		(m_context, "2d_rgb",				"",	GL_RGB,				MIPMAPS,	128, 64));
1733		copyTexImageGroup->addChild(new BasicCopyTexImage2DCase		(m_context, "2d_rgba",				"",	GL_RGBA,			MIPMAPS,	128, 64));
1734
1735		copyTexImageGroup->addChild(new BasicCopyTexImageCubeCase	(m_context, "cube_alpha",			"",	GL_ALPHA,			MIPMAPS,	64, 64));
1736		copyTexImageGroup->addChild(new BasicCopyTexImageCubeCase	(m_context, "cube_luminance",		"",	GL_LUMINANCE,		MIPMAPS,	64, 64));
1737		copyTexImageGroup->addChild(new BasicCopyTexImageCubeCase	(m_context, "cube_luminance_alpha",	"",	GL_LUMINANCE_ALPHA,	MIPMAPS,	64, 64));
1738		copyTexImageGroup->addChild(new BasicCopyTexImageCubeCase	(m_context, "cube_rgb",				"",	GL_RGB,				MIPMAPS,	64, 64));
1739		copyTexImageGroup->addChild(new BasicCopyTexImageCubeCase	(m_context, "cube_rgba",			"",	GL_RGBA,			MIPMAPS,	64, 64));
1740	}
1741
1742	// Basic glCopyTexSubImage2D() cases
1743	{
1744		tcu::TestCaseGroup* copyTexSubImageGroup = new tcu::TestCaseGroup(m_testCtx, "basic_copytexsubimage2d", "Basic glCopyTexSubImage2D() usage");
1745		addChild(copyTexSubImageGroup);
1746
1747		copyTexSubImageGroup->addChild(new BasicCopyTexSubImage2DCase	(m_context, "2d_alpha",				"",	GL_ALPHA,			GL_UNSIGNED_BYTE, MIPMAPS, 128, 64));
1748		copyTexSubImageGroup->addChild(new BasicCopyTexSubImage2DCase	(m_context, "2d_luminance",			"",	GL_LUMINANCE,		GL_UNSIGNED_BYTE, MIPMAPS, 128, 64));
1749		copyTexSubImageGroup->addChild(new BasicCopyTexSubImage2DCase	(m_context, "2d_luminance_alpha",	"",	GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE, MIPMAPS, 128, 64));
1750		copyTexSubImageGroup->addChild(new BasicCopyTexSubImage2DCase	(m_context, "2d_rgb",				"",	GL_RGB,				GL_UNSIGNED_BYTE, MIPMAPS, 128, 64));
1751		copyTexSubImageGroup->addChild(new BasicCopyTexSubImage2DCase	(m_context, "2d_rgba",				"",	GL_RGBA,			GL_UNSIGNED_BYTE, MIPMAPS, 128, 64));
1752
1753		copyTexSubImageGroup->addChild(new BasicCopyTexSubImageCubeCase	(m_context, "cube_alpha",			"",	GL_ALPHA,			GL_UNSIGNED_BYTE, MIPMAPS, 64, 64));
1754		copyTexSubImageGroup->addChild(new BasicCopyTexSubImageCubeCase	(m_context, "cube_luminance",		"",	GL_LUMINANCE,		GL_UNSIGNED_BYTE, MIPMAPS, 64, 64));
1755		copyTexSubImageGroup->addChild(new BasicCopyTexSubImageCubeCase	(m_context, "cube_luminance_alpha",	"",	GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE, MIPMAPS, 64, 64));
1756		copyTexSubImageGroup->addChild(new BasicCopyTexSubImageCubeCase	(m_context, "cube_rgb",				"",	GL_RGB,				GL_UNSIGNED_BYTE, MIPMAPS, 64, 64));
1757		copyTexSubImageGroup->addChild(new BasicCopyTexSubImageCubeCase	(m_context, "cube_rgba",			"",	GL_RGBA,			GL_UNSIGNED_BYTE, MIPMAPS, 64, 64));
1758	}
1759}
1760
1761} // Functional
1762} // gles2
1763} // deqp
1764