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