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