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