Home | History | Annotate | Download | only in functional
      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.
    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 
    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>
    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 
    126 static inline Vec2 safe2DTexCoords (const Vec2& raw, const IVec2& textureSize)
    127 {
    128 	return safeCoords(raw, textureSize, Vec2(0.5f));
    129 }
    130 
    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 
    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 {
    146 			Rect	(int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {}
    147 	IVec2	pos		(void) const { return IVec2(x, y); }
    148 	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 
    185 	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 
    195 	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 
    203 	TexTypeCoordParams (const Mat3& transform_) : transform(transform_) {}
    204 };
    205 
    206 template <> struct
    207 TexTypeCoordParams<TEXTURETYPE_3D>
    208 {
    209 	Mat3 transform;
    210 
    211 	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 
    241 	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 
    245 	int						getNumIndices			(void) const { return m_gridSize*m_gridSize*3*2; }
    246 	const float*			getPositionPtr			(void) const { DE_STATIC_ASSERT(sizeof(Vec2) == 2*sizeof(float)); return (float*)&m_positions[0]; }
    247 	const float*			getTexCoordPtr			(void) const { DE_STATIC_ASSERT(sizeof(TexCoordVec) == TEX_COORD_DIMS*(int)sizeof(float)); return (float*)&m_texCoords[0]; }
    248 	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>
    260 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>
    272 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>
    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 <>
    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 <>
    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 <>
    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 <>
    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 
    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 
    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 
    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 
    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 
    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>
    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 
    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); }
    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); }
    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); }
    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>
    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 
    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 
    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 
    527 Vertex2DTextureCase::~Vertex2DTextureCase(void)
    528 {
    529 	Vertex2DTextureCase::deinit();
    530 }
    531 
    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 
    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 
    642 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 
    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 
    733 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.
    780 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 
    786 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 
    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 
    833 VertexCubeTextureCase::~VertexCubeTextureCase(void)
    834 {
    835 	VertexCubeTextureCase::deinit();
    836 }
    837 
    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 
    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 
    963 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 
    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 
   1068 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.
   1115 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.
   1122 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 
   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 
   1171 Vertex2DArrayTextureCase::~Vertex2DArrayTextureCase(void)
   1172 {
   1173 	Vertex2DArrayTextureCase::deinit();
   1174 }
   1175 
   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 
   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 
   1288 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 
   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 
   1408 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.
   1455 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.
   1462 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 
   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 
   1511 Vertex3DTextureCase::~Vertex3DTextureCase(void)
   1512 {
   1513 	Vertex3DTextureCase::deinit();
   1514 }
   1515 
   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 
   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 
   1628 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 
   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 
   1751 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.
   1799 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.
   1806 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 
   1811 VertexTextureTests::VertexTextureTests (Context& context)
   1812 	: TestCaseGroup(context, "vertex", "Vertex Texture Tests")
   1813 {
   1814 }
   1815 
   1816 VertexTextureTests::~VertexTextureTests(void)
   1817 {
   1818 }
   1819 
   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