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 Vertex texture tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es2fVertexTextureTests.hpp"
25#include "glsTextureTestUtil.hpp"
26#include "gluTexture.hpp"
27#include "gluPixelTransfer.hpp"
28#include "gluTextureUtil.hpp"
29#include "tcuVector.hpp"
30#include "tcuMatrix.hpp"
31#include "tcuTextureUtil.hpp"
32#include "tcuImageCompare.hpp"
33#include "deRandom.hpp"
34#include "deString.h"
35
36#include <string>
37#include <vector>
38
39#include <limits>
40
41#include "glw.h"
42
43using tcu::TestLog;
44using tcu::Vec2;
45using tcu::Vec3;
46using tcu::Vec4;
47using tcu::IVec2;
48using tcu::IVec3;
49using tcu::IVec4;
50using tcu::Mat3;
51using std::string;
52using std::vector;
53
54namespace deqp
55{
56
57using namespace gls::TextureTestUtil;
58
59using gls::TextureTestUtil::TEXTURETYPE_2D;
60using gls::TextureTestUtil::TEXTURETYPE_CUBE;
61
62namespace gles2
63{
64namespace Functional
65{
66
67// The 2D case draws four images.
68static const int MAX_2D_RENDER_WIDTH		= 128*2;
69static const int MAX_2D_RENDER_HEIGHT		= 128*2;
70
71// The cube map case draws four 3-by-2 image groups.
72static const int MAX_CUBE_RENDER_WIDTH		= 28*2*3;
73static const int MAX_CUBE_RENDER_HEIGHT		= 28*2*2;
74
75static const int GRID_SIZE_2D				= 127;
76static const int GRID_SIZE_CUBE				= 63;
77
78// Helpers for making texture coordinates "safe", i.e. move them further from coordinate bounary.
79
80// Moves x towards the closest K+targetFraction, where K is an integer.
81// E.g. moveTowardsFraction(x, 0.5f) moves x away from integer boundaries.
82static inline float moveTowardsFraction (float x, float targetFraction)
83{
84	const float strictness = 0.5f;
85	DE_ASSERT(0.0f < strictness && strictness <= 1.0f);
86	DE_ASSERT(de::inBounds(targetFraction, 0.0f, 1.0f));
87	const float y = x + 0.5f - targetFraction;
88	return deFloatFloor(y) + deFloatFrac(y)*(1.0f-strictness) + strictness*0.5f - 0.5f + targetFraction;
89}
90
91static inline float safeCoord (float raw, int scale, float fraction)
92{
93	const float scaleFloat = (float)scale;
94	return moveTowardsFraction(raw*scaleFloat, fraction) / scaleFloat;
95}
96
97template <int Size>
98static inline tcu::Vector<float, Size> safeCoords (const tcu::Vector<float, Size>& raw, const tcu::Vector<int, Size>& scale, const tcu::Vector<float, Size>& fraction)
99{
100	tcu::Vector<float, Size> result;
101	for (int i = 0; i < Size; i++)
102		result[i] = safeCoord(raw[i], scale[i], fraction[i]);
103	return result;
104}
105
106static inline Vec2 safe2DTexCoords (const Vec2& raw, const IVec2& textureSize)
107{
108	return safeCoords(raw, textureSize, Vec2(0.5f));
109}
110
111namespace
112{
113
114struct Rect
115{
116			Rect	(int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {}
117	IVec2	pos		(void) const { return IVec2(x, y); }
118	IVec2	size	(void) const { return IVec2(w, h); }
119
120	int		x;
121	int		y;
122	int		w;
123	int		h;
124};
125
126template <TextureType> struct TexTypeTcuClass;
127template <> struct TexTypeTcuClass<TEXTURETYPE_2D>			{ typedef tcu::Texture2D		t; };
128template <> struct TexTypeTcuClass<TEXTURETYPE_CUBE>		{ typedef tcu::TextureCube		t; };
129
130template <TextureType> struct TexTypeSizeDims;
131template <> struct TexTypeSizeDims<TEXTURETYPE_2D>			{ enum { V = 2 }; };
132template <> struct TexTypeSizeDims<TEXTURETYPE_CUBE>		{ enum { V = 2 }; };
133
134template <TextureType> struct TexTypeCoordDims;
135template <> struct TexTypeCoordDims<TEXTURETYPE_2D>			{ enum { V = 2 }; };
136template <> struct TexTypeCoordDims<TEXTURETYPE_CUBE>		{ enum { V = 3 }; };
137
138template <TextureType TexType> struct TexTypeSizeIVec		{ typedef tcu::Vector<int,		TexTypeSizeDims<TexType>::V>	t; };
139template <TextureType TexType> struct TexTypeCoordVec		{ typedef tcu::Vector<float,	TexTypeCoordDims<TexType>::V>	t; };
140
141template <TextureType> struct TexTypeCoordParams;
142
143template <> struct
144TexTypeCoordParams<TEXTURETYPE_2D>
145{
146	Vec2 scale;
147	Vec2 bias;
148
149	TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_) : scale(scale_), bias(bias_) {}
150};
151
152template <> struct
153TexTypeCoordParams<TEXTURETYPE_CUBE>
154{
155	Vec2			scale;
156	Vec2			bias;
157	tcu::CubeFace	face;
158
159	TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_, tcu::CubeFace face_) : scale(scale_), bias(bias_), face(face_) {}
160};
161
162/*--------------------------------------------------------------------*//*!
163 * \brief Quad grid class containing position and texture coordinate data.
164 *
165 * A quad grid of size S means a grid consisting of S*S quads (S rows and
166 * S columns). The quads are rectangles with main axis aligned sides, and
167 * each consists of two triangles. Note that although there are only
168 * (S+1)*(S+1) distinct vertex positions, there are S*S*4 distinct vertices
169 * because we want texture coordinates to be constant across the vertices
170 * of a quad (to avoid interpolation issues), and thus each quad needs its
171 * own 4 vertices.
172 *
173 * Pointers returned by get*Ptr() are suitable for gl calls such as
174 * glVertexAttribPointer() (for position and tex coord) or glDrawElements()
175 * (for indices).
176 *//*--------------------------------------------------------------------*/
177template <TextureType TexType>
178class PosTexCoordQuadGrid
179{
180private:
181	enum { TEX_COORD_DIMS = TexTypeCoordDims <TexType>::V };
182	typedef typename TexTypeCoordVec<TexType>::t	TexCoordVec;
183	typedef typename TexTypeSizeIVec<TexType>::t	TexSizeIVec;
184	typedef TexTypeCoordParams<TexType>				TexCoordParams;
185
186public:
187							PosTexCoordQuadGrid		(int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords);
188
189	int						getSize					(void) const { return m_gridSize; }
190	Vec4					getQuadLDRU				(int col, int row) const; //!< Vec4(leftX, downY, rightX, upY)
191	const TexCoordVec&		getQuadTexCoord			(int col, int row) const;
192
193	int						getNumIndices			(void) const { return m_gridSize*m_gridSize*3*2; }
194	const float*			getPositionPtr			(void) const { DE_STATIC_ASSERT(sizeof(Vec2) == 2*sizeof(float)); return (float*)&m_positions[0]; }
195	const float*			getTexCoordPtr			(void) const { DE_STATIC_ASSERT(sizeof(TexCoordVec) == TEX_COORD_DIMS*(int)sizeof(float)); return (float*)&m_texCoords[0]; }
196	const deUint16*			getIndexPtr				(void) const { return &m_indices[0]; }
197
198private:
199	void					initializeTexCoords		(const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords);
200
201	const int				m_gridSize;
202	vector<Vec2>			m_positions;
203	vector<TexCoordVec>		m_texCoords;
204	vector<deUint16>		m_indices;
205};
206
207template <TextureType TexType>
208Vec4 PosTexCoordQuadGrid<TexType>::getQuadLDRU (int col, int row) const
209{
210	int ndx00 = (row*m_gridSize + col) * 4;
211	int ndx11 = ndx00 + 3;
212
213	return Vec4(m_positions[ndx00].x(),
214				m_positions[ndx00].y(),
215				m_positions[ndx11].x(),
216				m_positions[ndx11].y());
217}
218
219template <TextureType TexType>
220const typename TexTypeCoordVec<TexType>::t& PosTexCoordQuadGrid<TexType>::getQuadTexCoord (int col, int row) const
221{
222	return m_texCoords[(row*m_gridSize + col) * 4];
223}
224
225template <TextureType TexType>
226PosTexCoordQuadGrid<TexType>::PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
227	: m_gridSize(gridSize)
228{
229	DE_ASSERT(m_gridSize > 0 && m_gridSize*m_gridSize <= (int)std::numeric_limits<deUint16>::max() + 1);
230
231	const float gridSizeFloat = (float)m_gridSize;
232
233	m_positions.reserve(m_gridSize*m_gridSize*4);
234	m_indices.reserve(m_gridSize*m_gridSize*3*2);
235
236	for (int y = 0; y < m_gridSize; y++)
237	for (int x = 0; x < m_gridSize; x++)
238	{
239		float fx0 = (float)(x+0) / gridSizeFloat;
240		float fx1 = (float)(x+1) / gridSizeFloat;
241		float fy0 = (float)(y+0) / gridSizeFloat;
242		float fy1 = (float)(y+1) / gridSizeFloat;
243
244		Vec2 quadVertices[4] = { Vec2(fx0, fy0), Vec2(fx1, fy0), Vec2(fx0, fy1), Vec2(fx1, fy1) };
245
246		int firstNdx = (int)m_positions.size();
247
248		for (int i = 0; i < DE_LENGTH_OF_ARRAY(quadVertices); i++)
249			m_positions.push_back(safeCoords(quadVertices[i], renderSize, Vec2(0.0f)) * 2.0f - 1.0f);
250
251		m_indices.push_back(firstNdx + 0);
252		m_indices.push_back(firstNdx + 1);
253		m_indices.push_back(firstNdx + 2);
254
255		m_indices.push_back(firstNdx + 1);
256		m_indices.push_back(firstNdx + 3);
257		m_indices.push_back(firstNdx + 2);
258	}
259
260	m_texCoords.reserve(m_gridSize*m_gridSize*4);
261	initializeTexCoords(textureSize, texCoordParams, useSafeTexCoords);
262
263	DE_ASSERT((int)m_positions.size() == m_gridSize*m_gridSize*4);
264	DE_ASSERT((int)m_indices.size() == m_gridSize*m_gridSize*3*2);
265	DE_ASSERT((int)m_texCoords.size() == m_gridSize*m_gridSize*4);
266}
267
268template <>
269void PosTexCoordQuadGrid<TEXTURETYPE_2D>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
270{
271	DE_ASSERT(m_texCoords.empty());
272
273	const float gridSizeFloat = (float)m_gridSize;
274
275	for (int y = 0; y < m_gridSize; y++)
276	for (int x = 0; x < m_gridSize; x++)
277	{
278		Vec2 rawCoord = Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) * texCoordParams.scale + texCoordParams.bias;
279
280		for (int i = 0; i < 4; i++)
281			m_texCoords.push_back(useSafeTexCoords ? safe2DTexCoords(rawCoord, textureSize) : rawCoord);
282	}
283}
284
285template <>
286void PosTexCoordQuadGrid<TEXTURETYPE_CUBE>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
287{
288	DE_ASSERT(m_texCoords.empty());
289
290	const float		gridSizeFloat	= (float)m_gridSize;
291	vector<float>	texBoundaries;
292	computeQuadTexCoordCube(texBoundaries, texCoordParams.face);
293	const Vec3		coordA			= Vec3(texBoundaries[0], texBoundaries[1], texBoundaries[2]);
294	const Vec3		coordB			= Vec3(texBoundaries[3], texBoundaries[4], texBoundaries[5]);
295	const Vec3		coordC			= Vec3(texBoundaries[6], texBoundaries[7], texBoundaries[8]);
296	const Vec3		coordAB			= coordB - coordA;
297	const Vec3		coordAC			= coordC - coordA;
298
299	for (int y = 0; y < m_gridSize; y++)
300	for (int x = 0; x < m_gridSize; x++)
301	{
302		const Vec2 rawFaceCoord		= texCoordParams.scale * Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) + texCoordParams.bias;
303		const Vec2 safeFaceCoord	= useSafeTexCoords ? safe2DTexCoords(rawFaceCoord, textureSize) : rawFaceCoord;
304		const Vec3 texCoord			= coordA + coordAC*safeFaceCoord.x() + coordAB*safeFaceCoord.y();
305
306		for (int i = 0; i < 4; i++)
307			m_texCoords.push_back(texCoord);
308	}
309}
310
311} // anonymous
312
313static inline bool isLevelNearest (deUint32 filter)
314{
315	return filter == GL_NEAREST || filter == GL_NEAREST_MIPMAP_NEAREST || filter == GL_NEAREST_MIPMAP_LINEAR;
316}
317
318static inline IVec2 getTextureSize (const glu::Texture2D& tex)
319{
320	const tcu::Texture2D& ref = tex.getRefTexture();
321	return IVec2(ref.getWidth(), ref.getHeight());
322}
323
324static inline IVec2 getTextureSize (const glu::TextureCube& tex)
325{
326	const tcu::TextureCube& ref = tex.getRefTexture();
327	return IVec2(ref.getSize(), ref.getSize());
328}
329
330template <TextureType TexType>
331static void setPixelColors (const vector<Vec4>& quadColors, const Rect& region, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst)
332{
333	const int gridSize = grid.getSize();
334
335	for (int y = 0; y < gridSize; y++)
336	for (int x = 0; x < gridSize; x++)
337	{
338		const Vec4	color	= quadColors[y*gridSize + x];
339		const Vec4	ldru	= grid.getQuadLDRU(x, y) * 0.5f + 0.5f; // [-1, 1] -> [0, 1]
340		const int	ix0		= deCeilFloatToInt32(ldru.x() * (float)region.w - 0.5f);
341		const int	ix1		= deCeilFloatToInt32(ldru.z() * (float)region.w - 0.5f);
342		const int	iy0		= deCeilFloatToInt32(ldru.y() * (float)region.h - 0.5f);
343		const int	iy1		= deCeilFloatToInt32(ldru.w() * (float)region.h - 0.5f);
344
345		for (int iy = iy0; iy < iy1; iy++)
346		for (int ix = ix0; ix < ix1; ix++)
347		{
348			DE_ASSERT(deInBounds32(ix + region.x, 0, dst.getWidth()));
349			DE_ASSERT(deInBounds32(iy + region.y, 0, dst.getHeight()));
350
351			dst.setPixel(ix + region.x, iy + region.y, toRGBA(color));
352		}
353	}
354}
355
356static inline Vec4 sample (const tcu::Texture2D&		tex, const Vec2& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), lod); }
357static inline Vec4 sample (const tcu::TextureCube&		tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); }
358
359template <TextureType TexType>
360void computeReference (const typename TexTypeTcuClass<TexType>::t& texture, float lod, const tcu::Sampler& sampler, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst, const Rect& dstRegion)
361{
362	const int		gridSize	= grid.getSize();
363	vector<Vec4>	quadColors	(gridSize*gridSize);
364
365	for (int y = 0; y < gridSize; y++)
366	for (int x = 0; x < gridSize; x++)
367	{
368		const int										ndx		= y*gridSize + x;
369		const typename TexTypeCoordVec<TexType>::t&		coord	= grid.getQuadTexCoord(x, y);
370
371		quadColors[ndx] = sample(texture, coord, lod, sampler);
372	}
373
374	setPixelColors(quadColors, dstRegion, grid, dst);
375}
376
377static bool compareImages (const glu::RenderContext& renderCtx, tcu::TestLog& log, const tcu::Surface& ref, const tcu::Surface& res)
378{
379	DE_ASSERT(renderCtx.getRenderTarget().getNumSamples() == 0);
380
381	const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(15,15,15,15);
382	return tcu::pixelThresholdCompare(log, "Result", "Image compare result", ref, res, threshold, tcu::COMPARE_LOG_RESULT);
383}
384
385class Vertex2DTextureCase : public TestCase
386{
387public:
388								Vertex2DTextureCase		(Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
389								~Vertex2DTextureCase	(void);
390
391	void						init					(void);
392	void						deinit					(void);
393	IterateResult				iterate					(void);
394
395private:
396	typedef PosTexCoordQuadGrid<TEXTURETYPE_2D> Grid;
397
398								Vertex2DTextureCase		(const Vertex2DTextureCase& other);
399	Vertex2DTextureCase&		operator=				(const Vertex2DTextureCase& other);
400
401	float						calculateLod			(const Vec2& texScale, const Vec2& dstSize, int textureNdx) const;
402	void						setupShaderInputs		(int textureNdx, float lod, const Grid& grid) const;
403	void						renderCell				(int textureNdx, float lod, const Grid& grid) const;
404	void						computeReferenceCell	(int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
405
406	const deUint32				m_minFilter;
407	const deUint32				m_magFilter;
408	const deUint32				m_wrapS;
409	const deUint32				m_wrapT;
410
411	const glu::ShaderProgram*	m_program;
412	glu::Texture2D*				m_textures[2];	// 2 textures, a gradient texture and a grid texture.
413};
414
415Vertex2DTextureCase::Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
416	: TestCase				(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
417	, m_minFilter			(minFilter)
418	, m_magFilter			(magFilter)
419	, m_wrapS				(wrapS)
420	, m_wrapT				(wrapT)
421	, m_program				(DE_NULL)
422{
423	m_textures[0] = DE_NULL;
424	m_textures[1] = DE_NULL;
425}
426
427Vertex2DTextureCase::~Vertex2DTextureCase(void)
428{
429	Vertex2DTextureCase::deinit();
430}
431
432void Vertex2DTextureCase::init (void)
433{
434	const char* const vertexShader =
435		"attribute highp vec2 a_position;\n"
436		"attribute highp vec2 a_texCoord;\n"
437		"uniform highp sampler2D u_texture;\n"
438		"uniform highp float u_lod;\n"
439		"varying mediump vec4 v_color;\n"
440		"\n"
441		"void main()\n"
442		"{\n"
443		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
444		"	v_color = texture2DLod(u_texture, a_texCoord, u_lod);\n"
445		"}\n";
446
447	const char* const fragmentShader =
448		"varying mediump vec4 v_color;\n"
449		"\n"
450		"void main()\n"
451		"{\n"
452		"	gl_FragColor = v_color;\n"
453		"}\n";
454
455	if (m_context.getRenderTarget().getNumSamples() != 0)
456		throw tcu::NotSupportedError("MSAA config not supported by this test");
457
458	DE_ASSERT(!m_program);
459	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
460
461	if(!m_program->isOk())
462	{
463		m_testCtx.getLog() << *m_program;
464
465		GLint maxVertexTextures;
466		glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
467
468		if (maxVertexTextures < 1)
469			throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
470		else
471			TCU_FAIL("Failed to compile shader");
472	}
473
474	// Make the textures.
475	try
476	{
477		// Compute suitable power-of-two sizes (for mipmaps).
478		const int texWidth		= 1 << deLog2Ceil32(MAX_2D_RENDER_WIDTH / 2);
479		const int texHeight		= 1 << deLog2Ceil32(MAX_2D_RENDER_HEIGHT / 2);
480
481		for (int i = 0; i < 2; i++)
482		{
483			DE_ASSERT(!m_textures[i]);
484			m_textures[i] = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
485		}
486
487		const bool						mipmaps		= (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight));
488		const int						numLevels	= mipmaps ? deLog2Floor32(de::max(texWidth, texHeight))+1 : 1;
489		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
490		const Vec4						cBias		= fmtInfo.valueMin;
491		const Vec4						cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
492
493		// Fill first with gradient texture.
494		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
495		{
496			const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
497			const Vec4 gMax = Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
498
499			m_textures[0]->getRefTexture().allocLevel(levelNdx);
500			tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
501		}
502
503		// Fill second with grid texture.
504		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
505		{
506			const deUint32 step		= 0x00ffffff / numLevels;
507			const deUint32 rgb		= step*levelNdx;
508			const deUint32 colorA	= 0xff000000 | rgb;
509			const deUint32 colorB	= 0xff000000 | ~rgb;
510
511			m_textures[1]->getRefTexture().allocLevel(levelNdx);
512			tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
513		}
514
515		// Upload.
516		for (int i = 0; i < 2; i++)
517			m_textures[i]->upload();
518	}
519	catch (const std::exception&)
520	{
521		// Clean up to save memory.
522		Vertex2DTextureCase::deinit();
523		throw;
524	}
525}
526
527void Vertex2DTextureCase::deinit (void)
528{
529	for (int i = 0; i < 2; i++)
530	{
531		delete m_textures[i];
532		m_textures[i] = DE_NULL;
533	}
534
535	delete m_program;
536	m_program = DE_NULL;
537}
538
539float Vertex2DTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
540{
541	const tcu::Texture2D&		refTexture	= m_textures[textureNdx]->getRefTexture();
542	const Vec2					srcSize		= Vec2((float)refTexture.getWidth(), (float)refTexture.getHeight());
543	const Vec2					sizeRatio	= texScale*srcSize / dstSize;
544
545	// \note In this particular case dv/dx and du/dy are zero, simplifying the expression.
546	return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
547}
548
549Vertex2DTextureCase::IterateResult Vertex2DTextureCase::iterate (void)
550{
551	const int	viewportWidth		= deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_RENDER_WIDTH);
552	const int	viewportHeight		= deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_RENDER_HEIGHT);
553
554	const int	viewportXOffsetMax	= m_context.getRenderTarget().getWidth() - viewportWidth;
555	const int	viewportYOffsetMax	= m_context.getRenderTarget().getHeight() - viewportHeight;
556
557	de::Random	rnd					(deStringHash(getName()));
558
559	const int	viewportXOffset		= rnd.getInt(0, viewportXOffsetMax);
560	const int	viewportYOffset		= rnd.getInt(0, viewportYOffsetMax);
561
562	glUseProgram(m_program->getProgram());
563
564	// Divide viewport into 4 cells.
565	const int leftWidth		= viewportWidth / 2;
566	const int rightWidth	= viewportWidth - leftWidth;
567	const int bottomHeight	= viewportHeight / 2;
568	const int topHeight		= viewportHeight - bottomHeight;
569
570	// Clear.
571	glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
572	glClear(GL_COLOR_BUFFER_BIT);
573
574	// Texture scaling and offsetting vectors.
575	const Vec2 texMinScale		(+1.8f, +1.8f);
576	const Vec2 texMinOffset		(-0.3f, -0.2f);
577	const Vec2 texMagScale		(+0.3f, +0.3f);
578	const Vec2 texMagOffset		(+0.9f, +0.8f);
579
580	// Surface for the reference image.
581	tcu::Surface refImage(viewportWidth, viewportHeight);
582
583	{
584		const struct Render
585		{
586			const Rect	region;
587			int			textureNdx;
588			const Vec2	texCoordScale;
589			const Vec2	texCoordOffset;
590			Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
591		} renders[] =
592		{
593			Render(Rect(0,				0,				leftWidth,	bottomHeight),	0, texMinScale, texMinOffset),
594			Render(Rect(leftWidth,		0,				rightWidth,	bottomHeight),	0, texMagScale, texMagOffset),
595			Render(Rect(0,				bottomHeight,	leftWidth,	topHeight),		1, texMinScale, texMinOffset),
596			Render(Rect(leftWidth,		bottomHeight,	rightWidth,	topHeight),		1, texMagScale, texMagOffset)
597		};
598
599		for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
600		{
601			const Render&	rend				= renders[renderNdx];
602			const float		lod					= calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
603			const bool		useSafeTexCoords	= isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
604			const Grid		grid				(GRID_SIZE_2D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
605												 TexTypeCoordParams<TEXTURETYPE_2D>(rend.texCoordScale, rend.texCoordOffset), useSafeTexCoords);
606
607			glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
608			renderCell				(rend.textureNdx, lod, grid);
609			computeReferenceCell	(rend.textureNdx, lod, grid, refImage, rend.region);
610		}
611	}
612
613	// Read back rendered results.
614	tcu::Surface resImage(viewportWidth, viewportHeight);
615	glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
616
617	glUseProgram(0);
618
619	// Compare and log.
620	{
621		const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
622
623		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
624								isOk ? "Pass"				: "Image comparison failed");
625	}
626
627	return STOP;
628}
629
630void Vertex2DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
631{
632	const deUint32 programID = m_program->getProgram();
633
634	// SETUP ATTRIBUTES.
635
636	{
637		const int positionLoc = glGetAttribLocation(programID, "a_position");
638		if (positionLoc != -1)
639		{
640			glEnableVertexAttribArray(positionLoc);
641			glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
642		}
643	}
644
645	{
646		const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
647		if (texCoordLoc != -1)
648		{
649			glEnableVertexAttribArray(texCoordLoc);
650			glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
651		}
652	}
653
654	// SETUP UNIFORMS.
655
656	{
657		const int lodLoc = glGetUniformLocation(programID, "u_lod");
658		if (lodLoc != -1)
659			glUniform1f(lodLoc, lod);
660	}
661
662	glActiveTexture(GL_TEXTURE0);
663	glBindTexture(GL_TEXTURE_2D, m_textures[textureNdx]->getGLTexture());
664	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		m_wrapS);
665	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		m_wrapT);
666	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
667	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	m_magFilter);
668
669	{
670		const int texLoc = glGetUniformLocation(programID, "u_texture");
671		if (texLoc != -1)
672			glUniform1i(texLoc, 0);
673	}
674}
675
676// Renders one sub-image with given parameters.
677void Vertex2DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
678{
679	setupShaderInputs(textureNdx, lod, grid);
680	glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
681}
682
683void Vertex2DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
684{
685	computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion);
686}
687
688class VertexCubeTextureCase : public TestCase
689{
690public:
691								VertexCubeTextureCase	(Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
692								~VertexCubeTextureCase	(void);
693
694	void						init					(void);
695	void						deinit					(void);
696	IterateResult				iterate					(void);
697
698private:
699	typedef PosTexCoordQuadGrid<TEXTURETYPE_CUBE> Grid;
700
701								VertexCubeTextureCase	(const VertexCubeTextureCase& other);
702	VertexCubeTextureCase&		operator=				(const VertexCubeTextureCase& other);
703
704	float						calculateLod			(const Vec2& texScale, const Vec2& dstSize, int textureNdx) const;
705	void						setupShaderInputs		(int textureNdx, float lod, const Grid& grid) const;
706	void						renderCell				(int textureNdx, float lod, const Grid& grid) const;
707	void						computeReferenceCell	(int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
708
709	const deUint32				m_minFilter;
710	const deUint32				m_magFilter;
711	const deUint32				m_wrapS;
712	const deUint32				m_wrapT;
713
714	const glu::ShaderProgram*	m_program;
715	glu::TextureCube*			m_textures[2];	// 2 textures, a gradient texture and a grid texture.
716};
717
718VertexCubeTextureCase::VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
719	: TestCase				(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
720	, m_minFilter			(minFilter)
721	, m_magFilter			(magFilter)
722	, m_wrapS				(wrapS)
723	, m_wrapT				(wrapT)
724	, m_program				(DE_NULL)
725{
726	m_textures[0] = DE_NULL;
727	m_textures[1] = DE_NULL;
728}
729
730VertexCubeTextureCase::~VertexCubeTextureCase(void)
731{
732	VertexCubeTextureCase::deinit();
733}
734
735void VertexCubeTextureCase::init (void)
736{
737	const char* const vertexShader =
738		"attribute highp vec2 a_position;\n"
739		"attribute highp vec3 a_texCoord;\n"
740		"uniform highp samplerCube u_texture;\n"
741		"uniform highp float u_lod;\n"
742		"varying mediump vec4 v_color;\n"
743		"\n"
744		"void main()\n"
745		"{\n"
746		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
747		"	v_color = textureCubeLod(u_texture, a_texCoord, u_lod);\n"
748		"}\n";
749
750	const char* const fragmentShader =
751		"varying mediump vec4 v_color;\n"
752		"\n"
753		"void main()\n"
754		"{\n"
755		"	gl_FragColor = v_color;\n"
756		"}\n";
757
758	if (m_context.getRenderTarget().getNumSamples() != 0)
759		throw tcu::NotSupportedError("MSAA config not supported by this test");
760
761	DE_ASSERT(!m_program);
762	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
763
764	if(!m_program->isOk())
765	{
766		m_testCtx.getLog() << *m_program;
767
768		GLint maxVertexTextures;
769		glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
770
771		if (maxVertexTextures < 1)
772			throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
773		else
774			TCU_FAIL("Failed to compile shader");
775	}
776
777	// Make the textures.
778	try
779	{
780		// Compute suitable power-of-two sizes (for mipmaps).
781		const int texWidth		= 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2);
782		const int texHeight		= 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2);
783
784		DE_ASSERT(texWidth == texHeight);
785		DE_UNREF(texHeight);
786
787		for (int i = 0; i < 2; i++)
788		{
789			DE_ASSERT(!m_textures[i]);
790			m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth);
791		}
792
793		const bool						mipmaps		= deIsPowerOfTwo32(texWidth) != DE_FALSE;
794		const int						numLevels	= mipmaps ? deLog2Floor32(texWidth)+1 : 1;
795		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
796		const Vec4						cBias		= fmtInfo.valueMin;
797		const Vec4						cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
798
799		// Fill first with gradient texture.
800		static const Vec4 gradients[tcu::CUBEFACE_LAST][2] =
801		{
802			{ Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
803			{ Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
804			{ Vec4(-1.0f,  0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
805			{ Vec4(-1.0f, -1.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
806			{ Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
807			{ Vec4( 0.0f,  0.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
808		};
809		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
810		{
811			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
812			{
813				m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
814				tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
815			}
816		}
817
818		// Fill second with grid texture.
819		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
820		{
821			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
822			{
823				const deUint32 step		= 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
824				const deUint32 rgb		= step*levelNdx*face;
825				const deUint32 colorA	= 0xff000000 | rgb;
826				const deUint32 colorB	= 0xff000000 | ~rgb;
827
828				m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
829				tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
830			}
831		}
832
833		// Upload.
834		for (int i = 0; i < 2; i++)
835			m_textures[i]->upload();
836	}
837	catch (const std::exception&)
838	{
839		// Clean up to save memory.
840		VertexCubeTextureCase::deinit();
841		throw;
842	}
843}
844
845void VertexCubeTextureCase::deinit (void)
846{
847	for (int i = 0; i < 2; i++)
848	{
849		delete m_textures[i];
850		m_textures[i] = DE_NULL;
851	}
852
853	delete m_program;
854	m_program = DE_NULL;
855}
856
857float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
858{
859	const tcu::TextureCube&		refTexture	= m_textures[textureNdx]->getRefTexture();
860	const Vec2					srcSize		= Vec2((float)refTexture.getSize(), (float)refTexture.getSize());
861	const Vec2					sizeRatio	= texScale*srcSize / dstSize;
862
863	// \note In this particular case, dv/dx and du/dy are zero, simplifying the expression.
864	return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
865}
866
867VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void)
868{
869	const int	viewportWidth		= deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH);
870	const int	viewportHeight		= deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT);
871
872	const int	viewportXOffsetMax	= m_context.getRenderTarget().getWidth() - viewportWidth;
873	const int	viewportYOffsetMax	= m_context.getRenderTarget().getHeight() - viewportHeight;
874
875	de::Random	rnd					(deStringHash(getName()));
876
877	const int	viewportXOffset		= rnd.getInt(0, viewportXOffsetMax);
878	const int	viewportYOffset		= rnd.getInt(0, viewportYOffsetMax);
879
880	glUseProgram(m_program->getProgram());
881
882	// Divide viewport into 4 areas.
883	const int leftWidth		= viewportWidth / 2;
884	const int rightWidth	= viewportWidth - leftWidth;
885	const int bottomHeight	= viewportHeight / 2;
886	const int topHeight		= viewportHeight - bottomHeight;
887
888	// Clear.
889	glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
890	glClear(GL_COLOR_BUFFER_BIT);
891
892	// Texture scaling and offsetting vectors.
893	const Vec2 texMinScale		(1.0f, 1.0f);
894	const Vec2 texMinOffset		(0.0f, 0.0f);
895	const Vec2 texMagScale		(0.3f, 0.3f);
896	const Vec2 texMagOffset		(0.5f, 0.3f);
897
898	// Surface for the reference image.
899	tcu::Surface refImage(viewportWidth, viewportHeight);
900
901	// Each of the four areas is divided into 6 cells.
902	const int defCellWidth	= viewportWidth / 2 / 3;
903	const int defCellHeight	= viewportHeight / 2 / 2;
904
905	for (int i = 0; i < tcu::CUBEFACE_LAST; i++)
906	{
907		const int	cellOffsetX			= defCellWidth * (i % 3);
908		const int	cellOffsetY			= defCellHeight * (i / 3);
909		const bool	isRightmostCell		= i == 2 || i == 5;
910		const bool	isTopCell			= i >= 3;
911		const int	leftCellWidth		= isRightmostCell	? leftWidth		- cellOffsetX : defCellWidth;
912		const int	rightCellWidth		= isRightmostCell	? rightWidth	- cellOffsetX : defCellWidth;
913		const int	bottomCellHeight	= isTopCell			? bottomHeight	- cellOffsetY : defCellHeight;
914		const int	topCellHeight		= isTopCell			? topHeight		- cellOffsetY : defCellHeight;
915
916		const struct Render
917		{
918			const Rect	region;
919			int			textureNdx;
920			const Vec2	texCoordScale;
921			const Vec2	texCoordOffset;
922			Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
923		} renders[] =
924		{
925			Render(Rect(cellOffsetX + 0,			cellOffsetY + 0,				leftCellWidth,	bottomCellHeight),	0, texMinScale, texMinOffset),
926			Render(Rect(cellOffsetX + leftWidth,	cellOffsetY + 0,				rightCellWidth,	bottomCellHeight),	0, texMagScale, texMagOffset),
927			Render(Rect(cellOffsetX + 0,			cellOffsetY + bottomHeight,		leftCellWidth,	topCellHeight),		1, texMinScale, texMinOffset),
928			Render(Rect(cellOffsetX + leftWidth,	cellOffsetY + bottomHeight,		rightCellWidth,	topCellHeight),		1, texMagScale, texMagOffset)
929		};
930
931		for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
932		{
933			const Render&	rend				= renders[renderNdx];
934			const float		lod					= calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
935			const bool		useSafeTexCoords	= isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
936			const Grid		grid				(GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
937												 TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords);
938
939			glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
940			renderCell				(rend.textureNdx, lod, grid);
941			computeReferenceCell	(rend.textureNdx, lod, grid, refImage, rend.region);
942		}
943	}
944
945	// Read back rendered results.
946	tcu::Surface resImage(viewportWidth, viewportHeight);
947	glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
948
949	glUseProgram(0);
950
951	// Compare and log.
952	{
953		const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
954
955		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
956								isOk ? "Pass"				: "Image comparison failed");
957	}
958
959	return STOP;
960}
961
962void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
963{
964	const deUint32 programID = m_program->getProgram();
965
966	// SETUP ATTRIBUTES.
967
968	{
969		const int positionLoc = glGetAttribLocation(programID, "a_position");
970		if (positionLoc != -1)
971		{
972			glEnableVertexAttribArray(positionLoc);
973			glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
974		}
975	}
976
977	{
978		const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
979		if (texCoordLoc != -1)
980		{
981			glEnableVertexAttribArray(texCoordLoc);
982			glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
983		}
984	}
985
986	// SETUP UNIFORMS.
987
988	{
989		const int lodLoc = glGetUniformLocation(programID, "u_lod");
990		if (lodLoc != -1)
991			glUniform1f(lodLoc, lod);
992	}
993
994	glActiveTexture(GL_TEXTURE0);
995	glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture());
996	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
997	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
998	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
999	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	m_magFilter);
1000
1001	{
1002		const int texLoc = glGetUniformLocation(programID, "u_texture");
1003		if (texLoc != -1)
1004			glUniform1i(texLoc, 0);
1005	}
1006}
1007
1008// Renders one cube face with given parameters.
1009void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1010{
1011	setupShaderInputs(textureNdx, lod, grid);
1012	glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1013}
1014
1015// Computes reference for one cube face with given parameters.
1016void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1017{
1018	tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
1019	computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion);
1020}
1021
1022VertexTextureTests::VertexTextureTests (Context& context)
1023	: TestCaseGroup(context, "vertex", "Vertex Texture Tests")
1024{
1025}
1026
1027VertexTextureTests::~VertexTextureTests(void)
1028{
1029}
1030
1031void VertexTextureTests::init (void)
1032{
1033	// 2D and cube map groups, and their filtering and wrap sub-groups.
1034	TestCaseGroup* const group2D				= new TestCaseGroup(m_context, "2d",			"2D Vertex Texture Tests");
1035	TestCaseGroup* const groupCube				= new TestCaseGroup(m_context, "cube",			"Cube Map Vertex Texture Tests");
1036	TestCaseGroup* const filteringGroup2D		= new TestCaseGroup(m_context, "filtering",		"2D Vertex Texture Filtering Tests");
1037	TestCaseGroup* const wrapGroup2D			= new TestCaseGroup(m_context, "wrap",			"2D Vertex Texture Wrap Tests");
1038	TestCaseGroup* const filteringGroupCube		= new TestCaseGroup(m_context, "filtering",		"Cube Map Vertex Texture Filtering Tests");
1039	TestCaseGroup* const wrapGroupCube			= new TestCaseGroup(m_context, "wrap",			"Cube Map Vertex Texture Wrap Tests");
1040
1041	group2D->addChild(filteringGroup2D);
1042	group2D->addChild(wrapGroup2D);
1043	groupCube->addChild(filteringGroupCube);
1044	groupCube->addChild(wrapGroupCube);
1045
1046	addChild(group2D);
1047	addChild(groupCube);
1048
1049	static const struct
1050	{
1051		const char*		name;
1052		GLenum			mode;
1053	} wrapModes[] =
1054	{
1055		{ "clamp",		GL_CLAMP_TO_EDGE	},
1056		{ "repeat",		GL_REPEAT			},
1057		{ "mirror",		GL_MIRRORED_REPEAT	}
1058	};
1059
1060	static const struct
1061	{
1062		const char*		name;
1063		GLenum			mode;
1064	} minFilterModes[] =
1065	{
1066		{ "nearest",				GL_NEAREST					},
1067		{ "linear",					GL_LINEAR					},
1068		{ "nearest_mipmap_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1069		{ "linear_mipmap_nearest",	GL_LINEAR_MIPMAP_NEAREST	},
1070		{ "nearest_mipmap_linear",	GL_NEAREST_MIPMAP_LINEAR	},
1071		{ "linear_mipmap_linear",	GL_LINEAR_MIPMAP_LINEAR		}
1072	};
1073
1074	static const struct
1075	{
1076		const char*		name;
1077		GLenum			mode;
1078	} magFilterModes[] =
1079	{
1080		{ "nearest",	GL_NEAREST	},
1081		{ "linear",		GL_LINEAR	}
1082	};
1083
1084#define FOR_EACH(ITERATOR, ARRAY, BODY)	\
1085	for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++)	\
1086		BODY
1087
1088	// 2D cases.
1089
1090	FOR_EACH(minFilter,		minFilterModes,
1091	FOR_EACH(magFilter,		magFilterModes,
1092	FOR_EACH(wrapMode,		wrapModes,
1093		{
1094			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1095
1096			filteringGroup2D->addChild(new Vertex2DTextureCase(m_context,
1097															   name.c_str(), "",
1098															   minFilterModes[minFilter].mode,
1099															   magFilterModes[magFilter].mode,
1100															   wrapModes[wrapMode].mode,
1101															   wrapModes[wrapMode].mode));
1102		})));
1103
1104	FOR_EACH(wrapSMode,		wrapModes,
1105	FOR_EACH(wrapTMode,		wrapModes,
1106		{
1107			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1108
1109			wrapGroup2D->addChild(new Vertex2DTextureCase(m_context,
1110														  name.c_str(), "",
1111														  GL_LINEAR_MIPMAP_LINEAR,
1112														  GL_LINEAR,
1113														  wrapModes[wrapSMode].mode,
1114														  wrapModes[wrapTMode].mode));
1115		}));
1116
1117	// Cube map cases.
1118
1119	FOR_EACH(minFilter,		minFilterModes,
1120	FOR_EACH(magFilter,		magFilterModes,
1121	FOR_EACH(wrapMode,		wrapModes,
1122		{
1123			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1124
1125			filteringGroupCube->addChild(new VertexCubeTextureCase(m_context,
1126																   name.c_str(), "",
1127																   minFilterModes[minFilter].mode,
1128																   magFilterModes[magFilter].mode,
1129																   wrapModes[wrapMode].mode,
1130																   wrapModes[wrapMode].mode));
1131		})));
1132
1133	FOR_EACH(wrapSMode,		wrapModes,
1134	FOR_EACH(wrapTMode,		wrapModes,
1135		{
1136			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1137
1138			wrapGroupCube->addChild(new VertexCubeTextureCase(m_context,
1139															  name.c_str(), "",
1140															  GL_LINEAR_MIPMAP_LINEAR,
1141															  GL_LINEAR,
1142															  wrapModes[wrapSMode].mode,
1143															  wrapModes[wrapTMode].mode));
1144		}));
1145}
1146
1147} // Functional
1148} // gles2
1149} // deqp
1150