• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anon240494230111::Rect119 			Rect	(int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {}
posdeqp::gles2::Functional::__anon240494230111::Rect120 	IVec2	pos		(void) const { return IVec2(x, y); }
sizedeqp::gles2::Functional::__anon240494230111::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::__anon240494230111::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::__anon240494230111::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 	m_isES3Capable = glu::IsES3Compatible(m_context.getRenderContext().getFunctions());
765 
766 	if (m_context.getRenderTarget().getNumSamples() != 0)
767 		throw tcu::NotSupportedError("MSAA config not supported by this test");
768 
769 	DE_ASSERT(!m_program);
770 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
771 
772 	if(!m_program->isOk())
773 	{
774 		m_testCtx.getLog() << *m_program;
775 
776 		GLint maxVertexTextures;
777 		glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
778 
779 		if (maxVertexTextures < 1)
780 			throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
781 		else
782 			TCU_FAIL("Failed to compile shader");
783 	}
784 
785 	// Make the textures.
786 	try
787 	{
788 		// Compute suitable power-of-two sizes (for mipmaps).
789 		const int texWidth		= 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2);
790 		const int texHeight		= 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2);
791 
792 		DE_ASSERT(texWidth == texHeight);
793 		DE_UNREF(texHeight);
794 
795 		for (int i = 0; i < 2; i++)
796 		{
797 			DE_ASSERT(!m_textures[i]);
798 			m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth);
799 		}
800 
801 		const bool						mipmaps		= deIsPowerOfTwo32(texWidth) != DE_FALSE;
802 		const int						numLevels	= mipmaps ? deLog2Floor32(texWidth)+1 : 1;
803 		const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
804 		const Vec4						cBias		= fmtInfo.valueMin;
805 		const Vec4						cScale		= fmtInfo.valueMax-fmtInfo.valueMin;
806 
807 		// Fill first with gradient texture.
808 		static const Vec4 gradients[tcu::CUBEFACE_LAST][2] =
809 		{
810 			{ Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
811 			{ Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
812 			{ Vec4(-1.0f,  0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
813 			{ Vec4(-1.0f, -1.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
814 			{ Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
815 			{ Vec4( 0.0f,  0.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
816 		};
817 		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
818 		{
819 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
820 			{
821 				m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
822 				tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
823 			}
824 		}
825 
826 		// Fill second with grid texture.
827 		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
828 		{
829 			for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
830 			{
831 				const deUint32 step		= 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
832 				const deUint32 rgb		= step*levelNdx*face;
833 				const deUint32 colorA	= 0xff000000 | rgb;
834 				const deUint32 colorB	= 0xff000000 | ~rgb;
835 
836 				m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
837 				tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
838 			}
839 		}
840 
841 		// Upload.
842 		for (int i = 0; i < 2; i++)
843 			m_textures[i]->upload();
844 	}
845 	catch (const std::exception&)
846 	{
847 		// Clean up to save memory.
848 		VertexCubeTextureCase::deinit();
849 		throw;
850 	}
851 }
852 
deinit(void)853 void VertexCubeTextureCase::deinit (void)
854 {
855 	for (int i = 0; i < 2; i++)
856 	{
857 		delete m_textures[i];
858 		m_textures[i] = DE_NULL;
859 	}
860 
861 	delete m_program;
862 	m_program = DE_NULL;
863 }
864 
calculateLod(const Vec2 & texScale,const Vec2 & dstSize,int textureNdx) const865 float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
866 {
867 	const tcu::TextureCube&		refTexture	= m_textures[textureNdx]->getRefTexture();
868 	const Vec2					srcSize		= Vec2((float)refTexture.getSize(), (float)refTexture.getSize());
869 	const Vec2					sizeRatio	= texScale*srcSize / dstSize;
870 
871 	// \note In this particular case, dv/dx and du/dy are zero, simplifying the expression.
872 	return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
873 }
874 
iterate(void)875 VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void)
876 {
877 	const int	viewportWidth		= deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH);
878 	const int	viewportHeight		= deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT);
879 
880 	const int	viewportXOffsetMax	= m_context.getRenderTarget().getWidth() - viewportWidth;
881 	const int	viewportYOffsetMax	= m_context.getRenderTarget().getHeight() - viewportHeight;
882 
883 	de::Random	rnd					(deStringHash(getName()));
884 
885 	const int	viewportXOffset		= rnd.getInt(0, viewportXOffsetMax);
886 	const int	viewportYOffset		= rnd.getInt(0, viewportYOffsetMax);
887 
888 	glUseProgram(m_program->getProgram());
889 
890 	// Divide viewport into 4 areas.
891 	const int leftWidth		= viewportWidth / 2;
892 	const int rightWidth	= viewportWidth - leftWidth;
893 	const int bottomHeight	= viewportHeight / 2;
894 	const int topHeight		= viewportHeight - bottomHeight;
895 
896 	// Clear.
897 	glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
898 	glClear(GL_COLOR_BUFFER_BIT);
899 
900 	// Texture scaling and offsetting vectors.
901 	const Vec2 texMinScale		(1.0f, 1.0f);
902 	const Vec2 texMinOffset		(0.0f, 0.0f);
903 	const Vec2 texMagScale		(0.3f, 0.3f);
904 	const Vec2 texMagOffset		(0.5f, 0.3f);
905 
906 	// Surface for the reference image.
907 	tcu::Surface refImage(viewportWidth, viewportHeight);
908 
909 	// Each of the four areas is divided into 6 cells.
910 	const int defCellWidth	= viewportWidth / 2 / 3;
911 	const int defCellHeight	= viewportHeight / 2 / 2;
912 
913 	for (int i = 0; i < tcu::CUBEFACE_LAST; i++)
914 	{
915 		const int	cellOffsetX			= defCellWidth * (i % 3);
916 		const int	cellOffsetY			= defCellHeight * (i / 3);
917 		const bool	isRightmostCell		= i == 2 || i == 5;
918 		const bool	isTopCell			= i >= 3;
919 		const int	leftCellWidth		= isRightmostCell	? leftWidth		- cellOffsetX : defCellWidth;
920 		const int	rightCellWidth		= isRightmostCell	? rightWidth	- cellOffsetX : defCellWidth;
921 		const int	bottomCellHeight	= isTopCell			? bottomHeight	- cellOffsetY : defCellHeight;
922 		const int	topCellHeight		= isTopCell			? topHeight		- cellOffsetY : defCellHeight;
923 
924 		const struct Render
925 		{
926 			const Rect	region;
927 			int			textureNdx;
928 			const Vec2	texCoordScale;
929 			const Vec2	texCoordOffset;
930 			Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
931 		} renders[] =
932 		{
933 			Render(Rect(cellOffsetX + 0,			cellOffsetY + 0,				leftCellWidth,	bottomCellHeight),	0, texMinScale, texMinOffset),
934 			Render(Rect(cellOffsetX + leftWidth,	cellOffsetY + 0,				rightCellWidth,	bottomCellHeight),	0, texMagScale, texMagOffset),
935 			Render(Rect(cellOffsetX + 0,			cellOffsetY + bottomHeight,		leftCellWidth,	topCellHeight),		1, texMinScale, texMinOffset),
936 			Render(Rect(cellOffsetX + leftWidth,	cellOffsetY + bottomHeight,		rightCellWidth,	topCellHeight),		1, texMagScale, texMagOffset)
937 		};
938 
939 		for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
940 		{
941 			const Render&	rend				= renders[renderNdx];
942 			const float		lod					= calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
943 			const bool		useSafeTexCoords	= isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
944 			const Grid		grid				(GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
945 												 TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords);
946 
947 			glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
948 			renderCell				(rend.textureNdx, lod, grid);
949 			computeReferenceCell	(rend.textureNdx, lod, grid, refImage, rend.region);
950 		}
951 	}
952 
953 	// Read back rendered results.
954 	tcu::Surface resImage(viewportWidth, viewportHeight);
955 	glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
956 
957 	glUseProgram(0);
958 
959 	// Compare and log.
960 	{
961 		const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
962 
963 		m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
964 								isOk ? "Pass"				: "Image comparison failed");
965 	}
966 
967 	return STOP;
968 }
969 
setupShaderInputs(int textureNdx,float lod,const Grid & grid) const970 void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
971 {
972 	const deUint32 programID = m_program->getProgram();
973 
974 	// SETUP ATTRIBUTES.
975 
976 	{
977 		const int positionLoc = glGetAttribLocation(programID, "a_position");
978 		if (positionLoc != -1)
979 		{
980 			glEnableVertexAttribArray(positionLoc);
981 			glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
982 		}
983 	}
984 
985 	{
986 		const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
987 		if (texCoordLoc != -1)
988 		{
989 			glEnableVertexAttribArray(texCoordLoc);
990 			glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
991 		}
992 	}
993 
994 	// SETUP UNIFORMS.
995 
996 	{
997 		const int lodLoc = glGetUniformLocation(programID, "u_lod");
998 		if (lodLoc != -1)
999 			glUniform1f(lodLoc, lod);
1000 	}
1001 
1002 	glActiveTexture(GL_TEXTURE0);
1003 	glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture());
1004 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		m_wrapS);
1005 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		m_wrapT);
1006 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	m_minFilter);
1007 	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	m_magFilter);
1008 
1009 	{
1010 		const int texLoc = glGetUniformLocation(programID, "u_texture");
1011 		if (texLoc != -1)
1012 			glUniform1i(texLoc, 0);
1013 	}
1014 }
1015 
1016 // Renders one cube face with given parameters.
renderCell(int textureNdx,float lod,const Grid & grid) const1017 void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1018 {
1019 	setupShaderInputs(textureNdx, lod, grid);
1020 	glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1021 }
1022 
1023 // Computes reference for one cube face with given parameters.
computeReferenceCell(int textureNdx,float lod,const Grid & grid,tcu::Surface & dst,const Rect & dstRegion) const1024 void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1025 {
1026 	tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
1027 	sampler.seamlessCubeMap = m_isES3Capable;
1028 	computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion);
1029 }
1030 
VertexTextureTests(Context & context)1031 VertexTextureTests::VertexTextureTests (Context& context)
1032 	: TestCaseGroup(context, "vertex", "Vertex Texture Tests")
1033 {
1034 }
1035 
~VertexTextureTests(void)1036 VertexTextureTests::~VertexTextureTests(void)
1037 {
1038 }
1039 
init(void)1040 void VertexTextureTests::init (void)
1041 {
1042 	// 2D and cube map groups, and their filtering and wrap sub-groups.
1043 	TestCaseGroup* const group2D				= new TestCaseGroup(m_context, "2d",			"2D Vertex Texture Tests");
1044 	TestCaseGroup* const groupCube				= new TestCaseGroup(m_context, "cube",			"Cube Map Vertex Texture Tests");
1045 	TestCaseGroup* const filteringGroup2D		= new TestCaseGroup(m_context, "filtering",		"2D Vertex Texture Filtering Tests");
1046 	TestCaseGroup* const wrapGroup2D			= new TestCaseGroup(m_context, "wrap",			"2D Vertex Texture Wrap Tests");
1047 	TestCaseGroup* const filteringGroupCube		= new TestCaseGroup(m_context, "filtering",		"Cube Map Vertex Texture Filtering Tests");
1048 	TestCaseGroup* const wrapGroupCube			= new TestCaseGroup(m_context, "wrap",			"Cube Map Vertex Texture Wrap Tests");
1049 
1050 	group2D->addChild(filteringGroup2D);
1051 	group2D->addChild(wrapGroup2D);
1052 	groupCube->addChild(filteringGroupCube);
1053 	groupCube->addChild(wrapGroupCube);
1054 
1055 	addChild(group2D);
1056 	addChild(groupCube);
1057 
1058 	static const struct
1059 	{
1060 		const char*		name;
1061 		GLenum			mode;
1062 	} wrapModes[] =
1063 	{
1064 		{ "clamp",		GL_CLAMP_TO_EDGE	},
1065 		{ "repeat",		GL_REPEAT			},
1066 		{ "mirror",		GL_MIRRORED_REPEAT	}
1067 	};
1068 
1069 	static const struct
1070 	{
1071 		const char*		name;
1072 		GLenum			mode;
1073 	} minFilterModes[] =
1074 	{
1075 		{ "nearest",				GL_NEAREST					},
1076 		{ "linear",					GL_LINEAR					},
1077 		{ "nearest_mipmap_nearest",	GL_NEAREST_MIPMAP_NEAREST	},
1078 		{ "linear_mipmap_nearest",	GL_LINEAR_MIPMAP_NEAREST	},
1079 		{ "nearest_mipmap_linear",	GL_NEAREST_MIPMAP_LINEAR	},
1080 		{ "linear_mipmap_linear",	GL_LINEAR_MIPMAP_LINEAR		}
1081 	};
1082 
1083 	static const struct
1084 	{
1085 		const char*		name;
1086 		GLenum			mode;
1087 	} magFilterModes[] =
1088 	{
1089 		{ "nearest",	GL_NEAREST	},
1090 		{ "linear",		GL_LINEAR	}
1091 	};
1092 
1093 #define FOR_EACH(ITERATOR, ARRAY, BODY)	\
1094 	for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++)	\
1095 		BODY
1096 
1097 	// 2D cases.
1098 
1099 	FOR_EACH(minFilter,		minFilterModes,
1100 	FOR_EACH(magFilter,		magFilterModes,
1101 	FOR_EACH(wrapMode,		wrapModes,
1102 		{
1103 			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1104 
1105 			filteringGroup2D->addChild(new Vertex2DTextureCase(m_context,
1106 															   name.c_str(), "",
1107 															   minFilterModes[minFilter].mode,
1108 															   magFilterModes[magFilter].mode,
1109 															   wrapModes[wrapMode].mode,
1110 															   wrapModes[wrapMode].mode));
1111 		})))
1112 
1113 	FOR_EACH(wrapSMode,		wrapModes,
1114 	FOR_EACH(wrapTMode,		wrapModes,
1115 		{
1116 			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1117 
1118 			wrapGroup2D->addChild(new Vertex2DTextureCase(m_context,
1119 														  name.c_str(), "",
1120 														  GL_LINEAR_MIPMAP_LINEAR,
1121 														  GL_LINEAR,
1122 														  wrapModes[wrapSMode].mode,
1123 														  wrapModes[wrapTMode].mode));
1124 		}))
1125 
1126 	// Cube map cases.
1127 
1128 	FOR_EACH(minFilter,		minFilterModes,
1129 	FOR_EACH(magFilter,		magFilterModes,
1130 	FOR_EACH(wrapMode,		wrapModes,
1131 		{
1132 			const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1133 
1134 			filteringGroupCube->addChild(new VertexCubeTextureCase(m_context,
1135 																   name.c_str(), "",
1136 																   minFilterModes[minFilter].mode,
1137 																   magFilterModes[magFilter].mode,
1138 																   wrapModes[wrapMode].mode,
1139 																   wrapModes[wrapMode].mode));
1140 		})))
1141 
1142 	FOR_EACH(wrapSMode,		wrapModes,
1143 	FOR_EACH(wrapTMode,		wrapModes,
1144 		{
1145 			const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1146 
1147 			wrapGroupCube->addChild(new VertexCubeTextureCase(m_context,
1148 															  name.c_str(), "",
1149 															  GL_LINEAR_MIPMAP_LINEAR,
1150 															  GL_LINEAR,
1151 															  wrapModes[wrapSMode].mode,
1152 															  wrapModes[wrapTMode].mode));
1153 		}))
1154 }
1155 
1156 } // Functional
1157 } // gles2
1158 } // deqp
1159