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