• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.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 "es3fVertexTextureTests.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 "deMath.h"
34 #include "deRandom.hpp"
35 #include "deString.h"
36 
37 #include <string>
38 #include <vector>
39 
40 #include <limits>
41 
42 #include "glw.h"
43 
44 using tcu::TestLog;
45 using tcu::Vec2;
46 using tcu::Vec3;
47 using tcu::Vec4;
48 using tcu::IVec2;
49 using tcu::IVec3;
50 using tcu::IVec4;
51 using tcu::Mat3;
52 using std::string;
53 using std::vector;
54 
55 namespace deqp
56 {
57 
58 using namespace gls::TextureTestUtil;
59 using namespace glu::TextureTestUtil;
60 
61 using glu::TextureTestUtil::TEXTURETYPE_2D;
62 using glu::TextureTestUtil::TEXTURETYPE_CUBE;
63 using glu::TextureTestUtil::TEXTURETYPE_2D_ARRAY;
64 using glu::TextureTestUtil::TEXTURETYPE_3D;
65 
66 namespace gles3
67 {
68 namespace Functional
69 {
70 
71 static const int WIDTH_2D_ARRAY				= 128;
72 static const int HEIGHT_2D_ARRAY			= 128;
73 static const int LAYERS_2D_ARRAY			= 8;
74 
75 static const int WIDTH_3D					= 64;
76 static const int HEIGHT_3D					= 64;
77 static const int DEPTH_3D					= 64;
78 
79 // The 2D case draws four images.
80 static const int MAX_2D_RENDER_WIDTH		= 128*2;
81 static const int MAX_2D_RENDER_HEIGHT		= 128*2;
82 
83 // The cube map case draws four 3-by-2 image groups.
84 static const int MAX_CUBE_RENDER_WIDTH		= 28*2*3;
85 static const int MAX_CUBE_RENDER_HEIGHT		= 28*2*2;
86 
87 static const int MAX_2D_ARRAY_RENDER_WIDTH	= 128*2;
88 static const int MAX_2D_ARRAY_RENDER_HEIGHT	= 128*2;
89 
90 static const int MAX_3D_RENDER_WIDTH		= 128*2;
91 static const int MAX_3D_RENDER_HEIGHT		= 128*2;
92 
93 static const int GRID_SIZE_2D				= 127;
94 static const int GRID_SIZE_CUBE				= 63;
95 static const int GRID_SIZE_2D_ARRAY			= 127;
96 static const int GRID_SIZE_3D				= 127;
97 
98 // Helpers for making texture coordinates "safe", i.e. move them further from coordinate bounary.
99 
100 // Moves x towards the closest K+targetFraction, where K is an integer.
101 // E.g. moveTowardsFraction(x, 0.5f) moves x away from integer boundaries.
moveTowardsFraction(float x,float targetFraction)102 static inline float moveTowardsFraction (float x, float targetFraction)
103 {
104 	const float strictness = 0.5f;
105 	DE_ASSERT(0.0f < strictness && strictness <= 1.0f);
106 	DE_ASSERT(de::inBounds(targetFraction, 0.0f, 1.0f));
107 	const float y = x + 0.5f - targetFraction;
108 	return deFloatFloor(y) + deFloatFrac(y)*(1.0f-strictness) + strictness*0.5f - 0.5f + targetFraction;
109 }
110 
safeCoord(float raw,int scale,float fraction)111 static inline float safeCoord (float raw, int scale, float fraction)
112 {
113 	const float scaleFloat = (float)scale;
114 	return moveTowardsFraction(raw*scaleFloat, fraction) / scaleFloat;
115 }
116 
117 template <int Size>
safeCoords(const tcu::Vector<float,Size> & raw,const tcu::Vector<int,Size> & scale,const tcu::Vector<float,Size> & fraction)118 static inline tcu::Vector<float, Size> safeCoords (const tcu::Vector<float, Size>& raw, const tcu::Vector<int, Size>& scale, const tcu::Vector<float, Size>& fraction)
119 {
120 	tcu::Vector<float, Size> result;
121 	for (int i = 0; i < Size; i++)
122 		result[i] = safeCoord(raw[i], scale[i], fraction[i]);
123 	return result;
124 }
125 
safe2DTexCoords(const Vec2 & raw,const IVec2 & textureSize)126 static inline Vec2 safe2DTexCoords (const Vec2& raw, const IVec2& textureSize)
127 {
128 	return safeCoords(raw, textureSize, Vec2(0.5f));
129 }
130 
safe2DArrayTexCoords(const Vec3 & raw,const IVec3 & textureSize)131 static inline Vec3 safe2DArrayTexCoords (const Vec3& raw, const IVec3& textureSize)
132 {
133 	return safeCoords(raw, textureSize, Vec3(0.5f, 0.5f, 0.0f));
134 }
135 
safe3DTexCoords(const Vec3 & raw,const IVec3 & textureSize)136 static inline Vec3 safe3DTexCoords (const Vec3& raw, const IVec3& textureSize)
137 {
138 	return safeCoords(raw, textureSize, Vec3(0.5f));
139 }
140 
141 namespace
142 {
143 
144 struct Rect
145 {
Rectdeqp::gles3::Functional::__anon936a6fe40111::Rect146 			Rect	(int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {}
posdeqp::gles3::Functional::__anon936a6fe40111::Rect147 	IVec2	pos		(void) const { return IVec2(x, y); }
sizedeqp::gles3::Functional::__anon936a6fe40111::Rect148 	IVec2	size	(void) const { return IVec2(w, h); }
149 
150 	int		x;
151 	int		y;
152 	int		w;
153 	int		h;
154 };
155 
156 template <TextureType> struct TexTypeTcuClass;
157 template <> struct TexTypeTcuClass<TEXTURETYPE_2D>			{ typedef tcu::Texture2D		t; };
158 template <> struct TexTypeTcuClass<TEXTURETYPE_CUBE>		{ typedef tcu::TextureCube		t; };
159 template <> struct TexTypeTcuClass<TEXTURETYPE_2D_ARRAY>	{ typedef tcu::Texture2DArray	t; };
160 template <> struct TexTypeTcuClass<TEXTURETYPE_3D>			{ typedef tcu::Texture3D		t; };
161 
162 template <TextureType> struct TexTypeSizeDims;
163 template <> struct TexTypeSizeDims<TEXTURETYPE_2D>			{ enum { V = 2 }; };
164 template <> struct TexTypeSizeDims<TEXTURETYPE_CUBE>		{ enum { V = 2 }; };
165 template <> struct TexTypeSizeDims<TEXTURETYPE_2D_ARRAY>	{ enum { V = 3 }; };
166 template <> struct TexTypeSizeDims<TEXTURETYPE_3D>			{ enum { V = 3 }; };
167 
168 template <TextureType> struct TexTypeCoordDims;
169 template <> struct TexTypeCoordDims<TEXTURETYPE_2D>			{ enum { V = 2 }; };
170 template <> struct TexTypeCoordDims<TEXTURETYPE_CUBE>		{ enum { V = 3 }; };
171 template <> struct TexTypeCoordDims<TEXTURETYPE_2D_ARRAY>	{ enum { V = 3 }; };
172 template <> struct TexTypeCoordDims<TEXTURETYPE_3D>			{ enum { V = 3 }; };
173 
174 template <TextureType TexType> struct TexTypeSizeIVec		{ typedef tcu::Vector<int,		TexTypeSizeDims<TexType>::V>	t; };
175 template <TextureType TexType> struct TexTypeCoordVec		{ typedef tcu::Vector<float,	TexTypeCoordDims<TexType>::V>	t; };
176 
177 template <TextureType> struct TexTypeCoordParams;
178 
179 template <> struct
180 TexTypeCoordParams<TEXTURETYPE_2D>
181 {
182 	Vec2 scale;
183 	Vec2 bias;
184 
TexTypeCoordParamsdeqp::gles3::Functional::__anon936a6fe40111::TexTypeCoordParams185 	TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_) : scale(scale_), bias(bias_) {}
186 };
187 
188 template <> struct
189 TexTypeCoordParams<TEXTURETYPE_CUBE>
190 {
191 	Vec2			scale;
192 	Vec2			bias;
193 	tcu::CubeFace	face;
194 
TexTypeCoordParamsdeqp::gles3::Functional::__anon936a6fe40111::TexTypeCoordParams195 	TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_, tcu::CubeFace face_) : scale(scale_), bias(bias_), face(face_) {}
196 };
197 
198 template <> struct
199 TexTypeCoordParams<TEXTURETYPE_2D_ARRAY>
200 {
201 	Mat3 transform;
202 
TexTypeCoordParamsdeqp::gles3::Functional::__anon936a6fe40111::TexTypeCoordParams203 	TexTypeCoordParams (const Mat3& transform_) : transform(transform_) {}
204 };
205 
206 template <> struct
207 TexTypeCoordParams<TEXTURETYPE_3D>
208 {
209 	Mat3 transform;
210 
TexTypeCoordParamsdeqp::gles3::Functional::__anon936a6fe40111::TexTypeCoordParams211 	TexTypeCoordParams (const Mat3& transform_) : transform(transform_) {}
212 };
213 
214 /*--------------------------------------------------------------------*//*!
215  * \brief Quad grid class containing position and texture coordinate data.
216  *
217  * A quad grid of size S means a grid consisting of S*S quads (S rows and
218  * S columns). The quads are rectangles with main axis aligned sides, and
219  * each consists of two triangles. Note that although there are only
220  * (S+1)*(S+1) distinct vertex positions, there are S*S*4 distinct vertices
221  * because we want texture coordinates to be constant across the vertices
222  * of a quad (to avoid interpolation issues), and thus each quad needs its
223  * own 4 vertices.
224  *
225  * Pointers returned by get*Ptr() are suitable for gl calls such as
226  * glVertexAttribPointer() (for position and tex coord) or glDrawElements()
227  * (for indices).
228  *//*--------------------------------------------------------------------*/
229 template <TextureType TexType>
230 class PosTexCoordQuadGrid
231 {
232 private:
233 	enum { TEX_COORD_DIMS = TexTypeCoordDims <TexType>::V };
234 	typedef typename TexTypeCoordVec<TexType>::t	TexCoordVec;
235 	typedef typename TexTypeSizeIVec<TexType>::t	TexSizeIVec;
236 	typedef TexTypeCoordParams<TexType>				TexCoordParams;
237 
238 public:
239 							PosTexCoordQuadGrid		(int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords);
240 
getSize(void) const241 	int						getSize					(void) const { return m_gridSize; }
242 	Vec4					getQuadLDRU				(int col, int row) const; //!< Vec4(leftX, downY, rightX, upY)
243 	const TexCoordVec&		getQuadTexCoord			(int col, int row) const;
244 
getNumIndices(void) const245 	int						getNumIndices			(void) const { return m_gridSize*m_gridSize*3*2; }
getPositionPtr(void) const246 	const float*			getPositionPtr			(void) const { DE_STATIC_ASSERT(sizeof(Vec2) == 2*sizeof(float)); return (float*)&m_positions[0]; }
getTexCoordPtr(void) const247 	const float*			getTexCoordPtr			(void) const { DE_STATIC_ASSERT(sizeof(TexCoordVec) == TEX_COORD_DIMS*(int)sizeof(float)); return (float*)&m_texCoords[0]; }
getIndexPtr(void) const248 	const deUint16*			getIndexPtr				(void) const { return &m_indices[0]; }
249 
250 private:
251 	void					initializeTexCoords		(const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords);
252 
253 	const int				m_gridSize;
254 	vector<Vec2>			m_positions;
255 	vector<TexCoordVec>		m_texCoords;
256 	vector<deUint16>		m_indices;
257 };
258 
259 template <TextureType TexType>
getQuadLDRU(int col,int row) const260 Vec4 PosTexCoordQuadGrid<TexType>::getQuadLDRU (int col, int row) const
261 {
262 	int ndx00 = (row*m_gridSize + col) * 4;
263 	int ndx11 = ndx00 + 3;
264 
265 	return Vec4(m_positions[ndx00].x(),
266 				m_positions[ndx00].y(),
267 				m_positions[ndx11].x(),
268 				m_positions[ndx11].y());
269 }
270 
271 template <TextureType TexType>
getQuadTexCoord(int col,int row) const272 const typename TexTypeCoordVec<TexType>::t& PosTexCoordQuadGrid<TexType>::getQuadTexCoord (int col, int row) const
273 {
274 	return m_texCoords[(row*m_gridSize + col) * 4];
275 }
276 
277 template <TextureType TexType>
PosTexCoordQuadGrid(int gridSize,const IVec2 & renderSize,const TexSizeIVec & textureSize,const TexCoordParams & texCoordParams,bool useSafeTexCoords)278 PosTexCoordQuadGrid<TexType>::PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
279 	: m_gridSize(gridSize)
280 {
281 	DE_ASSERT(m_gridSize > 0 && m_gridSize*m_gridSize <= (int)std::numeric_limits<deUint16>::max() + 1);
282 
283 	const float gridSizeFloat = (float)m_gridSize;
284 
285 	m_positions.reserve(m_gridSize*m_gridSize*4);
286 	m_indices.reserve(m_gridSize*m_gridSize*3*2);
287 
288 	for (int y = 0; y < m_gridSize; y++)
289 	for (int x = 0; x < m_gridSize; x++)
290 	{
291 		float fx0 = (float)(x+0) / gridSizeFloat;
292 		float fx1 = (float)(x+1) / gridSizeFloat;
293 		float fy0 = (float)(y+0) / gridSizeFloat;
294 		float fy1 = (float)(y+1) / gridSizeFloat;
295 
296 		Vec2 quadVertices[4] = { Vec2(fx0, fy0), Vec2(fx1, fy0), Vec2(fx0, fy1), Vec2(fx1, fy1) };
297 
298 		int firstNdx = (int)m_positions.size();
299 
300 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(quadVertices); i++)
301 			m_positions.push_back(safeCoords(quadVertices[i], renderSize, Vec2(0.0f)) * 2.0f - 1.0f);
302 
303 		m_indices.push_back(deUint16(firstNdx + 0));
304 		m_indices.push_back(deUint16(firstNdx + 1));
305 		m_indices.push_back(deUint16(firstNdx + 2));
306 
307 		m_indices.push_back(deUint16(firstNdx + 1));
308 		m_indices.push_back(deUint16(firstNdx + 3));
309 		m_indices.push_back(deUint16(firstNdx + 2));
310 	}
311 
312 	m_texCoords.reserve(m_gridSize*m_gridSize*4);
313 	initializeTexCoords(textureSize, texCoordParams, useSafeTexCoords);
314 
315 	DE_ASSERT((int)m_positions.size() == m_gridSize*m_gridSize*4);
316 	DE_ASSERT((int)m_indices.size() == m_gridSize*m_gridSize*3*2);
317 	DE_ASSERT((int)m_texCoords.size() == m_gridSize*m_gridSize*4);
318 }
319 
320 template <>
initializeTexCoords(const IVec2 & textureSize,const TexCoordParams & texCoordParams,bool useSafeTexCoords)321 void PosTexCoordQuadGrid<TEXTURETYPE_2D>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
322 {
323 	DE_ASSERT(m_texCoords.empty());
324 
325 	const float gridSizeFloat = (float)m_gridSize;
326 
327 	for (int y = 0; y < m_gridSize; y++)
328 	for (int x = 0; x < m_gridSize; x++)
329 	{
330 		Vec2 rawCoord = Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) * texCoordParams.scale + texCoordParams.bias;
331 
332 		for (int i = 0; i < 4; i++)
333 			m_texCoords.push_back(useSafeTexCoords ? safe2DTexCoords(rawCoord, textureSize) : rawCoord);
334 	}
335 }
336 
337 template <>
initializeTexCoords(const IVec2 & textureSize,const TexCoordParams & texCoordParams,bool useSafeTexCoords)338 void PosTexCoordQuadGrid<TEXTURETYPE_CUBE>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
339 {
340 	DE_ASSERT(m_texCoords.empty());
341 
342 	const float		gridSizeFloat	= (float)m_gridSize;
343 	vector<float>	texBoundaries;
344 	computeQuadTexCoordCube(texBoundaries, texCoordParams.face);
345 	const Vec3		coordA			= Vec3(texBoundaries[0], texBoundaries[1], texBoundaries[2]);
346 	const Vec3		coordB			= Vec3(texBoundaries[3], texBoundaries[4], texBoundaries[5]);
347 	const Vec3		coordC			= Vec3(texBoundaries[6], texBoundaries[7], texBoundaries[8]);
348 	const Vec3		coordAB			= coordB - coordA;
349 	const Vec3		coordAC			= coordC - coordA;
350 
351 	for (int y = 0; y < m_gridSize; y++)
352 	for (int x = 0; x < m_gridSize; x++)
353 	{
354 		const Vec2 rawFaceCoord		= texCoordParams.scale * Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) + texCoordParams.bias;
355 		const Vec2 safeFaceCoord	= useSafeTexCoords ? safe2DTexCoords(rawFaceCoord, textureSize) : rawFaceCoord;
356 		const Vec3 texCoord			= coordA + coordAC*safeFaceCoord.x() + coordAB*safeFaceCoord.y();
357 
358 		for (int i = 0; i < 4; i++)
359 			m_texCoords.push_back(texCoord);
360 	}
361 }
362 
363 template <>
initializeTexCoords(const IVec3 & textureSize,const TexCoordParams & texCoordParams,bool useSafeTexCoords)364 void PosTexCoordQuadGrid<TEXTURETYPE_2D_ARRAY>::initializeTexCoords (const IVec3& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
365 {
366 	DE_ASSERT(m_texCoords.empty());
367 
368 	const float gridSizeFloat = (float)m_gridSize;
369 
370 	for (int y = 0; y < m_gridSize; y++)
371 	for (int x = 0; x < m_gridSize; x++)
372 	{
373 		const Vec3 rawCoord = texCoordParams.transform * Vec3((float)x / gridSizeFloat, (float)y / gridSizeFloat, 1.0f);
374 
375 		for (int i = 0; i < 4; i++)
376 			m_texCoords.push_back(useSafeTexCoords ? safe2DArrayTexCoords(rawCoord, textureSize) : rawCoord);
377 	}
378 }
379 
380 template <>
initializeTexCoords(const IVec3 & textureSize,const TexCoordParams & texCoordParams,bool useSafeTexCoords)381 void PosTexCoordQuadGrid<TEXTURETYPE_3D>::initializeTexCoords (const IVec3& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
382 {
383 	DE_ASSERT(m_texCoords.empty());
384 
385 	const float gridSizeFloat = (float)m_gridSize;
386 
387 	for (int y = 0; y < m_gridSize; y++)
388 	for (int x = 0; x < m_gridSize; x++)
389 	{
390 		Vec3 rawCoord = texCoordParams.transform * Vec3((float)x / gridSizeFloat, (float)y / gridSizeFloat, 1.0f);
391 
392 		for (int i = 0; i < 4; i++)
393 			m_texCoords.push_back(useSafeTexCoords ? safe3DTexCoords(rawCoord, textureSize) : rawCoord);
394 	}
395 }
396 
397 } // anonymous
398 
isLevelNearest(deUint32 filter)399 static inline bool isLevelNearest (deUint32 filter)
400 {
401 	return filter == GL_NEAREST || filter == GL_NEAREST_MIPMAP_NEAREST || filter == GL_NEAREST_MIPMAP_LINEAR;
402 }
403 
getTextureSize(const glu::Texture2D & tex)404 static inline IVec2 getTextureSize (const glu::Texture2D& tex)
405 {
406 	const tcu::Texture2D& ref = tex.getRefTexture();
407 	return IVec2(ref.getWidth(), ref.getHeight());
408 }
409 
getTextureSize(const glu::TextureCube & tex)410 static inline IVec2 getTextureSize (const glu::TextureCube& tex)
411 {
412 	const tcu::TextureCube& ref = tex.getRefTexture();
413 	return IVec2(ref.getSize(), ref.getSize());
414 }
415 
getTextureSize(const glu::Texture2DArray & tex)416 static inline IVec3 getTextureSize (const glu::Texture2DArray& tex)
417 {
418 	const tcu::Texture2DArray& ref = tex.getRefTexture();
419 	return IVec3(ref.getWidth(), ref.getHeight(), ref.getNumLayers());
420 }
421 
getTextureSize(const glu::Texture3D & tex)422 static inline IVec3 getTextureSize (const glu::Texture3D& tex)
423 {
424 	const tcu::Texture3D& ref = tex.getRefTexture();
425 	return IVec3(ref.getWidth(), ref.getHeight(), ref.getDepth());
426 }
427 
428 template <TextureType TexType>
setPixelColors(const vector<Vec4> & quadColors,const Rect & region,const PosTexCoordQuadGrid<TexType> & grid,tcu::Surface & dst)429 static void setPixelColors (const vector<Vec4>& quadColors, const Rect& region, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst)
430 {
431 	const int gridSize = grid.getSize();
432 
433 	for (int y = 0; y < gridSize; y++)
434 	for (int x = 0; x < gridSize; x++)
435 	{
436 		const Vec4	color	= quadColors[y*gridSize + x];
437 		const Vec4	ldru	= grid.getQuadLDRU(x, y) * 0.5f + 0.5f; // [-1, 1] -> [0, 1]
438 		const int	ix0		= deCeilFloatToInt32(ldru.x() * (float)region.w - 0.5f);
439 		const int	ix1		= deCeilFloatToInt32(ldru.z() * (float)region.w - 0.5f);
440 		const int	iy0		= deCeilFloatToInt32(ldru.y() * (float)region.h - 0.5f);
441 		const int	iy1		= deCeilFloatToInt32(ldru.w() * (float)region.h - 0.5f);
442 
443 		for (int iy = iy0; iy < iy1; iy++)
444 		for (int ix = ix0; ix < ix1; ix++)
445 		{
446 			DE_ASSERT(deInBounds32(ix + region.x, 0, dst.getWidth()));
447 			DE_ASSERT(deInBounds32(iy + region.y, 0, dst.getHeight()));
448 
449 			dst.setPixel(ix + region.x, iy + region.y, tcu::RGBA(color));
450 		}
451 	}
452 }
453 
sample(const tcu::Texture2D & tex,const Vec2 & coord,float lod,const tcu::Sampler & sam)454 static 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); }
sample(const tcu::TextureCube & tex,const Vec3 & coord,float lod,const tcu::Sampler & sam)455 static 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); }
sample(const tcu::Texture2DArray & tex,const Vec3 & coord,float lod,const tcu::Sampler & sam)456 static inline Vec4 sample (const tcu::Texture2DArray&	tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); }
sample(const tcu::Texture3D & tex,const Vec3 & coord,float lod,const tcu::Sampler & sam)457 static inline Vec4 sample (const tcu::Texture3D&		tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); }
458 
459 template <TextureType TexType>
computeReference(const typename TexTypeTcuClass<TexType>::t & texture,float lod,const tcu::Sampler & sampler,const PosTexCoordQuadGrid<TexType> & grid,tcu::Surface & dst,const Rect & dstRegion)460 void computeReference (const typename TexTypeTcuClass<TexType>::t& texture, float lod, const tcu::Sampler& sampler, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst, const Rect& dstRegion)
461 {
462 	const int		gridSize	= grid.getSize();
463 	vector<Vec4>	quadColors	(gridSize*gridSize);
464 
465 	for (int y = 0; y < gridSize; y++)
466 	for (int x = 0; x < gridSize; x++)
467 	{
468 		const int										ndx		= y*gridSize + x;
469 		const typename TexTypeCoordVec<TexType>::t&		coord	= grid.getQuadTexCoord(x, y);
470 
471 		quadColors[ndx] = sample(texture, coord, lod, sampler);
472 	}
473 
474 	setPixelColors(quadColors, dstRegion, grid, dst);
475 }
476 
compareImages(const glu::RenderContext & renderCtx,tcu::TestLog & log,const tcu::Surface & ref,const tcu::Surface & res)477 static bool compareImages (const glu::RenderContext& renderCtx, tcu::TestLog& log, const tcu::Surface& ref, const tcu::Surface& res)
478 {
479 	DE_ASSERT(renderCtx.getRenderTarget().getNumSamples() == 0);
480 
481 	const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(15,15,15,15);
482 	return tcu::pixelThresholdCompare(log, "Result", "Image compare result", ref, res, threshold, tcu::COMPARE_LOG_RESULT);
483 }
484 
485 class Vertex2DTextureCase : public TestCase
486 {
487 public:
488 								Vertex2DTextureCase		(Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
489 								~Vertex2DTextureCase	(void);
490 
491 	void						init					(void);
492 	void						deinit					(void);
493 	IterateResult				iterate					(void);
494 
495 private:
496 	typedef PosTexCoordQuadGrid<TEXTURETYPE_2D> Grid;
497 
498 								Vertex2DTextureCase		(const Vertex2DTextureCase& other);
499 	Vertex2DTextureCase&		operator=				(const Vertex2DTextureCase& other);
500 
501 	float						calculateLod			(const Vec2& texScale, const Vec2& dstSize, int textureNdx) const;
502 	void						setupShaderInputs		(int textureNdx, float lod, const Grid& grid) const;
503 	void						renderCell				(int textureNdx, float lod, const Grid& grid) const;
504 	void						computeReferenceCell	(int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
505 
506 	const deUint32				m_minFilter;
507 	const deUint32				m_magFilter;
508 	const deUint32				m_wrapS;
509 	const deUint32				m_wrapT;
510 
511 	const glu::ShaderProgram*	m_program;
512 	glu::Texture2D*				m_textures[2];	// 2 textures, a gradient texture and a grid texture.
513 };
514 
Vertex2DTextureCase(Context & testCtx,const char * name,const char * desc,deUint32 minFilter,deUint32 magFilter,deUint32 wrapS,deUint32 wrapT)515 Vertex2DTextureCase::Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
516 	: TestCase				(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
517 	, m_minFilter			(minFilter)
518 	, m_magFilter			(magFilter)
519 	, m_wrapS				(wrapS)
520 	, m_wrapT				(wrapT)
521 	, m_program				(DE_NULL)
522 {
523 	m_textures[0] = DE_NULL;
524 	m_textures[1] = DE_NULL;
525 }
526 
~Vertex2DTextureCase(void)527 Vertex2DTextureCase::~Vertex2DTextureCase(void)
528 {
529 	Vertex2DTextureCase::deinit();
530 }
531 
init(void)532 void Vertex2DTextureCase::init (void)
533 {
534 	const char* const vertexShader =
535 		"#version 300 es\n"
536 		"in highp vec2 a_position;\n"
537 		"in highp vec2 a_texCoord;\n"
538 		"uniform highp sampler2D u_texture;\n"
539 		"uniform highp float u_lod;\n"
540 		"out mediump vec4 v_color;\n"
541 		"\n"
542 		"void main()\n"
543 		"{\n"
544 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
545 		"	v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
546 		"}\n";
547 
548 	const char* const fragmentShader =
549 		"#version 300 es\n"
550 		"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
551 		"in mediump vec4 v_color;\n"
552 		"\n"
553 		"void main()\n"
554 		"{\n"
555 		"	dEQP_FragColor = v_color;\n"
556 		"}\n";
557 
558 	if (m_context.getRenderTarget().getNumSamples() != 0)
559 		throw tcu::NotSupportedError("MSAA config not supported by this test");
560 
561 	DE_ASSERT(!m_program);
562 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
563 
564 	if(!m_program->isOk())
565 	{
566 		m_testCtx.getLog() << *m_program;
567 
568 		GLint maxVertexTextures;
569 		glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
570 
571 		if (maxVertexTextures < 1)
572 			throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
573 		else
574 			TCU_FAIL("Failed to compile shader");
575 	}
576 
577 	// Make the textures.
578 	try
579 	{
580 		// Compute suitable power-of-two sizes (for mipmaps).
581 		const int texWidth		= 1 << deLog2Ceil32(MAX_2D_RENDER_WIDTH / 2);
582 		const int texHeight		= 1 << deLog2Ceil32(MAX_2D_RENDER_HEIGHT / 2);
583 
584 		for (int i = 0; i < 2; i++)
585 		{
586 			DE_ASSERT(!m_textures[i]);
587 			m_textures[i] = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
588 		}
589 
590 		const bool						mipmaps		= (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight));
591 		const int						numLevels	= mipmaps ? deLog2Floor32(de::max(texWidth, texHeight))+1 : 1;
592 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
593 		const Vec4						cBias		= fmtInfo.valueMin;
594 		const Vec4						cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
595 
596 		// Fill first with gradient texture.
597 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
598 		{
599 			const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
600 			const Vec4 gMax = Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
601 
602 			m_textures[0]->getRefTexture().allocLevel(levelNdx);
603 			tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
604 		}
605 
606 		// Fill second with grid texture.
607 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
608 		{
609 			const deUint32 step		= 0x00ffffff / numLevels;
610 			const deUint32 rgb		= step*levelNdx;
611 			const deUint32 colorA	= 0xff000000 | rgb;
612 			const deUint32 colorB	= 0xff000000 | ~rgb;
613 
614 			m_textures[1]->getRefTexture().allocLevel(levelNdx);
615 			tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
616 		}
617 
618 		// Upload.
619 		for (int i = 0; i < 2; i++)
620 			m_textures[i]->upload();
621 	}
622 	catch (const std::exception&)
623 	{
624 		// Clean up to save memory.
625 		Vertex2DTextureCase::deinit();
626 		throw;
627 	}
628 }
629 
deinit(void)630 void Vertex2DTextureCase::deinit (void)
631 {
632 	for (int i = 0; i < 2; i++)
633 	{
634 		delete m_textures[i];
635 		m_textures[i] = DE_NULL;
636 	}
637 
638 	delete m_program;
639 	m_program = DE_NULL;
640 }
641 
calculateLod(const Vec2 & texScale,const Vec2 & dstSize,int textureNdx) const642 float Vertex2DTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
643 {
644 	const tcu::Texture2D&		refTexture	= m_textures[textureNdx]->getRefTexture();
645 	const Vec2					srcSize		= Vec2((float)refTexture.getWidth(), (float)refTexture.getHeight());
646 	const Vec2					sizeRatio	= texScale*srcSize / dstSize;
647 
648 	// \note In this particular case dv/dx and du/dy are zero, simplifying the expression.
649 	return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
650 }
651 
iterate(void)652 Vertex2DTextureCase::IterateResult Vertex2DTextureCase::iterate (void)
653 {
654 	const int	viewportWidth		= deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_RENDER_WIDTH);
655 	const int	viewportHeight		= deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_RENDER_HEIGHT);
656 
657 	const int	viewportXOffsetMax	= m_context.getRenderTarget().getWidth() - viewportWidth;
658 	const int	viewportYOffsetMax	= m_context.getRenderTarget().getHeight() - viewportHeight;
659 
660 	de::Random	rnd					(deStringHash(getName()));
661 
662 	const int	viewportXOffset		= rnd.getInt(0, viewportXOffsetMax);
663 	const int	viewportYOffset		= rnd.getInt(0, viewportYOffsetMax);
664 
665 	glUseProgram(m_program->getProgram());
666 
667 	// Divide viewport into 4 cells.
668 	const int leftWidth		= viewportWidth / 2;
669 	const int rightWidth	= viewportWidth - leftWidth;
670 	const int bottomHeight	= viewportHeight / 2;
671 	const int topHeight		= viewportHeight - bottomHeight;
672 
673 	// Clear.
674 	glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
675 	glClear(GL_COLOR_BUFFER_BIT);
676 
677 	// Texture scaling and offsetting vectors.
678 	const Vec2 texMinScale		(+1.8f, +1.8f);
679 	const Vec2 texMinOffset		(-0.3f, -0.2f);
680 	const Vec2 texMagScale		(+0.3f, +0.3f);
681 	const Vec2 texMagOffset		(+0.9f, +0.8f);
682 
683 	// Surface for the reference image.
684 	tcu::Surface refImage(viewportWidth, viewportHeight);
685 
686 	{
687 		const struct Render
688 		{
689 			const Rect	region;
690 			int			textureNdx;
691 			const Vec2	texCoordScale;
692 			const Vec2	texCoordOffset;
693 			Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
694 		} renders[] =
695 		{
696 			Render(Rect(0,				0,				leftWidth,	bottomHeight),	0, texMinScale, texMinOffset),
697 			Render(Rect(leftWidth,		0,				rightWidth,	bottomHeight),	0, texMagScale, texMagOffset),
698 			Render(Rect(0,				bottomHeight,	leftWidth,	topHeight),		1, texMinScale, texMinOffset),
699 			Render(Rect(leftWidth,		bottomHeight,	rightWidth,	topHeight),		1, texMagScale, texMagOffset)
700 		};
701 
702 		for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
703 		{
704 			const Render&	rend				= renders[renderNdx];
705 			const float		lod					= calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
706 			const bool		useSafeTexCoords	= isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
707 			const Grid		grid				(GRID_SIZE_2D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
708 												 TexTypeCoordParams<TEXTURETYPE_2D>(rend.texCoordScale, rend.texCoordOffset), useSafeTexCoords);
709 
710 			glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
711 			renderCell				(rend.textureNdx, lod, grid);
712 			computeReferenceCell	(rend.textureNdx, lod, grid, refImage, rend.region);
713 		}
714 	}
715 
716 	// Read back rendered results.
717 	tcu::Surface resImage(viewportWidth, viewportHeight);
718 	glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
719 
720 	glUseProgram(0);
721 
722 	// Compare and log.
723 	{
724 		const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
725 
726 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
727 								isOk ? "Pass"				: "Image comparison failed");
728 	}
729 
730 	return STOP;
731 }
732 
setupShaderInputs(int textureNdx,float lod,const Grid & grid) const733 void Vertex2DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
734 {
735 	const deUint32 programID = m_program->getProgram();
736 
737 	// SETUP ATTRIBUTES.
738 
739 	{
740 		const int positionLoc = glGetAttribLocation(programID, "a_position");
741 		if (positionLoc != -1)
742 		{
743 			glEnableVertexAttribArray(positionLoc);
744 			glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
745 		}
746 	}
747 
748 	{
749 		const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
750 		if (texCoordLoc != -1)
751 		{
752 			glEnableVertexAttribArray(texCoordLoc);
753 			glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
754 		}
755 	}
756 
757 	// SETUP UNIFORMS.
758 
759 	{
760 		const int lodLoc = glGetUniformLocation(programID, "u_lod");
761 		if (lodLoc != -1)
762 			glUniform1f(lodLoc, lod);
763 	}
764 
765 	glActiveTexture(GL_TEXTURE0);
766 	glBindTexture(GL_TEXTURE_2D, m_textures[textureNdx]->getGLTexture());
767 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		m_wrapS);
768 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		m_wrapT);
769 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
770 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	m_magFilter);
771 
772 	{
773 		const int texLoc = glGetUniformLocation(programID, "u_texture");
774 		if (texLoc != -1)
775 			glUniform1i(texLoc, 0);
776 	}
777 }
778 
779 // Renders one sub-image with given parameters.
renderCell(int textureNdx,float lod,const Grid & grid) const780 void Vertex2DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
781 {
782 	setupShaderInputs(textureNdx, lod, grid);
783 	glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
784 }
785 
computeReferenceCell(int textureNdx,float lod,const Grid & grid,tcu::Surface & dst,const Rect & dstRegion) const786 void Vertex2DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
787 {
788 	computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion);
789 }
790 
791 class VertexCubeTextureCase : public TestCase
792 {
793 public:
794 								VertexCubeTextureCase	(Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
795 								~VertexCubeTextureCase	(void);
796 
797 	void						init					(void);
798 	void						deinit					(void);
799 	IterateResult				iterate					(void);
800 
801 private:
802 	typedef PosTexCoordQuadGrid<TEXTURETYPE_CUBE> Grid;
803 
804 								VertexCubeTextureCase	(const VertexCubeTextureCase& other);
805 	VertexCubeTextureCase&		operator=				(const VertexCubeTextureCase& other);
806 
807 	float						calculateLod			(const Vec2& texScale, const Vec2& dstSize, int textureNdx) const;
808 	void						setupShaderInputs		(int textureNdx, float lod, const Grid& grid) const;
809 	void						renderCell				(int textureNdx, float lod, const Grid& grid) const;
810 	void						computeReferenceCell	(int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
811 
812 	const deUint32				m_minFilter;
813 	const deUint32				m_magFilter;
814 	const deUint32				m_wrapS;
815 	const deUint32				m_wrapT;
816 
817 	const glu::ShaderProgram*	m_program;
818 	glu::TextureCube*			m_textures[2];	// 2 textures, a gradient texture and a grid texture.
819 };
820 
VertexCubeTextureCase(Context & testCtx,const char * name,const char * desc,deUint32 minFilter,deUint32 magFilter,deUint32 wrapS,deUint32 wrapT)821 VertexCubeTextureCase::VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
822 	: TestCase				(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
823 	, m_minFilter			(minFilter)
824 	, m_magFilter			(magFilter)
825 	, m_wrapS				(wrapS)
826 	, m_wrapT				(wrapT)
827 	, m_program				(DE_NULL)
828 {
829 	m_textures[0] = DE_NULL;
830 	m_textures[1] = DE_NULL;
831 }
832 
~VertexCubeTextureCase(void)833 VertexCubeTextureCase::~VertexCubeTextureCase(void)
834 {
835 	VertexCubeTextureCase::deinit();
836 }
837 
init(void)838 void VertexCubeTextureCase::init (void)
839 {
840 	const char* const vertexShader =
841 		"#version 300 es\n"
842 		"in highp vec2 a_position;\n"
843 		"in highp vec3 a_texCoord;\n"
844 		"uniform highp samplerCube u_texture;\n"
845 		"uniform highp float u_lod;\n"
846 		"out mediump vec4 v_color;\n"
847 		"\n"
848 		"void main()\n"
849 		"{\n"
850 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
851 		"	v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
852 		"}\n";
853 
854 	const char* const fragmentShader =
855 		"#version 300 es\n"
856 		"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
857 		"in mediump vec4 v_color;\n"
858 		"\n"
859 		"void main()\n"
860 		"{\n"
861 		"	dEQP_FragColor = v_color;\n"
862 		"}\n";
863 
864 	if (m_context.getRenderTarget().getNumSamples() != 0)
865 		throw tcu::NotSupportedError("MSAA config not supported by this test");
866 
867 	DE_ASSERT(!m_program);
868 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
869 
870 	if(!m_program->isOk())
871 	{
872 		m_testCtx.getLog() << *m_program;
873 
874 		GLint maxVertexTextures;
875 		glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
876 
877 		if (maxVertexTextures < 1)
878 			throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
879 		else
880 			TCU_FAIL("Failed to compile shader");
881 	}
882 
883 	// Make the textures.
884 	try
885 	{
886 		// Compute suitable power-of-two sizes (for mipmaps).
887 		const int texWidth		= 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2);
888 		const int texHeight		= 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2);
889 
890 		DE_ASSERT(texWidth == texHeight);
891 		DE_UNREF(texHeight);
892 
893 		for (int i = 0; i < 2; i++)
894 		{
895 			DE_ASSERT(!m_textures[i]);
896 			m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth);
897 		}
898 
899 		const bool						mipmaps		= deIsPowerOfTwo32(texWidth) != DE_FALSE;
900 		const int						numLevels	= mipmaps ? deLog2Floor32(texWidth)+1 : 1;
901 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
902 		const Vec4						cBias		= fmtInfo.valueMin;
903 		const Vec4						cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
904 
905 		// Fill first with gradient texture.
906 		static const Vec4 gradients[tcu::CUBEFACE_LAST][2] =
907 		{
908 			{ Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
909 			{ Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
910 			{ Vec4(-1.0f,  0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
911 			{ Vec4(-1.0f, -1.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
912 			{ Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
913 			{ Vec4( 0.0f,  0.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
914 		};
915 		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
916 		{
917 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
918 			{
919 				m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
920 				tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
921 			}
922 		}
923 
924 		// Fill second with grid texture.
925 		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
926 		{
927 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
928 			{
929 				const deUint32 step		= 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
930 				const deUint32 rgb		= step*levelNdx*face;
931 				const deUint32 colorA	= 0xff000000 | rgb;
932 				const deUint32 colorB	= 0xff000000 | ~rgb;
933 
934 				m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
935 				tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
936 			}
937 		}
938 
939 		// Upload.
940 		for (int i = 0; i < 2; i++)
941 			m_textures[i]->upload();
942 	}
943 	catch (const std::exception&)
944 	{
945 		// Clean up to save memory.
946 		VertexCubeTextureCase::deinit();
947 		throw;
948 	}
949 }
950 
deinit(void)951 void VertexCubeTextureCase::deinit (void)
952 {
953 	for (int i = 0; i < 2; i++)
954 	{
955 		delete m_textures[i];
956 		m_textures[i] = DE_NULL;
957 	}
958 
959 	delete m_program;
960 	m_program = DE_NULL;
961 }
962 
calculateLod(const Vec2 & texScale,const Vec2 & dstSize,int textureNdx) const963 float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
964 {
965 	const tcu::TextureCube&		refTexture	= m_textures[textureNdx]->getRefTexture();
966 	const Vec2					srcSize		= Vec2((float)refTexture.getSize(), (float)refTexture.getSize());
967 	const Vec2					sizeRatio	= texScale*srcSize / dstSize;
968 
969 	// \note In this particular case, dv/dx and du/dy are zero, simplifying the expression.
970 	return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
971 }
972 
iterate(void)973 VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void)
974 {
975 	const int	viewportWidth		= deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH);
976 	const int	viewportHeight		= deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT);
977 
978 	const int	viewportXOffsetMax	= m_context.getRenderTarget().getWidth() - viewportWidth;
979 	const int	viewportYOffsetMax	= m_context.getRenderTarget().getHeight() - viewportHeight;
980 
981 	de::Random	rnd					(deStringHash(getName()));
982 
983 	const int	viewportXOffset		= rnd.getInt(0, viewportXOffsetMax);
984 	const int	viewportYOffset		= rnd.getInt(0, viewportYOffsetMax);
985 
986 	glUseProgram(m_program->getProgram());
987 
988 	// Divide viewport into 4 areas.
989 	const int leftWidth		= viewportWidth / 2;
990 	const int rightWidth	= viewportWidth - leftWidth;
991 	const int bottomHeight	= viewportHeight / 2;
992 	const int topHeight		= viewportHeight - bottomHeight;
993 
994 	// Clear.
995 	glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
996 	glClear(GL_COLOR_BUFFER_BIT);
997 
998 	// Texture scaling and offsetting vectors.
999 	const Vec2 texMinScale		(1.0f, 1.0f);
1000 	const Vec2 texMinOffset		(0.0f, 0.0f);
1001 	const Vec2 texMagScale		(0.3f, 0.3f);
1002 	const Vec2 texMagOffset		(0.5f, 0.3f);
1003 
1004 	// Surface for the reference image.
1005 	tcu::Surface refImage(viewportWidth, viewportHeight);
1006 
1007 	// Each of the four areas is divided into 6 cells.
1008 	const int defCellWidth	= viewportWidth / 2 / 3;
1009 	const int defCellHeight	= viewportHeight / 2 / 2;
1010 
1011 	for (int i = 0; i < tcu::CUBEFACE_LAST; i++)
1012 	{
1013 		const int	cellOffsetX			= defCellWidth * (i % 3);
1014 		const int	cellOffsetY			= defCellHeight * (i / 3);
1015 		const bool	isRightmostCell		= i == 2 || i == 5;
1016 		const bool	isTopCell			= i >= 3;
1017 		const int	leftCellWidth		= isRightmostCell	? leftWidth		- cellOffsetX : defCellWidth;
1018 		const int	rightCellWidth		= isRightmostCell	? rightWidth	- cellOffsetX : defCellWidth;
1019 		const int	bottomCellHeight	= isTopCell			? bottomHeight	- cellOffsetY : defCellHeight;
1020 		const int	topCellHeight		= isTopCell			? topHeight		- cellOffsetY : defCellHeight;
1021 
1022 		const struct Render
1023 		{
1024 			const Rect	region;
1025 			int			textureNdx;
1026 			const Vec2	texCoordScale;
1027 			const Vec2	texCoordOffset;
1028 			Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
1029 		} renders[] =
1030 		{
1031 			Render(Rect(cellOffsetX + 0,			cellOffsetY + 0,				leftCellWidth,	bottomCellHeight),	0, texMinScale, texMinOffset),
1032 			Render(Rect(cellOffsetX + leftWidth,	cellOffsetY + 0,				rightCellWidth,	bottomCellHeight),	0, texMagScale, texMagOffset),
1033 			Render(Rect(cellOffsetX + 0,			cellOffsetY + bottomHeight,		leftCellWidth,	topCellHeight),		1, texMinScale, texMinOffset),
1034 			Render(Rect(cellOffsetX + leftWidth,	cellOffsetY + bottomHeight,		rightCellWidth,	topCellHeight),		1, texMagScale, texMagOffset)
1035 		};
1036 
1037 		for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
1038 		{
1039 			const Render&	rend				= renders[renderNdx];
1040 			const float		lod					= calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
1041 			const bool		useSafeTexCoords	= isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
1042 			const Grid		grid				(GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
1043 												 TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords);
1044 
1045 			glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
1046 			renderCell				(rend.textureNdx, lod, grid);
1047 			computeReferenceCell	(rend.textureNdx, lod, grid, refImage, rend.region);
1048 		}
1049 	}
1050 
1051 	// Read back rendered results.
1052 	tcu::Surface resImage(viewportWidth, viewportHeight);
1053 	glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
1054 
1055 	glUseProgram(0);
1056 
1057 	// Compare and log.
1058 	{
1059 		const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
1060 
1061 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1062 								isOk ? "Pass"				: "Image comparison failed");
1063 	}
1064 
1065 	return STOP;
1066 }
1067 
setupShaderInputs(int textureNdx,float lod,const Grid & grid) const1068 void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
1069 {
1070 	const deUint32 programID = m_program->getProgram();
1071 
1072 	// SETUP ATTRIBUTES.
1073 
1074 	{
1075 		const int positionLoc = glGetAttribLocation(programID, "a_position");
1076 		if (positionLoc != -1)
1077 		{
1078 			glEnableVertexAttribArray(positionLoc);
1079 			glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
1080 		}
1081 	}
1082 
1083 	{
1084 		const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
1085 		if (texCoordLoc != -1)
1086 		{
1087 			glEnableVertexAttribArray(texCoordLoc);
1088 			glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
1089 		}
1090 	}
1091 
1092 	// SETUP UNIFORMS.
1093 
1094 	{
1095 		const int lodLoc = glGetUniformLocation(programID, "u_lod");
1096 		if (lodLoc != -1)
1097 			glUniform1f(lodLoc, lod);
1098 	}
1099 
1100 	glActiveTexture(GL_TEXTURE0);
1101 	glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture());
1102 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
1103 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
1104 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1105 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	m_magFilter);
1106 
1107 	{
1108 		const int texLoc = glGetUniformLocation(programID, "u_texture");
1109 		if (texLoc != -1)
1110 			glUniform1i(texLoc, 0);
1111 	}
1112 }
1113 
1114 // Renders one cube face with given parameters.
renderCell(int textureNdx,float lod,const Grid & grid) const1115 void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1116 {
1117 	setupShaderInputs(textureNdx, lod, grid);
1118 	glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1119 }
1120 
1121 // Computes reference for one cube face with given parameters.
computeReferenceCell(int textureNdx,float lod,const Grid & grid,tcu::Surface & dst,const Rect & dstRegion) const1122 void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1123 {
1124 	tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
1125 	sampler.seamlessCubeMap = true;
1126 	computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion);
1127 }
1128 
1129 class Vertex2DArrayTextureCase : public TestCase
1130 {
1131 public:
1132 								Vertex2DArrayTextureCase	(Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
1133 								~Vertex2DArrayTextureCase	(void);
1134 
1135 	void						init						(void);
1136 	void						deinit						(void);
1137 	IterateResult				iterate						(void);
1138 
1139 private:
1140 	typedef PosTexCoordQuadGrid<TEXTURETYPE_2D_ARRAY> Grid;
1141 
1142 								Vertex2DArrayTextureCase	(const Vertex2DArrayTextureCase& other);
1143 	Vertex2DArrayTextureCase&	operator=					(const Vertex2DArrayTextureCase& other);
1144 
1145 	float						calculateLod				(const Mat3& transf, const Vec2& dstSize, int textureNdx) const;
1146 	void						setupShaderInputs			(int textureNdx, float lod, const Grid& grid) const;
1147 	void						renderCell					(int textureNdx, float lod, const Grid& grid) const;
1148 	void						computeReferenceCell		(int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
1149 
1150 	const deUint32				m_minFilter;
1151 	const deUint32				m_magFilter;
1152 	const deUint32				m_wrapS;
1153 	const deUint32				m_wrapT;
1154 
1155 	const glu::ShaderProgram*	m_program;
1156 	glu::Texture2DArray*		m_textures[2];	// 2 textures, a gradient texture and a grid texture.
1157 };
1158 
Vertex2DArrayTextureCase(Context & testCtx,const char * name,const char * desc,deUint32 minFilter,deUint32 magFilter,deUint32 wrapS,deUint32 wrapT)1159 Vertex2DArrayTextureCase::Vertex2DArrayTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
1160 	: TestCase				(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
1161 	, m_minFilter			(minFilter)
1162 	, m_magFilter			(magFilter)
1163 	, m_wrapS				(wrapS)
1164 	, m_wrapT				(wrapT)
1165 	, m_program				(DE_NULL)
1166 {
1167 	m_textures[0] = DE_NULL;
1168 	m_textures[1] = DE_NULL;
1169 }
1170 
~Vertex2DArrayTextureCase(void)1171 Vertex2DArrayTextureCase::~Vertex2DArrayTextureCase(void)
1172 {
1173 	Vertex2DArrayTextureCase::deinit();
1174 }
1175 
init(void)1176 void Vertex2DArrayTextureCase::init (void)
1177 {
1178 	const char* const vertexShaderSource =
1179 		"#version 300 es\n"
1180 		"in highp vec2 a_position;\n"
1181 		"in highp vec3 a_texCoord;\n"
1182 		"uniform highp sampler2DArray u_texture;\n"
1183 		"uniform highp float u_lod;\n"
1184 		"out mediump vec4 v_color;\n"
1185 		"\n"
1186 		"void main()\n"
1187 		"{\n"
1188 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
1189 		"	v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
1190 		"}\n";
1191 
1192 	const char* const fragmentShaderSource =
1193 		"#version 300 es\n"
1194 		"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
1195 		"in mediump vec4 v_color;\n"
1196 		"\n"
1197 		"void main()\n"
1198 		"{\n"
1199 		"	dEQP_FragColor = v_color;\n"
1200 		"}\n";
1201 
1202 	if (m_context.getRenderTarget().getNumSamples() != 0)
1203 		throw tcu::NotSupportedError("MSAA config not supported by this test");
1204 
1205 	// Create shader.
1206 
1207 	DE_ASSERT(!m_program);
1208 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
1209 
1210 	if(!m_program->isOk())
1211 	{
1212 		m_testCtx.getLog() << *m_program;
1213 
1214 		GLint maxVertexTextures;
1215 		glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
1216 
1217 		if (maxVertexTextures < 1)
1218 			throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
1219 		else
1220 			TCU_FAIL("Failed to compile shader");
1221 	}
1222 
1223 	// Make the textures.
1224 
1225 	try
1226 	{
1227 		const int texWidth	= WIDTH_2D_ARRAY;
1228 		const int texHeight	= HEIGHT_2D_ARRAY;
1229 		const int texLayers	= LAYERS_2D_ARRAY;
1230 
1231 		for (int i = 0; i < 2; i++)
1232 		{
1233 			DE_ASSERT(!m_textures[i]);
1234 			m_textures[i] = new glu::Texture2DArray(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight, texLayers);
1235 		}
1236 
1237 		const int						numLevels	= deLog2Floor32(de::max(texWidth, texHeight)) + 1;
1238 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
1239 		const Vec4						cBias		= fmtInfo.valueMin;
1240 		const Vec4						cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
1241 
1242 		// Fill first with gradient texture.
1243 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1244 		{
1245 			const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
1246 			const Vec4 gMax = Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
1247 
1248 			m_textures[0]->getRefTexture().allocLevel(levelNdx);
1249 			tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
1250 		}
1251 
1252 		// Fill second with grid texture.
1253 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1254 		{
1255 			const deUint32 step		= 0x00ffffff / numLevels;
1256 			const deUint32 rgb		= step*levelNdx;
1257 			const deUint32 colorA	= 0xff000000 | rgb;
1258 			const deUint32 colorB	= 0xff000000 | ~rgb;
1259 
1260 			m_textures[1]->getRefTexture().allocLevel(levelNdx);
1261 			tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
1262 		}
1263 
1264 		// Upload.
1265 		for (int i = 0; i < 2; i++)
1266 			m_textures[i]->upload();
1267 	}
1268 	catch (const std::exception&)
1269 	{
1270 		// Clean up to save memory.
1271 		Vertex2DArrayTextureCase::deinit();
1272 		throw;
1273 	}
1274 }
1275 
deinit(void)1276 void Vertex2DArrayTextureCase::deinit (void)
1277 {
1278 	for (int i = 0; i < 2; i++)
1279 	{
1280 		delete m_textures[i];
1281 		m_textures[i] = DE_NULL;
1282 	}
1283 
1284 	delete m_program;
1285 	m_program = DE_NULL;
1286 }
1287 
calculateLod(const Mat3 & transf,const Vec2 & dstSize,int textureNdx) const1288 float Vertex2DArrayTextureCase::calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const
1289 {
1290 	const tcu::Texture2DArray&	refTexture	= m_textures[textureNdx]->getRefTexture();
1291 	const int					texWidth	= refTexture.getWidth();
1292 	const int					texHeight	= refTexture.getHeight();
1293 
1294 	// Calculate transformed coordinates of three screen corners.
1295 	const Vec2					trans00		= (transf * Vec3(0.0f, 0.0f, 1.0f)).xy();
1296 	const Vec2					trans01		= (transf * Vec3(0.0f, 1.0f, 1.0f)).xy();
1297 	const Vec2					trans10		= (transf * Vec3(1.0f, 0.0f, 1.0f)).xy();
1298 
1299 	// Derivates.
1300 	const float dudx = (trans10.x() - trans00.x()) * (float)texWidth / dstSize.x();
1301 	const float dudy = (trans01.x() - trans00.x()) * (float)texWidth / dstSize.y();
1302 	const float dvdx = (trans10.y() - trans00.y()) * (float)texHeight / dstSize.x();
1303 	const float dvdy = (trans01.y() - trans00.y()) * (float)texHeight / dstSize.y();
1304 
1305 	return deFloatLog2(deFloatSqrt(de::max(dudx*dudx + dvdx*dvdx, dudy*dudy + dvdy*dvdy)));
1306 }
1307 
iterate(void)1308 Vertex2DArrayTextureCase::IterateResult Vertex2DArrayTextureCase::iterate (void)
1309 {
1310 	const int	viewportWidth		= deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_ARRAY_RENDER_WIDTH);
1311 	const int	viewportHeight		= deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_ARRAY_RENDER_HEIGHT);
1312 
1313 	const int	viewportXOffsetMax	= m_context.getRenderTarget().getWidth() - viewportWidth;
1314 	const int	viewportYOffsetMax	= m_context.getRenderTarget().getHeight() - viewportHeight;
1315 
1316 	de::Random	rnd					(deStringHash(getName()));
1317 
1318 	const int	viewportXOffset		= rnd.getInt(0, viewportXOffsetMax);
1319 	const int	viewportYOffset		= rnd.getInt(0, viewportYOffsetMax);
1320 
1321 	glUseProgram(m_program->getProgram());
1322 
1323 	// Divide viewport into 4 cells.
1324 	const int leftWidth		= viewportWidth / 2;
1325 	const int rightWidth	= viewportWidth - leftWidth;
1326 	const int bottomHeight	= viewportHeight / 2;
1327 	const int topHeight		= viewportHeight - bottomHeight;
1328 
1329 	// Clear.
1330 	glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
1331 	glClear(GL_COLOR_BUFFER_BIT);
1332 
1333 	// Shear by layer count to get all layers visible.
1334 	static const float layerShearTransfData[] =
1335 	{
1336 		1.0f,					0.0f, 0.0f,
1337 		0.0f,					1.0f, 0.0f,
1338 		(float)LAYERS_2D_ARRAY, 0.0f, 0.0f
1339 	};
1340 
1341 	// Minification and magnification transformations.
1342 	static const float texMinTransfData[] =
1343 	{
1344 		2.1f,  0.0f, -0.3f,
1345 		0.0f,  2.1f, -0.3f,
1346 		0.0f,  0.0f,  1.0f
1347 	};
1348 	static const float texMagTransfData[] =
1349 	{
1350 		0.4f,  0.0f,  0.8f,
1351 		0.0f,  0.4f,  0.8f,
1352 		0.0f,  0.0f,  1.0f
1353 	};
1354 
1355 	// Transformation matrices for minification and magnification.
1356 	const Mat3 texMinTransf = Mat3(layerShearTransfData) * Mat3(texMinTransfData);
1357 	const Mat3 texMagTransf = Mat3(layerShearTransfData) * Mat3(texMagTransfData);
1358 
1359 	// Surface for the reference image.
1360 	tcu::Surface refImage(viewportWidth, viewportHeight);
1361 
1362 	{
1363 		const struct Render
1364 		{
1365 			const Rect	region;
1366 			int			textureNdx;
1367 			const Mat3	texTransform;
1368 			Render (const Rect& r, int tN, const Mat3& tT) : region(r), textureNdx(tN), texTransform(tT) {}
1369 		} renders[] =
1370 		{
1371 			Render(Rect(0,				0,				leftWidth,	bottomHeight),	0, texMinTransf),
1372 			Render(Rect(leftWidth,		0,				rightWidth,	bottomHeight),	0, texMagTransf),
1373 			Render(Rect(0,				bottomHeight,	leftWidth,	topHeight),		1, texMinTransf),
1374 			Render(Rect(leftWidth,		bottomHeight,	rightWidth,	topHeight),		1, texMagTransf)
1375 		};
1376 
1377 		for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
1378 		{
1379 			const Render&	rend				= renders[renderNdx];
1380 			const float		lod					= calculateLod(rend.texTransform, rend.region.size().asFloat(), rend.textureNdx);
1381 			const bool		useSafeTexCoords	= isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
1382 			const Grid		grid				(GRID_SIZE_2D_ARRAY, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
1383 												 TexTypeCoordParams<TEXTURETYPE_2D_ARRAY>(rend.texTransform), useSafeTexCoords);
1384 
1385 			glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
1386 			renderCell				(rend.textureNdx, lod, grid);
1387 			computeReferenceCell	(rend.textureNdx, lod, grid, refImage, rend.region);
1388 		}
1389 	}
1390 
1391 	// Read back rendered results.
1392 	tcu::Surface resImage(viewportWidth, viewportHeight);
1393 	glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
1394 
1395 	glUseProgram(0);
1396 
1397 	// Compare and log.
1398 	{
1399 		const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
1400 
1401 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1402 								isOk ? "Pass"				: "Image comparison failed");
1403 	}
1404 
1405 	return STOP;
1406 }
1407 
setupShaderInputs(int textureNdx,float lod,const Grid & grid) const1408 void Vertex2DArrayTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
1409 {
1410 	const deUint32 programID = m_program->getProgram();
1411 
1412 	// SETUP ATTRIBUTES.
1413 
1414 	{
1415 		const int positionLoc = glGetAttribLocation(programID, "a_position");
1416 		if (positionLoc != -1)
1417 		{
1418 			glEnableVertexAttribArray(positionLoc);
1419 			glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
1420 		}
1421 	}
1422 
1423 	{
1424 		const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
1425 		if (texCoordLoc != -1)
1426 		{
1427 			glEnableVertexAttribArray(texCoordLoc);
1428 			glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
1429 		}
1430 	}
1431 
1432 	// SETUP UNIFORMS.
1433 
1434 	{
1435 		const int lodLoc = glGetUniformLocation(programID, "u_lod");
1436 		if (lodLoc != -1)
1437 			glUniform1f(lodLoc, lod);
1438 	}
1439 
1440 	glActiveTexture(GL_TEXTURE0);
1441 	glBindTexture(GL_TEXTURE_2D_ARRAY, m_textures[textureNdx]->getGLTexture());
1442 	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S,		m_wrapS);
1443 	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T,		m_wrapT);
1444 	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1445 	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,	m_magFilter);
1446 
1447 	{
1448 		const int texLoc = glGetUniformLocation(programID, "u_texture");
1449 		if (texLoc != -1)
1450 			glUniform1i(texLoc, 0);
1451 	}
1452 }
1453 
1454 // Renders one sub-image with given parameters.
renderCell(int textureNdx,float lod,const Grid & grid) const1455 void Vertex2DArrayTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1456 {
1457 	setupShaderInputs(textureNdx, lod, grid);
1458 	glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1459 }
1460 
1461 // Computes reference for one sub-image with given parameters.
computeReferenceCell(int textureNdx,float lod,const Grid & grid,tcu::Surface & dst,const Rect & dstRegion) const1462 void Vertex2DArrayTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1463 {
1464 	computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion);
1465 }
1466 
1467 class Vertex3DTextureCase : public TestCase
1468 {
1469 public:
1470 								Vertex3DTextureCase		(Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR);
1471 								~Vertex3DTextureCase	(void);
1472 
1473 	void						init					(void);
1474 	void						deinit					(void);
1475 	IterateResult				iterate					(void);
1476 
1477 private:
1478 	typedef PosTexCoordQuadGrid<TEXTURETYPE_3D> Grid;
1479 
1480 								Vertex3DTextureCase		(const Vertex3DTextureCase& other);
1481 	Vertex3DTextureCase&		operator=				(const Vertex3DTextureCase& other);
1482 
1483 	float						calculateLod			(const Mat3& transf, const Vec2& dstSize, int textureNdx) const;
1484 	void						setupShaderInputs		(int textureNdx, float lod, const Grid& grid) const;
1485 	void						renderCell				(int textureNdx, float lod, const Grid& grid) const;
1486 	void						computeReferenceCell	(int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
1487 
1488 	const deUint32				m_minFilter;
1489 	const deUint32				m_magFilter;
1490 	const deUint32				m_wrapS;
1491 	const deUint32				m_wrapT;
1492 	const deUint32				m_wrapR;
1493 
1494 	const glu::ShaderProgram*	m_program;
1495 	glu::Texture3D*				m_textures[2];	// 2 textures, a gradient texture and a grid texture.
1496 };
1497 
Vertex3DTextureCase(Context & testCtx,const char * name,const char * desc,deUint32 minFilter,deUint32 magFilter,deUint32 wrapS,deUint32 wrapT,deUint32 wrapR)1498 Vertex3DTextureCase::Vertex3DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR)
1499 	: TestCase				(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
1500 	, m_minFilter			(minFilter)
1501 	, m_magFilter			(magFilter)
1502 	, m_wrapS				(wrapS)
1503 	, m_wrapT				(wrapT)
1504 	, m_wrapR				(wrapR)
1505 	, m_program				(DE_NULL)
1506 {
1507 	m_textures[0] = DE_NULL;
1508 	m_textures[1] = DE_NULL;
1509 }
1510 
~Vertex3DTextureCase(void)1511 Vertex3DTextureCase::~Vertex3DTextureCase(void)
1512 {
1513 	Vertex3DTextureCase::deinit();
1514 }
1515 
init(void)1516 void Vertex3DTextureCase::init (void)
1517 {
1518 	const char* const vertexShaderSource =
1519 		"#version 300 es\n"
1520 		"in highp vec2 a_position;\n"
1521 		"in highp vec3 a_texCoord;\n"
1522 		"uniform highp sampler3D u_texture;\n"
1523 		"uniform highp float u_lod;\n"
1524 		"out mediump vec4 v_color;\n"
1525 		"\n"
1526 		"void main()\n"
1527 		"{\n"
1528 		"	gl_Position = vec4(a_position, 0.0, 1.0);\n"
1529 		"	v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
1530 		"}\n";
1531 
1532 	const char* const fragmentShaderSource =
1533 		"#version 300 es\n"
1534 		"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
1535 		"in mediump vec4 v_color;\n"
1536 		"\n"
1537 		"void main()\n"
1538 		"{\n"
1539 		"	dEQP_FragColor = v_color;\n"
1540 		"}\n";
1541 
1542 	if (m_context.getRenderTarget().getNumSamples() != 0)
1543 		throw tcu::NotSupportedError("MSAA config not supported by this test");
1544 
1545 	// Create shader.
1546 
1547 	DE_ASSERT(!m_program);
1548 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
1549 
1550 	if(!m_program->isOk())
1551 	{
1552 		m_testCtx.getLog() << *m_program;
1553 
1554 		GLint maxVertexTextures;
1555 		glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
1556 
1557 		if (maxVertexTextures < 1)
1558 			throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
1559 		else
1560 			TCU_FAIL("Failed to compile shader");
1561 	}
1562 
1563 	// Make the textures.
1564 
1565 	try
1566 	{
1567 		const int texWidth	= WIDTH_3D;
1568 		const int texHeight	= HEIGHT_3D;
1569 		const int texDepth	= DEPTH_3D;
1570 
1571 		for (int i = 0; i < 2; i++)
1572 		{
1573 			DE_ASSERT(!m_textures[i]);
1574 			m_textures[i] = new glu::Texture3D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight, texDepth);
1575 		}
1576 
1577 		const int						numLevels	= deLog2Floor32(de::max(de::max(texWidth, texHeight), texDepth)) + 1;
1578 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
1579 		const Vec4						cBias		= fmtInfo.valueMin;
1580 		const Vec4						cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
1581 
1582 		// Fill first with gradient texture.
1583 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1584 		{
1585 			const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
1586 			const Vec4 gMax = Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
1587 
1588 			m_textures[0]->getRefTexture().allocLevel(levelNdx);
1589 			tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
1590 		}
1591 
1592 		// Fill second with grid texture.
1593 		for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1594 		{
1595 			const deUint32 step		= 0x00ffffff / numLevels;
1596 			const deUint32 rgb		= step*levelNdx;
1597 			const deUint32 colorA	= 0xff000000 | rgb;
1598 			const deUint32 colorB	= 0xff000000 | ~rgb;
1599 
1600 			m_textures[1]->getRefTexture().allocLevel(levelNdx);
1601 			tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
1602 		}
1603 
1604 		// Upload.
1605 		for (int i = 0; i < 2; i++)
1606 			m_textures[i]->upload();
1607 	}
1608 	catch (const std::exception&)
1609 	{
1610 		// Clean up to save memory.
1611 		Vertex3DTextureCase::deinit();
1612 		throw;
1613 	}
1614 }
1615 
deinit(void)1616 void Vertex3DTextureCase::deinit (void)
1617 {
1618 	for (int i = 0; i < 2; i++)
1619 	{
1620 		delete m_textures[i];
1621 		m_textures[i] = DE_NULL;
1622 	}
1623 
1624 	delete m_program;
1625 	m_program = DE_NULL;
1626 }
1627 
calculateLod(const Mat3 & transf,const Vec2 & dstSize,int textureNdx) const1628 float Vertex3DTextureCase::calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const
1629 {
1630 	const tcu::Texture3D&	refTexture	= m_textures[textureNdx]->getRefTexture();
1631 	const int				srcWidth	= refTexture.getWidth();
1632 	const int				srcHeight	= refTexture.getHeight();
1633 	const int				srcDepth	= refTexture.getDepth();
1634 
1635 	// Calculate transformed coordinates of three screen corners.
1636 	const Vec3				trans00		= transf * Vec3(0.0f, 0.0f, 1.0f);
1637 	const Vec3				trans01		= transf * Vec3(0.0f, 1.0f, 1.0f);
1638 	const Vec3				trans10		= transf * Vec3(1.0f, 0.0f, 1.0f);
1639 
1640 	// Derivates.
1641 	const float dudx = (trans10.x() - trans00.x()) * (float)srcWidth / dstSize.x();
1642 	const float dudy = (trans01.x() - trans00.x()) * (float)srcWidth / dstSize.y();
1643 	const float dvdx = (trans10.y() - trans00.y()) * (float)srcHeight / dstSize.x();
1644 	const float dvdy = (trans01.y() - trans00.y()) * (float)srcHeight / dstSize.y();
1645 	const float dwdx = (trans10.z() - trans00.z()) * (float)srcDepth / dstSize.x();
1646 	const float dwdy = (trans01.z() - trans00.z()) * (float)srcDepth / dstSize.y();
1647 
1648 	return deFloatLog2(deFloatSqrt(de::max(dudx*dudx + dvdx*dvdx + dwdx*dwdx, dudy*dudy + dvdy*dvdy + dwdy*dwdy)));
1649 }
1650 
iterate(void)1651 Vertex3DTextureCase::IterateResult Vertex3DTextureCase::iterate (void)
1652 {
1653 	const int	viewportWidth		= deMin32(m_context.getRenderTarget().getWidth(), MAX_3D_RENDER_WIDTH);
1654 	const int	viewportHeight		= deMin32(m_context.getRenderTarget().getHeight(), MAX_3D_RENDER_HEIGHT);
1655 
1656 	const int	viewportXOffsetMax	= m_context.getRenderTarget().getWidth() - viewportWidth;
1657 	const int	viewportYOffsetMax	= m_context.getRenderTarget().getHeight() - viewportHeight;
1658 
1659 	de::Random	rnd					(deStringHash(getName()));
1660 
1661 	const int	viewportXOffset		= rnd.getInt(0, viewportXOffsetMax);
1662 	const int	viewportYOffset		= rnd.getInt(0, viewportYOffsetMax);
1663 
1664 	glUseProgram(m_program->getProgram());
1665 
1666 	// Divide viewport into 4 cells.
1667 	const int leftWidth		= viewportWidth / 2;
1668 	const int rightWidth		= viewportWidth - leftWidth;
1669 	const int bottomHeight	= viewportHeight / 2;
1670 	const int topHeight		= viewportHeight - bottomHeight;
1671 
1672 	// Clear.
1673 	glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
1674 	glClear(GL_COLOR_BUFFER_BIT);
1675 
1676 	// Shear to get all slices visible.
1677 	static const float depthShearTransfData[] =
1678 	{
1679 		1.0f, 0.0f, 0.0f,
1680 		0.0f, 1.0f, 0.0f,
1681 		1.0f, 1.0f, 0.0f
1682 	};
1683 
1684 	// Minification and magnification transformations.
1685 	static const float texMinTransfData[] =
1686 	{
1687 		2.2f,  0.0f, -0.3f,
1688 		0.0f,  2.2f, -0.3f,
1689 		0.0f,  0.0f,  1.0f
1690 	};
1691 	static const float texMagTransfData[] =
1692 	{
1693 		0.4f,  0.0f,  0.8f,
1694 		0.0f,  0.4f,  0.8f,
1695 		0.0f,  0.0f,  1.0f
1696 	};
1697 
1698 	// Transformation matrices for minification and magnification.
1699 	const Mat3 texMinTransf = Mat3(depthShearTransfData) * Mat3(texMinTransfData);
1700 	const Mat3 texMagTransf = Mat3(depthShearTransfData) * Mat3(texMagTransfData);
1701 
1702 	// Surface for the reference image.
1703 	tcu::Surface refImage(viewportWidth, viewportHeight);
1704 
1705 	{
1706 		const struct Render
1707 		{
1708 			const Rect	region;
1709 			int			textureNdx;
1710 			const Mat3		texTransform;
1711 			Render (const Rect& r, int tN, const Mat3& tT) : region(r), textureNdx(tN), texTransform(tT) {}
1712 		} renders[] =
1713 		{
1714 			Render(Rect(0,				0,				leftWidth,	bottomHeight),	0, texMinTransf),
1715 			Render(Rect(leftWidth,		0,				rightWidth,	bottomHeight),	0, texMagTransf),
1716 			Render(Rect(0,				bottomHeight,	leftWidth,	topHeight),		1, texMinTransf),
1717 			Render(Rect(leftWidth,		bottomHeight,	rightWidth,	topHeight),		1, texMagTransf)
1718 		};
1719 
1720 		for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
1721 		{
1722 			const Render&	rend				= renders[renderNdx];
1723 			const float		lod					= calculateLod(rend.texTransform, rend.region.size().asFloat(), rend.textureNdx);
1724 			const bool		useSafeTexCoords	= isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
1725 			const Grid		grid				(GRID_SIZE_3D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
1726 												 TexTypeCoordParams<TEXTURETYPE_3D>(rend.texTransform), useSafeTexCoords);
1727 
1728 			glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
1729 			renderCell				(rend.textureNdx, lod, grid);
1730 			computeReferenceCell	(rend.textureNdx, lod, grid, refImage, rend.region);
1731 		}
1732 	}
1733 
1734 	// Read back rendered results.
1735 	tcu::Surface resImage(viewportWidth, viewportHeight);
1736 	glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
1737 
1738 	glUseProgram(0);
1739 
1740 	// Compare and log.
1741 	{
1742 		const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
1743 
1744 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
1745 								isOk ? "Pass"				: "Image comparison failed");
1746 	}
1747 
1748 	return STOP;
1749 }
1750 
setupShaderInputs(int textureNdx,float lod,const Grid & grid) const1751 void Vertex3DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
1752 {
1753 	const deUint32 programID = m_program->getProgram();
1754 
1755 	// SETUP ATTRIBUTES.
1756 
1757 	{
1758 		const int positionLoc = glGetAttribLocation(programID, "a_position");
1759 		if (positionLoc != -1)
1760 		{
1761 			glEnableVertexAttribArray(positionLoc);
1762 			glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
1763 		}
1764 	}
1765 
1766 	{
1767 		const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
1768 		if (texCoordLoc != -1)
1769 		{
1770 			glEnableVertexAttribArray(texCoordLoc);
1771 			glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
1772 		}
1773 	}
1774 
1775 	// SETUP UNIFORMS.
1776 
1777 	{
1778 		const int lodLoc = glGetUniformLocation(programID, "u_lod");
1779 		if (lodLoc != -1)
1780 			glUniform1f(lodLoc, lod);
1781 	}
1782 
1783 	glActiveTexture(GL_TEXTURE0);
1784 	glBindTexture(GL_TEXTURE_3D, m_textures[textureNdx]->getGLTexture());
1785 	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,		m_wrapS);
1786 	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,		m_wrapT);
1787 	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,		m_wrapR);
1788 	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1789 	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,	m_magFilter);
1790 
1791 	{
1792 		const int texLoc = glGetUniformLocation(programID, "u_texture");
1793 		if (texLoc != -1)
1794 			glUniform1i(texLoc, 0);
1795 	}
1796 }
1797 
1798 // Renders one sub-image with given parameters.
renderCell(int textureNdx,float lod,const Grid & grid) const1799 void Vertex3DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1800 {
1801 	setupShaderInputs(textureNdx, lod, grid);
1802 	glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1803 }
1804 
1805 // Computes reference for one sub-image with given parameters.
computeReferenceCell(int textureNdx,float lod,const Grid & grid,tcu::Surface & dst,const Rect & dstRegion) const1806 void Vertex3DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1807 {
1808 	computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, m_magFilter), grid, dst, dstRegion);
1809 }
1810 
VertexTextureTests(Context & context)1811 VertexTextureTests::VertexTextureTests (Context& context)
1812 	: TestCaseGroup(context, "vertex", "Vertex Texture Tests")
1813 {
1814 }
1815 
~VertexTextureTests(void)1816 VertexTextureTests::~VertexTextureTests(void)
1817 {
1818 }
1819 
init(void)1820 void VertexTextureTests::init (void)
1821 {
1822 	// 2D and cube map groups, and their filtering and wrap sub-groups.
1823 	TestCaseGroup* const group2D				= new TestCaseGroup(m_context, "2d",			"2D Vertex Texture Tests");
1824 	TestCaseGroup* const groupCube				= new TestCaseGroup(m_context, "cube",			"Cube Map Vertex Texture Tests");
1825 	TestCaseGroup* const group2DArray			= new TestCaseGroup(m_context, "2d_array",		"2D Array Vertex Texture Tests");
1826 	TestCaseGroup* const group3D				= new TestCaseGroup(m_context, "3d",			"3D Vertex Texture Tests");
1827 	TestCaseGroup* const filteringGroup2D		= new TestCaseGroup(m_context, "filtering",		"2D Vertex Texture Filtering Tests");
1828 	TestCaseGroup* const wrapGroup2D			= new TestCaseGroup(m_context, "wrap",			"2D Vertex Texture Wrap Tests");
1829 	TestCaseGroup* const filteringGroupCube		= new TestCaseGroup(m_context, "filtering",		"Cube Map Vertex Texture Filtering Tests");
1830 	TestCaseGroup* const wrapGroupCube			= new TestCaseGroup(m_context, "wrap",			"Cube Map Vertex Texture Wrap Tests");
1831 	TestCaseGroup* const filteringGroup2DArray	= new TestCaseGroup(m_context, "filtering",		"2D Array Vertex Texture Filtering Tests");
1832 	TestCaseGroup* const wrapGroup2DArray		= new TestCaseGroup(m_context, "wrap",			"2D Array Vertex Texture Wrap Tests");
1833 	TestCaseGroup* const filteringGroup3D		= new TestCaseGroup(m_context, "filtering",		"3D Vertex Texture Filtering Tests");
1834 	TestCaseGroup* const wrapGroup3D			= new TestCaseGroup(m_context, "wrap",			"3D Vertex Texture Wrap Tests");
1835 
1836 	group2D->addChild(filteringGroup2D);
1837 	group2D->addChild(wrapGroup2D);
1838 	groupCube->addChild(filteringGroupCube);
1839 	groupCube->addChild(wrapGroupCube);
1840 	group2DArray->addChild(filteringGroup2DArray);
1841 	group2DArray->addChild(wrapGroup2DArray);
1842 	group3D->addChild(filteringGroup3D);
1843 	group3D->addChild(wrapGroup3D);
1844 
1845 	addChild(group2D);
1846 	addChild(groupCube);
1847 	addChild(group2DArray);
1848 	addChild(group3D);
1849 
1850 	static const struct
1851 	{
1852 		const char*		name;
1853 		GLenum			mode;
1854 	} wrapModes[] =
1855 	{
1856 		{ "clamp",		GL_CLAMP_TO_EDGE	},
1857 		{ "repeat",		GL_REPEAT			},
1858 		{ "mirror",		GL_MIRRORED_REPEAT	}
1859 	};
1860 
1861 	static const struct
1862 	{
1863 		const char*		name;
1864 		GLenum			mode;
1865 	} minFilterModes[] =
1866 	{
1867 		{ "nearest",				GL_NEAREST					},
1868 		{ "linear",					GL_LINEAR					},
1869 		{ "nearest_mipmap_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1870 		{ "linear_mipmap_nearest",	GL_LINEAR_MIPMAP_NEAREST	},
1871 		{ "nearest_mipmap_linear",	GL_NEAREST_MIPMAP_LINEAR	},
1872 		{ "linear_mipmap_linear",	GL_LINEAR_MIPMAP_LINEAR		}
1873 	};
1874 
1875 	static const struct
1876 	{
1877 		const char*		name;
1878 		GLenum			mode;
1879 	} magFilterModes[] =
1880 	{
1881 		{ "nearest",	GL_NEAREST	},
1882 		{ "linear",		GL_LINEAR	}
1883 	};
1884 
1885 #define FOR_EACH(ITERATOR, ARRAY, BODY)	\
1886 	for (int (ITERATOR) = 0; (ITERATOR) < DE_LENGTH_OF_ARRAY(ARRAY); (ITERATOR)++)	\
1887 		BODY
1888 
1889 	// 2D cases.
1890 
1891 	FOR_EACH(minFilter,		minFilterModes,
1892 	FOR_EACH(magFilter,		magFilterModes,
1893 	FOR_EACH(wrapMode,		wrapModes,
1894 		{
1895 			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1896 
1897 			filteringGroup2D->addChild(new Vertex2DTextureCase(m_context,
1898 															   name.c_str(), "",
1899 															   minFilterModes[minFilter].mode,
1900 															   magFilterModes[magFilter].mode,
1901 															   wrapModes[wrapMode].mode,
1902 															   wrapModes[wrapMode].mode));
1903 		})));
1904 
1905 	FOR_EACH(wrapSMode,		wrapModes,
1906 	FOR_EACH(wrapTMode,		wrapModes,
1907 		{
1908 			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1909 
1910 			wrapGroup2D->addChild(new Vertex2DTextureCase(m_context,
1911 														  name.c_str(), "",
1912 														  GL_LINEAR_MIPMAP_LINEAR,
1913 														  GL_LINEAR,
1914 														  wrapModes[wrapSMode].mode,
1915 														  wrapModes[wrapTMode].mode));
1916 		}));
1917 
1918 	// Cube map cases.
1919 
1920 	FOR_EACH(minFilter,		minFilterModes,
1921 	FOR_EACH(magFilter,		magFilterModes,
1922 	FOR_EACH(wrapMode,		wrapModes,
1923 		{
1924 			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1925 
1926 			filteringGroupCube->addChild(new VertexCubeTextureCase(m_context,
1927 																   name.c_str(), "",
1928 																   minFilterModes[minFilter].mode,
1929 																   magFilterModes[magFilter].mode,
1930 																   wrapModes[wrapMode].mode,
1931 																   wrapModes[wrapMode].mode));
1932 		})));
1933 
1934 	FOR_EACH(wrapSMode,		wrapModes,
1935 	FOR_EACH(wrapTMode,		wrapModes,
1936 		{
1937 			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1938 
1939 			wrapGroupCube->addChild(new VertexCubeTextureCase(m_context,
1940 															  name.c_str(), "",
1941 															  GL_LINEAR_MIPMAP_LINEAR,
1942 															  GL_LINEAR,
1943 															  wrapModes[wrapSMode].mode,
1944 															  wrapModes[wrapTMode].mode));
1945 		}));
1946 
1947 	// 2D array cases.
1948 
1949 	FOR_EACH(minFilter,		minFilterModes,
1950 	FOR_EACH(magFilter,		magFilterModes,
1951 	FOR_EACH(wrapMode,		wrapModes,
1952 		{
1953 			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1954 
1955 			filteringGroup2DArray->addChild(new Vertex2DArrayTextureCase(m_context,
1956 																		 name.c_str(), "",
1957 																		 minFilterModes[minFilter].mode,
1958 																		 magFilterModes[magFilter].mode,
1959 																		 wrapModes[wrapMode].mode,
1960 																		 wrapModes[wrapMode].mode));
1961 		})));
1962 
1963 	FOR_EACH(wrapSMode,		wrapModes,
1964 	FOR_EACH(wrapTMode,		wrapModes,
1965 		{
1966 			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1967 
1968 			wrapGroup2DArray->addChild(new Vertex2DArrayTextureCase(m_context,
1969 																	name.c_str(), "",
1970 																	GL_LINEAR_MIPMAP_LINEAR,
1971 																	GL_LINEAR,
1972 																	wrapModes[wrapSMode].mode,
1973 																	wrapModes[wrapTMode].mode));
1974 		}));
1975 
1976 	// 3D cases.
1977 
1978 	FOR_EACH(minFilter,		minFilterModes,
1979 	FOR_EACH(magFilter,		magFilterModes,
1980 	FOR_EACH(wrapMode,		wrapModes,
1981 		{
1982 			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1983 
1984 			filteringGroup3D->addChild(new Vertex3DTextureCase(m_context,
1985 															   name.c_str(), "",
1986 															   minFilterModes[minFilter].mode,
1987 															   magFilterModes[magFilter].mode,
1988 															   wrapModes[wrapMode].mode,
1989 															   wrapModes[wrapMode].mode,
1990 															   wrapModes[wrapMode].mode));
1991 		})));
1992 
1993 	FOR_EACH(wrapSMode,		wrapModes,
1994 	FOR_EACH(wrapTMode,		wrapModes,
1995 	FOR_EACH(wrapRMode,		wrapModes,
1996 		{
1997 			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name + "_" + wrapModes[wrapRMode].name;
1998 
1999 			wrapGroup3D->addChild(new Vertex3DTextureCase(m_context,
2000 														  name.c_str(), "",
2001 														  GL_LINEAR_MIPMAP_LINEAR,
2002 														  GL_LINEAR,
2003 														  wrapModes[wrapSMode].mode,
2004 														  wrapModes[wrapTMode].mode,
2005 														  wrapModes[wrapRMode].mode));
2006 		})));
2007 }
2008 
2009 } // Functional
2010 } // gles3
2011 } // deqp
2012