Merge "Fix color change verification in dithering tests" into nougat-cts-dev am:...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fVertexTextureTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Vertex texture tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fVertexTextureTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluTexture.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "tcuVector.hpp"
30 #include "tcuMatrix.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuImageCompare.hpp"
33 #include "deRandom.hpp"
34 #include "deString.h"
35
36 #include <string>
37 #include <vector>
38
39 #include <limits>
40
41 #include "glw.h"
42
43 using tcu::TestLog;
44 using tcu::Vec2;
45 using tcu::Vec3;
46 using tcu::Vec4;
47 using tcu::IVec2;
48 using tcu::IVec3;
49 using tcu::IVec4;
50 using tcu::Mat3;
51 using std::string;
52 using std::vector;
53
54 namespace deqp
55 {
56
57 using namespace gls::TextureTestUtil;
58
59 using gls::TextureTestUtil::TEXTURETYPE_2D;
60 using gls::TextureTestUtil::TEXTURETYPE_CUBE;
61 using gls::TextureTestUtil::TEXTURETYPE_2D_ARRAY;
62 using gls::TextureTestUtil::TEXTURETYPE_3D;
63
64 namespace gles3
65 {
66 namespace Functional
67 {
68
69 static const int WIDTH_2D_ARRAY                         = 128;
70 static const int HEIGHT_2D_ARRAY                        = 128;
71 static const int LAYERS_2D_ARRAY                        = 8;
72
73 static const int WIDTH_3D                                       = 64;
74 static const int HEIGHT_3D                                      = 64;
75 static const int DEPTH_3D                                       = 64;
76
77 // The 2D case draws four images.
78 static const int MAX_2D_RENDER_WIDTH            = 128*2;
79 static const int MAX_2D_RENDER_HEIGHT           = 128*2;
80
81 // The cube map case draws four 3-by-2 image groups.
82 static const int MAX_CUBE_RENDER_WIDTH          = 28*2*3;
83 static const int MAX_CUBE_RENDER_HEIGHT         = 28*2*2;
84
85 static const int MAX_2D_ARRAY_RENDER_WIDTH      = 128*2;
86 static const int MAX_2D_ARRAY_RENDER_HEIGHT     = 128*2;
87
88 static const int MAX_3D_RENDER_WIDTH            = 128*2;
89 static const int MAX_3D_RENDER_HEIGHT           = 128*2;
90
91 static const int GRID_SIZE_2D                           = 127;
92 static const int GRID_SIZE_CUBE                         = 63;
93 static const int GRID_SIZE_2D_ARRAY                     = 127;
94 static const int GRID_SIZE_3D                           = 127;
95
96 // Helpers for making texture coordinates "safe", i.e. move them further from coordinate bounary.
97
98 // Moves x towards the closest K+targetFraction, where K is an integer.
99 // E.g. moveTowardsFraction(x, 0.5f) moves x away from integer boundaries.
100 static inline float moveTowardsFraction (float x, float targetFraction)
101 {
102         const float strictness = 0.5f;
103         DE_ASSERT(0.0f < strictness && strictness <= 1.0f);
104         DE_ASSERT(de::inBounds(targetFraction, 0.0f, 1.0f));
105         const float y = x + 0.5f - targetFraction;
106         return deFloatFloor(y) + deFloatFrac(y)*(1.0f-strictness) + strictness*0.5f - 0.5f + targetFraction;
107 }
108
109 static inline float safeCoord (float raw, int scale, float fraction)
110 {
111         const float scaleFloat = (float)scale;
112         return moveTowardsFraction(raw*scaleFloat, fraction) / scaleFloat;
113 }
114
115 template <int Size>
116 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)
117 {
118         tcu::Vector<float, Size> result;
119         for (int i = 0; i < Size; i++)
120                 result[i] = safeCoord(raw[i], scale[i], fraction[i]);
121         return result;
122 }
123
124 static inline Vec2 safe2DTexCoords (const Vec2& raw, const IVec2& textureSize)
125 {
126         return safeCoords(raw, textureSize, Vec2(0.5f));
127 }
128
129 static inline Vec3 safe2DArrayTexCoords (const Vec3& raw, const IVec3& textureSize)
130 {
131         return safeCoords(raw, textureSize, Vec3(0.5f, 0.5f, 0.0f));
132 }
133
134 static inline Vec3 safe3DTexCoords (const Vec3& raw, const IVec3& textureSize)
135 {
136         return safeCoords(raw, textureSize, Vec3(0.5f));
137 }
138
139 namespace
140 {
141
142 struct Rect
143 {
144                         Rect    (int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {}
145         IVec2   pos             (void) const { return IVec2(x, y); }
146         IVec2   size    (void) const { return IVec2(w, h); }
147
148         int             x;
149         int             y;
150         int             w;
151         int             h;
152 };
153
154 template <TextureType> struct TexTypeTcuClass;
155 template <> struct TexTypeTcuClass<TEXTURETYPE_2D>                      { typedef tcu::Texture2D                t; };
156 template <> struct TexTypeTcuClass<TEXTURETYPE_CUBE>            { typedef tcu::TextureCube              t; };
157 template <> struct TexTypeTcuClass<TEXTURETYPE_2D_ARRAY>        { typedef tcu::Texture2DArray   t; };
158 template <> struct TexTypeTcuClass<TEXTURETYPE_3D>                      { typedef tcu::Texture3D                t; };
159
160 template <TextureType> struct TexTypeSizeDims;
161 template <> struct TexTypeSizeDims<TEXTURETYPE_2D>                      { enum { V = 2 }; };
162 template <> struct TexTypeSizeDims<TEXTURETYPE_CUBE>            { enum { V = 2 }; };
163 template <> struct TexTypeSizeDims<TEXTURETYPE_2D_ARRAY>        { enum { V = 3 }; };
164 template <> struct TexTypeSizeDims<TEXTURETYPE_3D>                      { enum { V = 3 }; };
165
166 template <TextureType> struct TexTypeCoordDims;
167 template <> struct TexTypeCoordDims<TEXTURETYPE_2D>                     { enum { V = 2 }; };
168 template <> struct TexTypeCoordDims<TEXTURETYPE_CUBE>           { enum { V = 3 }; };
169 template <> struct TexTypeCoordDims<TEXTURETYPE_2D_ARRAY>       { enum { V = 3 }; };
170 template <> struct TexTypeCoordDims<TEXTURETYPE_3D>                     { enum { V = 3 }; };
171
172 template <TextureType TexType> struct TexTypeSizeIVec           { typedef tcu::Vector<int,              TexTypeSizeDims<TexType>::V>    t; };
173 template <TextureType TexType> struct TexTypeCoordVec           { typedef tcu::Vector<float,    TexTypeCoordDims<TexType>::V>   t; };
174
175 template <TextureType> struct TexTypeCoordParams;
176
177 template <> struct
178 TexTypeCoordParams<TEXTURETYPE_2D>
179 {
180         Vec2 scale;
181         Vec2 bias;
182
183         TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_) : scale(scale_), bias(bias_) {}
184 };
185
186 template <> struct
187 TexTypeCoordParams<TEXTURETYPE_CUBE>
188 {
189         Vec2                    scale;
190         Vec2                    bias;
191         tcu::CubeFace   face;
192
193         TexTypeCoordParams (const Vec2& scale_, const Vec2& bias_, tcu::CubeFace face_) : scale(scale_), bias(bias_), face(face_) {}
194 };
195
196 template <> struct
197 TexTypeCoordParams<TEXTURETYPE_2D_ARRAY>
198 {
199         Mat3 transform;
200
201         TexTypeCoordParams (const Mat3& transform_) : transform(transform_) {}
202 };
203
204 template <> struct
205 TexTypeCoordParams<TEXTURETYPE_3D>
206 {
207         Mat3 transform;
208
209         TexTypeCoordParams (const Mat3& transform_) : transform(transform_) {}
210 };
211
212 /*--------------------------------------------------------------------*//*!
213  * \brief Quad grid class containing position and texture coordinate data.
214  *
215  * A quad grid of size S means a grid consisting of S*S quads (S rows and
216  * S columns). The quads are rectangles with main axis aligned sides, and
217  * each consists of two triangles. Note that although there are only
218  * (S+1)*(S+1) distinct vertex positions, there are S*S*4 distinct vertices
219  * because we want texture coordinates to be constant across the vertices
220  * of a quad (to avoid interpolation issues), and thus each quad needs its
221  * own 4 vertices.
222  *
223  * Pointers returned by get*Ptr() are suitable for gl calls such as
224  * glVertexAttribPointer() (for position and tex coord) or glDrawElements()
225  * (for indices).
226  *//*--------------------------------------------------------------------*/
227 template <TextureType TexType>
228 class PosTexCoordQuadGrid
229 {
230 private:
231         enum { TEX_COORD_DIMS = TexTypeCoordDims <TexType>::V };
232         typedef typename TexTypeCoordVec<TexType>::t    TexCoordVec;
233         typedef typename TexTypeSizeIVec<TexType>::t    TexSizeIVec;
234         typedef TexTypeCoordParams<TexType>                             TexCoordParams;
235
236 public:
237                                                         PosTexCoordQuadGrid             (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords);
238
239         int                                             getSize                                 (void) const { return m_gridSize; }
240         Vec4                                    getQuadLDRU                             (int col, int row) const; //!< Vec4(leftX, downY, rightX, upY)
241         const TexCoordVec&              getQuadTexCoord                 (int col, int row) const;
242
243         int                                             getNumIndices                   (void) const { return m_gridSize*m_gridSize*3*2; }
244         const float*                    getPositionPtr                  (void) const { DE_STATIC_ASSERT(sizeof(Vec2) == 2*sizeof(float)); return (float*)&m_positions[0]; }
245         const float*                    getTexCoordPtr                  (void) const { DE_STATIC_ASSERT(sizeof(TexCoordVec) == TEX_COORD_DIMS*(int)sizeof(float)); return (float*)&m_texCoords[0]; }
246         const deUint16*                 getIndexPtr                             (void) const { return &m_indices[0]; }
247
248 private:
249         void                                    initializeTexCoords             (const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords);
250
251         const int                               m_gridSize;
252         vector<Vec2>                    m_positions;
253         vector<TexCoordVec>             m_texCoords;
254         vector<deUint16>                m_indices;
255 };
256
257 template <TextureType TexType>
258 Vec4 PosTexCoordQuadGrid<TexType>::getQuadLDRU (int col, int row) const
259 {
260         int ndx00 = (row*m_gridSize + col) * 4;
261         int ndx11 = ndx00 + 3;
262
263         return Vec4(m_positions[ndx00].x(),
264                                 m_positions[ndx00].y(),
265                                 m_positions[ndx11].x(),
266                                 m_positions[ndx11].y());
267 }
268
269 template <TextureType TexType>
270 const typename TexTypeCoordVec<TexType>::t& PosTexCoordQuadGrid<TexType>::getQuadTexCoord (int col, int row) const
271 {
272         return m_texCoords[(row*m_gridSize + col) * 4];
273 }
274
275 template <TextureType TexType>
276 PosTexCoordQuadGrid<TexType>::PosTexCoordQuadGrid (int gridSize, const IVec2& renderSize, const TexSizeIVec& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
277         : m_gridSize(gridSize)
278 {
279         DE_ASSERT(m_gridSize > 0 && m_gridSize*m_gridSize <= (int)std::numeric_limits<deUint16>::max() + 1);
280
281         const float gridSizeFloat = (float)m_gridSize;
282
283         m_positions.reserve(m_gridSize*m_gridSize*4);
284         m_indices.reserve(m_gridSize*m_gridSize*3*2);
285
286         for (int y = 0; y < m_gridSize; y++)
287         for (int x = 0; x < m_gridSize; x++)
288         {
289                 float fx0 = (float)(x+0) / gridSizeFloat;
290                 float fx1 = (float)(x+1) / gridSizeFloat;
291                 float fy0 = (float)(y+0) / gridSizeFloat;
292                 float fy1 = (float)(y+1) / gridSizeFloat;
293
294                 Vec2 quadVertices[4] = { Vec2(fx0, fy0), Vec2(fx1, fy0), Vec2(fx0, fy1), Vec2(fx1, fy1) };
295
296                 int firstNdx = (int)m_positions.size();
297
298                 for (int i = 0; i < DE_LENGTH_OF_ARRAY(quadVertices); i++)
299                         m_positions.push_back(safeCoords(quadVertices[i], renderSize, Vec2(0.0f)) * 2.0f - 1.0f);
300
301                 m_indices.push_back(deUint16(firstNdx + 0));
302                 m_indices.push_back(deUint16(firstNdx + 1));
303                 m_indices.push_back(deUint16(firstNdx + 2));
304
305                 m_indices.push_back(deUint16(firstNdx + 1));
306                 m_indices.push_back(deUint16(firstNdx + 3));
307                 m_indices.push_back(deUint16(firstNdx + 2));
308         }
309
310         m_texCoords.reserve(m_gridSize*m_gridSize*4);
311         initializeTexCoords(textureSize, texCoordParams, useSafeTexCoords);
312
313         DE_ASSERT((int)m_positions.size() == m_gridSize*m_gridSize*4);
314         DE_ASSERT((int)m_indices.size() == m_gridSize*m_gridSize*3*2);
315         DE_ASSERT((int)m_texCoords.size() == m_gridSize*m_gridSize*4);
316 }
317
318 template <>
319 void PosTexCoordQuadGrid<TEXTURETYPE_2D>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
320 {
321         DE_ASSERT(m_texCoords.empty());
322
323         const float gridSizeFloat = (float)m_gridSize;
324
325         for (int y = 0; y < m_gridSize; y++)
326         for (int x = 0; x < m_gridSize; x++)
327         {
328                 Vec2 rawCoord = Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) * texCoordParams.scale + texCoordParams.bias;
329
330                 for (int i = 0; i < 4; i++)
331                         m_texCoords.push_back(useSafeTexCoords ? safe2DTexCoords(rawCoord, textureSize) : rawCoord);
332         }
333 }
334
335 template <>
336 void PosTexCoordQuadGrid<TEXTURETYPE_CUBE>::initializeTexCoords (const IVec2& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
337 {
338         DE_ASSERT(m_texCoords.empty());
339
340         const float             gridSizeFloat   = (float)m_gridSize;
341         vector<float>   texBoundaries;
342         computeQuadTexCoordCube(texBoundaries, texCoordParams.face);
343         const Vec3              coordA                  = Vec3(texBoundaries[0], texBoundaries[1], texBoundaries[2]);
344         const Vec3              coordB                  = Vec3(texBoundaries[3], texBoundaries[4], texBoundaries[5]);
345         const Vec3              coordC                  = Vec3(texBoundaries[6], texBoundaries[7], texBoundaries[8]);
346         const Vec3              coordAB                 = coordB - coordA;
347         const Vec3              coordAC                 = coordC - coordA;
348
349         for (int y = 0; y < m_gridSize; y++)
350         for (int x = 0; x < m_gridSize; x++)
351         {
352                 const Vec2 rawFaceCoord         = texCoordParams.scale * Vec2((float)x / gridSizeFloat, (float)y / gridSizeFloat) + texCoordParams.bias;
353                 const Vec2 safeFaceCoord        = useSafeTexCoords ? safe2DTexCoords(rawFaceCoord, textureSize) : rawFaceCoord;
354                 const Vec3 texCoord                     = coordA + coordAC*safeFaceCoord.x() + coordAB*safeFaceCoord.y();
355
356                 for (int i = 0; i < 4; i++)
357                         m_texCoords.push_back(texCoord);
358         }
359 }
360
361 template <>
362 void PosTexCoordQuadGrid<TEXTURETYPE_2D_ARRAY>::initializeTexCoords (const IVec3& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
363 {
364         DE_ASSERT(m_texCoords.empty());
365
366         const float gridSizeFloat = (float)m_gridSize;
367
368         for (int y = 0; y < m_gridSize; y++)
369         for (int x = 0; x < m_gridSize; x++)
370         {
371                 const Vec3 rawCoord = texCoordParams.transform * Vec3((float)x / gridSizeFloat, (float)y / gridSizeFloat, 1.0f);
372
373                 for (int i = 0; i < 4; i++)
374                         m_texCoords.push_back(useSafeTexCoords ? safe2DArrayTexCoords(rawCoord, textureSize) : rawCoord);
375         }
376 }
377
378 template <>
379 void PosTexCoordQuadGrid<TEXTURETYPE_3D>::initializeTexCoords (const IVec3& textureSize, const TexCoordParams& texCoordParams, bool useSafeTexCoords)
380 {
381         DE_ASSERT(m_texCoords.empty());
382
383         const float gridSizeFloat = (float)m_gridSize;
384
385         for (int y = 0; y < m_gridSize; y++)
386         for (int x = 0; x < m_gridSize; x++)
387         {
388                 Vec3 rawCoord = texCoordParams.transform * Vec3((float)x / gridSizeFloat, (float)y / gridSizeFloat, 1.0f);
389
390                 for (int i = 0; i < 4; i++)
391                         m_texCoords.push_back(useSafeTexCoords ? safe3DTexCoords(rawCoord, textureSize) : rawCoord);
392         }
393 }
394
395 } // anonymous
396
397 static inline bool isLevelNearest (deUint32 filter)
398 {
399         return filter == GL_NEAREST || filter == GL_NEAREST_MIPMAP_NEAREST || filter == GL_NEAREST_MIPMAP_LINEAR;
400 }
401
402 static inline IVec2 getTextureSize (const glu::Texture2D& tex)
403 {
404         const tcu::Texture2D& ref = tex.getRefTexture();
405         return IVec2(ref.getWidth(), ref.getHeight());
406 }
407
408 static inline IVec2 getTextureSize (const glu::TextureCube& tex)
409 {
410         const tcu::TextureCube& ref = tex.getRefTexture();
411         return IVec2(ref.getSize(), ref.getSize());
412 }
413
414 static inline IVec3 getTextureSize (const glu::Texture2DArray& tex)
415 {
416         const tcu::Texture2DArray& ref = tex.getRefTexture();
417         return IVec3(ref.getWidth(), ref.getHeight(), ref.getNumLayers());
418 }
419
420 static inline IVec3 getTextureSize (const glu::Texture3D& tex)
421 {
422         const tcu::Texture3D& ref = tex.getRefTexture();
423         return IVec3(ref.getWidth(), ref.getHeight(), ref.getDepth());
424 }
425
426 template <TextureType TexType>
427 static void setPixelColors (const vector<Vec4>& quadColors, const Rect& region, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst)
428 {
429         const int gridSize = grid.getSize();
430
431         for (int y = 0; y < gridSize; y++)
432         for (int x = 0; x < gridSize; x++)
433         {
434                 const Vec4      color   = quadColors[y*gridSize + x];
435                 const Vec4      ldru    = grid.getQuadLDRU(x, y) * 0.5f + 0.5f; // [-1, 1] -> [0, 1]
436                 const int       ix0             = deCeilFloatToInt32(ldru.x() * (float)region.w - 0.5f);
437                 const int       ix1             = deCeilFloatToInt32(ldru.z() * (float)region.w - 0.5f);
438                 const int       iy0             = deCeilFloatToInt32(ldru.y() * (float)region.h - 0.5f);
439                 const int       iy1             = deCeilFloatToInt32(ldru.w() * (float)region.h - 0.5f);
440
441                 for (int iy = iy0; iy < iy1; iy++)
442                 for (int ix = ix0; ix < ix1; ix++)
443                 {
444                         DE_ASSERT(deInBounds32(ix + region.x, 0, dst.getWidth()));
445                         DE_ASSERT(deInBounds32(iy + region.y, 0, dst.getHeight()));
446
447                         dst.setPixel(ix + region.x, iy + region.y, tcu::RGBA(color));
448                 }
449         }
450 }
451
452 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); }
453 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); }
454 static inline Vec4 sample (const tcu::Texture2DArray&   tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); }
455 static inline Vec4 sample (const tcu::Texture3D&                tex, const Vec3& coord, float lod, const tcu::Sampler& sam) { return tex.sample(sam, coord.x(), coord.y(), coord.z(), lod); }
456
457 template <TextureType TexType>
458 void computeReference (const typename TexTypeTcuClass<TexType>::t& texture, float lod, const tcu::Sampler& sampler, const PosTexCoordQuadGrid<TexType>& grid, tcu::Surface& dst, const Rect& dstRegion)
459 {
460         const int               gridSize        = grid.getSize();
461         vector<Vec4>    quadColors      (gridSize*gridSize);
462
463         for (int y = 0; y < gridSize; y++)
464         for (int x = 0; x < gridSize; x++)
465         {
466                 const int                                                                               ndx             = y*gridSize + x;
467                 const typename TexTypeCoordVec<TexType>::t&             coord   = grid.getQuadTexCoord(x, y);
468
469                 quadColors[ndx] = sample(texture, coord, lod, sampler);
470         }
471
472         setPixelColors(quadColors, dstRegion, grid, dst);
473 }
474
475 static bool compareImages (const glu::RenderContext& renderCtx, tcu::TestLog& log, const tcu::Surface& ref, const tcu::Surface& res)
476 {
477         DE_ASSERT(renderCtx.getRenderTarget().getNumSamples() == 0);
478
479         const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(15,15,15,15);
480         return tcu::pixelThresholdCompare(log, "Result", "Image compare result", ref, res, threshold, tcu::COMPARE_LOG_RESULT);
481 }
482
483 class Vertex2DTextureCase : public TestCase
484 {
485 public:
486                                                                 Vertex2DTextureCase             (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
487                                                                 ~Vertex2DTextureCase    (void);
488
489         void                                            init                                    (void);
490         void                                            deinit                                  (void);
491         IterateResult                           iterate                                 (void);
492
493 private:
494         typedef PosTexCoordQuadGrid<TEXTURETYPE_2D> Grid;
495
496                                                                 Vertex2DTextureCase             (const Vertex2DTextureCase& other);
497         Vertex2DTextureCase&            operator=                               (const Vertex2DTextureCase& other);
498
499         float                                           calculateLod                    (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const;
500         void                                            setupShaderInputs               (int textureNdx, float lod, const Grid& grid) const;
501         void                                            renderCell                              (int textureNdx, float lod, const Grid& grid) const;
502         void                                            computeReferenceCell    (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
503
504         const deUint32                          m_minFilter;
505         const deUint32                          m_magFilter;
506         const deUint32                          m_wrapS;
507         const deUint32                          m_wrapT;
508
509         const glu::ShaderProgram*       m_program;
510         glu::Texture2D*                         m_textures[2];  // 2 textures, a gradient texture and a grid texture.
511 };
512
513 Vertex2DTextureCase::Vertex2DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
514         : TestCase                              (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
515         , m_minFilter                   (minFilter)
516         , m_magFilter                   (magFilter)
517         , m_wrapS                               (wrapS)
518         , m_wrapT                               (wrapT)
519         , m_program                             (DE_NULL)
520 {
521         m_textures[0] = DE_NULL;
522         m_textures[1] = DE_NULL;
523 }
524
525 Vertex2DTextureCase::~Vertex2DTextureCase(void)
526 {
527         Vertex2DTextureCase::deinit();
528 }
529
530 void Vertex2DTextureCase::init (void)
531 {
532         const char* const vertexShader =
533                 "#version 300 es\n"
534                 "in highp vec2 a_position;\n"
535                 "in highp vec2 a_texCoord;\n"
536                 "uniform highp sampler2D u_texture;\n"
537                 "uniform highp float u_lod;\n"
538                 "out mediump vec4 v_color;\n"
539                 "\n"
540                 "void main()\n"
541                 "{\n"
542                 "       gl_Position = vec4(a_position, 0.0, 1.0);\n"
543                 "       v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
544                 "}\n";
545
546         const char* const fragmentShader =
547                 "#version 300 es\n"
548                 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
549                 "in mediump vec4 v_color;\n"
550                 "\n"
551                 "void main()\n"
552                 "{\n"
553                 "       dEQP_FragColor = v_color;\n"
554                 "}\n";
555
556         if (m_context.getRenderTarget().getNumSamples() != 0)
557                 throw tcu::NotSupportedError("MSAA config not supported by this test");
558
559         DE_ASSERT(!m_program);
560         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
561
562         if(!m_program->isOk())
563         {
564                 m_testCtx.getLog() << *m_program;
565
566                 GLint maxVertexTextures;
567                 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
568
569                 if (maxVertexTextures < 1)
570                         throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
571                 else
572                         TCU_FAIL("Failed to compile shader");
573         }
574
575         // Make the textures.
576         try
577         {
578                 // Compute suitable power-of-two sizes (for mipmaps).
579                 const int texWidth              = 1 << deLog2Ceil32(MAX_2D_RENDER_WIDTH / 2);
580                 const int texHeight             = 1 << deLog2Ceil32(MAX_2D_RENDER_HEIGHT / 2);
581
582                 for (int i = 0; i < 2; i++)
583                 {
584                         DE_ASSERT(!m_textures[i]);
585                         m_textures[i] = new glu::Texture2D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
586                 }
587
588                 const bool                                              mipmaps         = (deIsPowerOfTwo32(texWidth) && deIsPowerOfTwo32(texHeight));
589                 const int                                               numLevels       = mipmaps ? deLog2Floor32(de::max(texWidth, texHeight))+1 : 1;
590                 const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
591                 const Vec4                                              cBias           = fmtInfo.valueMin;
592                 const Vec4                                              cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
593
594                 // Fill first with gradient texture.
595                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
596                 {
597                         const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
598                         const Vec4 gMax = Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
599
600                         m_textures[0]->getRefTexture().allocLevel(levelNdx);
601                         tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
602                 }
603
604                 // Fill second with grid texture.
605                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
606                 {
607                         const deUint32 step             = 0x00ffffff / numLevels;
608                         const deUint32 rgb              = step*levelNdx;
609                         const deUint32 colorA   = 0xff000000 | rgb;
610                         const deUint32 colorB   = 0xff000000 | ~rgb;
611
612                         m_textures[1]->getRefTexture().allocLevel(levelNdx);
613                         tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
614                 }
615
616                 // Upload.
617                 for (int i = 0; i < 2; i++)
618                         m_textures[i]->upload();
619         }
620         catch (const std::exception&)
621         {
622                 // Clean up to save memory.
623                 Vertex2DTextureCase::deinit();
624                 throw;
625         }
626 }
627
628 void Vertex2DTextureCase::deinit (void)
629 {
630         for (int i = 0; i < 2; i++)
631         {
632                 delete m_textures[i];
633                 m_textures[i] = DE_NULL;
634         }
635
636         delete m_program;
637         m_program = DE_NULL;
638 }
639
640 float Vertex2DTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
641 {
642         const tcu::Texture2D&           refTexture      = m_textures[textureNdx]->getRefTexture();
643         const Vec2                                      srcSize         = Vec2((float)refTexture.getWidth(), (float)refTexture.getHeight());
644         const Vec2                                      sizeRatio       = texScale*srcSize / dstSize;
645
646         // \note In this particular case dv/dx and du/dy are zero, simplifying the expression.
647         return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
648 }
649
650 Vertex2DTextureCase::IterateResult Vertex2DTextureCase::iterate (void)
651 {
652         const int       viewportWidth           = deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_RENDER_WIDTH);
653         const int       viewportHeight          = deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_RENDER_HEIGHT);
654
655         const int       viewportXOffsetMax      = m_context.getRenderTarget().getWidth() - viewportWidth;
656         const int       viewportYOffsetMax      = m_context.getRenderTarget().getHeight() - viewportHeight;
657
658         de::Random      rnd                                     (deStringHash(getName()));
659
660         const int       viewportXOffset         = rnd.getInt(0, viewportXOffsetMax);
661         const int       viewportYOffset         = rnd.getInt(0, viewportYOffsetMax);
662
663         glUseProgram(m_program->getProgram());
664
665         // Divide viewport into 4 cells.
666         const int leftWidth             = viewportWidth / 2;
667         const int rightWidth    = viewportWidth - leftWidth;
668         const int bottomHeight  = viewportHeight / 2;
669         const int topHeight             = viewportHeight - bottomHeight;
670
671         // Clear.
672         glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
673         glClear(GL_COLOR_BUFFER_BIT);
674
675         // Texture scaling and offsetting vectors.
676         const Vec2 texMinScale          (+1.8f, +1.8f);
677         const Vec2 texMinOffset         (-0.3f, -0.2f);
678         const Vec2 texMagScale          (+0.3f, +0.3f);
679         const Vec2 texMagOffset         (+0.9f, +0.8f);
680
681         // Surface for the reference image.
682         tcu::Surface refImage(viewportWidth, viewportHeight);
683
684         {
685                 const struct Render
686                 {
687                         const Rect      region;
688                         int                     textureNdx;
689                         const Vec2      texCoordScale;
690                         const Vec2      texCoordOffset;
691                         Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
692                 } renders[] =
693                 {
694                         Render(Rect(0,                          0,                              leftWidth,      bottomHeight),  0, texMinScale, texMinOffset),
695                         Render(Rect(leftWidth,          0,                              rightWidth,     bottomHeight),  0, texMagScale, texMagOffset),
696                         Render(Rect(0,                          bottomHeight,   leftWidth,      topHeight),             1, texMinScale, texMinOffset),
697                         Render(Rect(leftWidth,          bottomHeight,   rightWidth,     topHeight),             1, texMagScale, texMagOffset)
698                 };
699
700                 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
701                 {
702                         const Render&   rend                            = renders[renderNdx];
703                         const float             lod                                     = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
704                         const bool              useSafeTexCoords        = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
705                         const Grid              grid                            (GRID_SIZE_2D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
706                                                                                                  TexTypeCoordParams<TEXTURETYPE_2D>(rend.texCoordScale, rend.texCoordOffset), useSafeTexCoords);
707
708                         glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
709                         renderCell                              (rend.textureNdx, lod, grid);
710                         computeReferenceCell    (rend.textureNdx, lod, grid, refImage, rend.region);
711                 }
712         }
713
714         // Read back rendered results.
715         tcu::Surface resImage(viewportWidth, viewportHeight);
716         glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
717
718         glUseProgram(0);
719
720         // Compare and log.
721         {
722                 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
723
724                 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
725                                                                 isOk ? "Pass"                           : "Image comparison failed");
726         }
727
728         return STOP;
729 }
730
731 void Vertex2DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
732 {
733         const deUint32 programID = m_program->getProgram();
734
735         // SETUP ATTRIBUTES.
736
737         {
738                 const int positionLoc = glGetAttribLocation(programID, "a_position");
739                 if (positionLoc != -1)
740                 {
741                         glEnableVertexAttribArray(positionLoc);
742                         glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
743                 }
744         }
745
746         {
747                 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
748                 if (texCoordLoc != -1)
749                 {
750                         glEnableVertexAttribArray(texCoordLoc);
751                         glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
752                 }
753         }
754
755         // SETUP UNIFORMS.
756
757         {
758                 const int lodLoc = glGetUniformLocation(programID, "u_lod");
759                 if (lodLoc != -1)
760                         glUniform1f(lodLoc, lod);
761         }
762
763         glActiveTexture(GL_TEXTURE0);
764         glBindTexture(GL_TEXTURE_2D, m_textures[textureNdx]->getGLTexture());
765         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,               m_wrapS);
766         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,               m_wrapT);
767         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,   m_minFilter);
768         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,   m_magFilter);
769
770         {
771                 const int texLoc = glGetUniformLocation(programID, "u_texture");
772                 if (texLoc != -1)
773                         glUniform1i(texLoc, 0);
774         }
775 }
776
777 // Renders one sub-image with given parameters.
778 void Vertex2DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
779 {
780         setupShaderInputs(textureNdx, lod, grid);
781         glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
782 }
783
784 void Vertex2DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
785 {
786         computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion);
787 }
788
789 class VertexCubeTextureCase : public TestCase
790 {
791 public:
792                                                                 VertexCubeTextureCase   (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
793                                                                 ~VertexCubeTextureCase  (void);
794
795         void                                            init                                    (void);
796         void                                            deinit                                  (void);
797         IterateResult                           iterate                                 (void);
798
799 private:
800         typedef PosTexCoordQuadGrid<TEXTURETYPE_CUBE> Grid;
801
802                                                                 VertexCubeTextureCase   (const VertexCubeTextureCase& other);
803         VertexCubeTextureCase&          operator=                               (const VertexCubeTextureCase& other);
804
805         float                                           calculateLod                    (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const;
806         void                                            setupShaderInputs               (int textureNdx, float lod, const Grid& grid) const;
807         void                                            renderCell                              (int textureNdx, float lod, const Grid& grid) const;
808         void                                            computeReferenceCell    (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
809
810         const deUint32                          m_minFilter;
811         const deUint32                          m_magFilter;
812         const deUint32                          m_wrapS;
813         const deUint32                          m_wrapT;
814
815         const glu::ShaderProgram*       m_program;
816         glu::TextureCube*                       m_textures[2];  // 2 textures, a gradient texture and a grid texture.
817 };
818
819 VertexCubeTextureCase::VertexCubeTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
820         : TestCase                              (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
821         , m_minFilter                   (minFilter)
822         , m_magFilter                   (magFilter)
823         , m_wrapS                               (wrapS)
824         , m_wrapT                               (wrapT)
825         , m_program                             (DE_NULL)
826 {
827         m_textures[0] = DE_NULL;
828         m_textures[1] = DE_NULL;
829 }
830
831 VertexCubeTextureCase::~VertexCubeTextureCase(void)
832 {
833         VertexCubeTextureCase::deinit();
834 }
835
836 void VertexCubeTextureCase::init (void)
837 {
838         const char* const vertexShader =
839                 "#version 300 es\n"
840                 "in highp vec2 a_position;\n"
841                 "in highp vec3 a_texCoord;\n"
842                 "uniform highp samplerCube u_texture;\n"
843                 "uniform highp float u_lod;\n"
844                 "out mediump vec4 v_color;\n"
845                 "\n"
846                 "void main()\n"
847                 "{\n"
848                 "       gl_Position = vec4(a_position, 0.0, 1.0);\n"
849                 "       v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
850                 "}\n";
851
852         const char* const fragmentShader =
853                 "#version 300 es\n"
854                 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
855                 "in mediump vec4 v_color;\n"
856                 "\n"
857                 "void main()\n"
858                 "{\n"
859                 "       dEQP_FragColor = v_color;\n"
860                 "}\n";
861
862         if (m_context.getRenderTarget().getNumSamples() != 0)
863                 throw tcu::NotSupportedError("MSAA config not supported by this test");
864
865         DE_ASSERT(!m_program);
866         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
867
868         if(!m_program->isOk())
869         {
870                 m_testCtx.getLog() << *m_program;
871
872                 GLint maxVertexTextures;
873                 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
874
875                 if (maxVertexTextures < 1)
876                         throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
877                 else
878                         TCU_FAIL("Failed to compile shader");
879         }
880
881         // Make the textures.
882         try
883         {
884                 // Compute suitable power-of-two sizes (for mipmaps).
885                 const int texWidth              = 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2);
886                 const int texHeight             = 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2);
887
888                 DE_ASSERT(texWidth == texHeight);
889                 DE_UNREF(texHeight);
890
891                 for (int i = 0; i < 2; i++)
892                 {
893                         DE_ASSERT(!m_textures[i]);
894                         m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth);
895                 }
896
897                 const bool                                              mipmaps         = deIsPowerOfTwo32(texWidth) != DE_FALSE;
898                 const int                                               numLevels       = mipmaps ? deLog2Floor32(texWidth)+1 : 1;
899                 const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
900                 const Vec4                                              cBias           = fmtInfo.valueMin;
901                 const Vec4                                              cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
902
903                 // Fill first with gradient texture.
904                 static const Vec4 gradients[tcu::CUBEFACE_LAST][2] =
905                 {
906                         { Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
907                         { Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
908                         { Vec4(-1.0f,  0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
909                         { Vec4(-1.0f, -1.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
910                         { Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
911                         { Vec4( 0.0f,  0.0f,  0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
912                 };
913                 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
914                 {
915                         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
916                         {
917                                 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
918                                 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
919                         }
920                 }
921
922                 // Fill second with grid texture.
923                 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
924                 {
925                         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
926                         {
927                                 const deUint32 step             = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
928                                 const deUint32 rgb              = step*levelNdx*face;
929                                 const deUint32 colorA   = 0xff000000 | rgb;
930                                 const deUint32 colorB   = 0xff000000 | ~rgb;
931
932                                 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
933                                 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
934                         }
935                 }
936
937                 // Upload.
938                 for (int i = 0; i < 2; i++)
939                         m_textures[i]->upload();
940         }
941         catch (const std::exception&)
942         {
943                 // Clean up to save memory.
944                 VertexCubeTextureCase::deinit();
945                 throw;
946         }
947 }
948
949 void VertexCubeTextureCase::deinit (void)
950 {
951         for (int i = 0; i < 2; i++)
952         {
953                 delete m_textures[i];
954                 m_textures[i] = DE_NULL;
955         }
956
957         delete m_program;
958         m_program = DE_NULL;
959 }
960
961 float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
962 {
963         const tcu::TextureCube&         refTexture      = m_textures[textureNdx]->getRefTexture();
964         const Vec2                                      srcSize         = Vec2((float)refTexture.getSize(), (float)refTexture.getSize());
965         const Vec2                                      sizeRatio       = texScale*srcSize / dstSize;
966
967         // \note In this particular case, dv/dx and du/dy are zero, simplifying the expression.
968         return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
969 }
970
971 VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void)
972 {
973         const int       viewportWidth           = deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH);
974         const int       viewportHeight          = deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT);
975
976         const int       viewportXOffsetMax      = m_context.getRenderTarget().getWidth() - viewportWidth;
977         const int       viewportYOffsetMax      = m_context.getRenderTarget().getHeight() - viewportHeight;
978
979         de::Random      rnd                                     (deStringHash(getName()));
980
981         const int       viewportXOffset         = rnd.getInt(0, viewportXOffsetMax);
982         const int       viewportYOffset         = rnd.getInt(0, viewportYOffsetMax);
983
984         glUseProgram(m_program->getProgram());
985
986         // Divide viewport into 4 areas.
987         const int leftWidth             = viewportWidth / 2;
988         const int rightWidth    = viewportWidth - leftWidth;
989         const int bottomHeight  = viewportHeight / 2;
990         const int topHeight             = viewportHeight - bottomHeight;
991
992         // Clear.
993         glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
994         glClear(GL_COLOR_BUFFER_BIT);
995
996         // Texture scaling and offsetting vectors.
997         const Vec2 texMinScale          (1.0f, 1.0f);
998         const Vec2 texMinOffset         (0.0f, 0.0f);
999         const Vec2 texMagScale          (0.3f, 0.3f);
1000         const Vec2 texMagOffset         (0.5f, 0.3f);
1001
1002         // Surface for the reference image.
1003         tcu::Surface refImage(viewportWidth, viewportHeight);
1004
1005         // Each of the four areas is divided into 6 cells.
1006         const int defCellWidth  = viewportWidth / 2 / 3;
1007         const int defCellHeight = viewportHeight / 2 / 2;
1008
1009         for (int i = 0; i < tcu::CUBEFACE_LAST; i++)
1010         {
1011                 const int       cellOffsetX                     = defCellWidth * (i % 3);
1012                 const int       cellOffsetY                     = defCellHeight * (i / 3);
1013                 const bool      isRightmostCell         = i == 2 || i == 5;
1014                 const bool      isTopCell                       = i >= 3;
1015                 const int       leftCellWidth           = isRightmostCell       ? leftWidth             - cellOffsetX : defCellWidth;
1016                 const int       rightCellWidth          = isRightmostCell       ? rightWidth    - cellOffsetX : defCellWidth;
1017                 const int       bottomCellHeight        = isTopCell                     ? bottomHeight  - cellOffsetY : defCellHeight;
1018                 const int       topCellHeight           = isTopCell                     ? topHeight             - cellOffsetY : defCellHeight;
1019
1020                 const struct Render
1021                 {
1022                         const Rect      region;
1023                         int                     textureNdx;
1024                         const Vec2      texCoordScale;
1025                         const Vec2      texCoordOffset;
1026                         Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
1027                 } renders[] =
1028                 {
1029                         Render(Rect(cellOffsetX + 0,                    cellOffsetY + 0,                                leftCellWidth,  bottomCellHeight),      0, texMinScale, texMinOffset),
1030                         Render(Rect(cellOffsetX + leftWidth,    cellOffsetY + 0,                                rightCellWidth, bottomCellHeight),      0, texMagScale, texMagOffset),
1031                         Render(Rect(cellOffsetX + 0,                    cellOffsetY + bottomHeight,             leftCellWidth,  topCellHeight),         1, texMinScale, texMinOffset),
1032                         Render(Rect(cellOffsetX + leftWidth,    cellOffsetY + bottomHeight,             rightCellWidth, topCellHeight),         1, texMagScale, texMagOffset)
1033                 };
1034
1035                 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
1036                 {
1037                         const Render&   rend                            = renders[renderNdx];
1038                         const float             lod                                     = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
1039                         const bool              useSafeTexCoords        = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
1040                         const Grid              grid                            (GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
1041                                                                                                  TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords);
1042
1043                         glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
1044                         renderCell                              (rend.textureNdx, lod, grid);
1045                         computeReferenceCell    (rend.textureNdx, lod, grid, refImage, rend.region);
1046                 }
1047         }
1048
1049         // Read back rendered results.
1050         tcu::Surface resImage(viewportWidth, viewportHeight);
1051         glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
1052
1053         glUseProgram(0);
1054
1055         // Compare and log.
1056         {
1057                 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
1058
1059                 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
1060                                                                 isOk ? "Pass"                           : "Image comparison failed");
1061         }
1062
1063         return STOP;
1064 }
1065
1066 void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
1067 {
1068         const deUint32 programID = m_program->getProgram();
1069
1070         // SETUP ATTRIBUTES.
1071
1072         {
1073                 const int positionLoc = glGetAttribLocation(programID, "a_position");
1074                 if (positionLoc != -1)
1075                 {
1076                         glEnableVertexAttribArray(positionLoc);
1077                         glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
1078                 }
1079         }
1080
1081         {
1082                 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
1083                 if (texCoordLoc != -1)
1084                 {
1085                         glEnableVertexAttribArray(texCoordLoc);
1086                         glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
1087                 }
1088         }
1089
1090         // SETUP UNIFORMS.
1091
1092         {
1093                 const int lodLoc = glGetUniformLocation(programID, "u_lod");
1094                 if (lodLoc != -1)
1095                         glUniform1f(lodLoc, lod);
1096         }
1097
1098         glActiveTexture(GL_TEXTURE0);
1099         glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture());
1100         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,         m_wrapS);
1101         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,         m_wrapT);
1102         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,     m_minFilter);
1103         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,     m_magFilter);
1104
1105         {
1106                 const int texLoc = glGetUniformLocation(programID, "u_texture");
1107                 if (texLoc != -1)
1108                         glUniform1i(texLoc, 0);
1109         }
1110 }
1111
1112 // Renders one cube face with given parameters.
1113 void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1114 {
1115         setupShaderInputs(textureNdx, lod, grid);
1116         glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1117 }
1118
1119 // Computes reference for one cube face with given parameters.
1120 void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1121 {
1122         tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
1123         sampler.seamlessCubeMap = true;
1124         computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion);
1125 }
1126
1127 class Vertex2DArrayTextureCase : public TestCase
1128 {
1129 public:
1130                                                                 Vertex2DArrayTextureCase        (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT);
1131                                                                 ~Vertex2DArrayTextureCase       (void);
1132
1133         void                                            init                                            (void);
1134         void                                            deinit                                          (void);
1135         IterateResult                           iterate                                         (void);
1136
1137 private:
1138         typedef PosTexCoordQuadGrid<TEXTURETYPE_2D_ARRAY> Grid;
1139
1140                                                                 Vertex2DArrayTextureCase        (const Vertex2DArrayTextureCase& other);
1141         Vertex2DArrayTextureCase&       operator=                                       (const Vertex2DArrayTextureCase& other);
1142
1143         float                                           calculateLod                            (const Mat3& transf, const Vec2& dstSize, int textureNdx) const;
1144         void                                            setupShaderInputs                       (int textureNdx, float lod, const Grid& grid) const;
1145         void                                            renderCell                                      (int textureNdx, float lod, const Grid& grid) const;
1146         void                                            computeReferenceCell            (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
1147
1148         const deUint32                          m_minFilter;
1149         const deUint32                          m_magFilter;
1150         const deUint32                          m_wrapS;
1151         const deUint32                          m_wrapT;
1152
1153         const glu::ShaderProgram*       m_program;
1154         glu::Texture2DArray*            m_textures[2];  // 2 textures, a gradient texture and a grid texture.
1155 };
1156
1157 Vertex2DArrayTextureCase::Vertex2DArrayTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT)
1158         : TestCase                              (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
1159         , m_minFilter                   (minFilter)
1160         , m_magFilter                   (magFilter)
1161         , m_wrapS                               (wrapS)
1162         , m_wrapT                               (wrapT)
1163         , m_program                             (DE_NULL)
1164 {
1165         m_textures[0] = DE_NULL;
1166         m_textures[1] = DE_NULL;
1167 }
1168
1169 Vertex2DArrayTextureCase::~Vertex2DArrayTextureCase(void)
1170 {
1171         Vertex2DArrayTextureCase::deinit();
1172 }
1173
1174 void Vertex2DArrayTextureCase::init (void)
1175 {
1176         const char* const vertexShaderSource =
1177                 "#version 300 es\n"
1178                 "in highp vec2 a_position;\n"
1179                 "in highp vec3 a_texCoord;\n"
1180                 "uniform highp sampler2DArray u_texture;\n"
1181                 "uniform highp float u_lod;\n"
1182                 "out mediump vec4 v_color;\n"
1183                 "\n"
1184                 "void main()\n"
1185                 "{\n"
1186                 "       gl_Position = vec4(a_position, 0.0, 1.0);\n"
1187                 "       v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
1188                 "}\n";
1189
1190         const char* const fragmentShaderSource =
1191                 "#version 300 es\n"
1192                 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
1193                 "in mediump vec4 v_color;\n"
1194                 "\n"
1195                 "void main()\n"
1196                 "{\n"
1197                 "       dEQP_FragColor = v_color;\n"
1198                 "}\n";
1199
1200         if (m_context.getRenderTarget().getNumSamples() != 0)
1201                 throw tcu::NotSupportedError("MSAA config not supported by this test");
1202
1203         // Create shader.
1204
1205         DE_ASSERT(!m_program);
1206         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
1207
1208         if(!m_program->isOk())
1209         {
1210                 m_testCtx.getLog() << *m_program;
1211
1212                 GLint maxVertexTextures;
1213                 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
1214
1215                 if (maxVertexTextures < 1)
1216                         throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
1217                 else
1218                         TCU_FAIL("Failed to compile shader");
1219         }
1220
1221         // Make the textures.
1222
1223         try
1224         {
1225                 const int texWidth      = WIDTH_2D_ARRAY;
1226                 const int texHeight     = HEIGHT_2D_ARRAY;
1227                 const int texLayers     = LAYERS_2D_ARRAY;
1228
1229                 for (int i = 0; i < 2; i++)
1230                 {
1231                         DE_ASSERT(!m_textures[i]);
1232                         m_textures[i] = new glu::Texture2DArray(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight, texLayers);
1233                 }
1234
1235                 const int                                               numLevels       = deLog2Floor32(de::max(texWidth, texHeight)) + 1;
1236                 const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
1237                 const Vec4                                              cBias           = fmtInfo.valueMin;
1238                 const Vec4                                              cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
1239
1240                 // Fill first with gradient texture.
1241                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1242                 {
1243                         const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
1244                         const Vec4 gMax = Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
1245
1246                         m_textures[0]->getRefTexture().allocLevel(levelNdx);
1247                         tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
1248                 }
1249
1250                 // Fill second with grid texture.
1251                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1252                 {
1253                         const deUint32 step             = 0x00ffffff / numLevels;
1254                         const deUint32 rgb              = step*levelNdx;
1255                         const deUint32 colorA   = 0xff000000 | rgb;
1256                         const deUint32 colorB   = 0xff000000 | ~rgb;
1257
1258                         m_textures[1]->getRefTexture().allocLevel(levelNdx);
1259                         tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
1260                 }
1261
1262                 // Upload.
1263                 for (int i = 0; i < 2; i++)
1264                         m_textures[i]->upload();
1265         }
1266         catch (const std::exception&)
1267         {
1268                 // Clean up to save memory.
1269                 Vertex2DArrayTextureCase::deinit();
1270                 throw;
1271         }
1272 }
1273
1274 void Vertex2DArrayTextureCase::deinit (void)
1275 {
1276         for (int i = 0; i < 2; i++)
1277         {
1278                 delete m_textures[i];
1279                 m_textures[i] = DE_NULL;
1280         }
1281
1282         delete m_program;
1283         m_program = DE_NULL;
1284 }
1285
1286 float Vertex2DArrayTextureCase::calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const
1287 {
1288         const tcu::Texture2DArray&      refTexture      = m_textures[textureNdx]->getRefTexture();
1289         const int                                       texWidth        = refTexture.getWidth();
1290         const int                                       texHeight       = refTexture.getHeight();
1291
1292         // Calculate transformed coordinates of three screen corners.
1293         const Vec2                                      trans00         = (transf * Vec3(0.0f, 0.0f, 1.0f)).xy();
1294         const Vec2                                      trans01         = (transf * Vec3(0.0f, 1.0f, 1.0f)).xy();
1295         const Vec2                                      trans10         = (transf * Vec3(1.0f, 0.0f, 1.0f)).xy();
1296
1297         // Derivates.
1298         const float dudx = (trans10.x() - trans00.x()) * (float)texWidth / dstSize.x();
1299         const float dudy = (trans01.x() - trans00.x()) * (float)texWidth / dstSize.y();
1300         const float dvdx = (trans10.y() - trans00.y()) * (float)texHeight / dstSize.x();
1301         const float dvdy = (trans01.y() - trans00.y()) * (float)texHeight / dstSize.y();
1302
1303         return deFloatLog2(deFloatSqrt(de::max(dudx*dudx + dvdx*dvdx, dudy*dudy + dvdy*dvdy)));
1304 }
1305
1306 Vertex2DArrayTextureCase::IterateResult Vertex2DArrayTextureCase::iterate (void)
1307 {
1308         const int       viewportWidth           = deMin32(m_context.getRenderTarget().getWidth(), MAX_2D_ARRAY_RENDER_WIDTH);
1309         const int       viewportHeight          = deMin32(m_context.getRenderTarget().getHeight(), MAX_2D_ARRAY_RENDER_HEIGHT);
1310
1311         const int       viewportXOffsetMax      = m_context.getRenderTarget().getWidth() - viewportWidth;
1312         const int       viewportYOffsetMax      = m_context.getRenderTarget().getHeight() - viewportHeight;
1313
1314         de::Random      rnd                                     (deStringHash(getName()));
1315
1316         const int       viewportXOffset         = rnd.getInt(0, viewportXOffsetMax);
1317         const int       viewportYOffset         = rnd.getInt(0, viewportYOffsetMax);
1318
1319         glUseProgram(m_program->getProgram());
1320
1321         // Divide viewport into 4 cells.
1322         const int leftWidth             = viewportWidth / 2;
1323         const int rightWidth    = viewportWidth - leftWidth;
1324         const int bottomHeight  = viewportHeight / 2;
1325         const int topHeight             = viewportHeight - bottomHeight;
1326
1327         // Clear.
1328         glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
1329         glClear(GL_COLOR_BUFFER_BIT);
1330
1331         // Shear by layer count to get all layers visible.
1332         static const float layerShearTransfData[] =
1333         {
1334                 1.0f,                                   0.0f, 0.0f,
1335                 0.0f,                                   1.0f, 0.0f,
1336                 (float)LAYERS_2D_ARRAY, 0.0f, 0.0f
1337         };
1338
1339         // Minification and magnification transformations.
1340         static const float texMinTransfData[] =
1341         {
1342                 2.1f,  0.0f, -0.3f,
1343                 0.0f,  2.1f, -0.3f,
1344                 0.0f,  0.0f,  1.0f
1345         };
1346         static const float texMagTransfData[] =
1347         {
1348                 0.4f,  0.0f,  0.8f,
1349                 0.0f,  0.4f,  0.8f,
1350                 0.0f,  0.0f,  1.0f
1351         };
1352
1353         // Transformation matrices for minification and magnification.
1354         const Mat3 texMinTransf = Mat3(layerShearTransfData) * Mat3(texMinTransfData);
1355         const Mat3 texMagTransf = Mat3(layerShearTransfData) * Mat3(texMagTransfData);
1356
1357         // Surface for the reference image.
1358         tcu::Surface refImage(viewportWidth, viewportHeight);
1359
1360         {
1361                 const struct Render
1362                 {
1363                         const Rect      region;
1364                         int                     textureNdx;
1365                         const Mat3      texTransform;
1366                         Render (const Rect& r, int tN, const Mat3& tT) : region(r), textureNdx(tN), texTransform(tT) {}
1367                 } renders[] =
1368                 {
1369                         Render(Rect(0,                          0,                              leftWidth,      bottomHeight),  0, texMinTransf),
1370                         Render(Rect(leftWidth,          0,                              rightWidth,     bottomHeight),  0, texMagTransf),
1371                         Render(Rect(0,                          bottomHeight,   leftWidth,      topHeight),             1, texMinTransf),
1372                         Render(Rect(leftWidth,          bottomHeight,   rightWidth,     topHeight),             1, texMagTransf)
1373                 };
1374
1375                 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
1376                 {
1377                         const Render&   rend                            = renders[renderNdx];
1378                         const float             lod                                     = calculateLod(rend.texTransform, rend.region.size().asFloat(), rend.textureNdx);
1379                         const bool              useSafeTexCoords        = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
1380                         const Grid              grid                            (GRID_SIZE_2D_ARRAY, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
1381                                                                                                  TexTypeCoordParams<TEXTURETYPE_2D_ARRAY>(rend.texTransform), useSafeTexCoords);
1382
1383                         glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
1384                         renderCell                              (rend.textureNdx, lod, grid);
1385                         computeReferenceCell    (rend.textureNdx, lod, grid, refImage, rend.region);
1386                 }
1387         }
1388
1389         // Read back rendered results.
1390         tcu::Surface resImage(viewportWidth, viewportHeight);
1391         glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
1392
1393         glUseProgram(0);
1394
1395         // Compare and log.
1396         {
1397                 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
1398
1399                 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
1400                                                                 isOk ? "Pass"                           : "Image comparison failed");
1401         }
1402
1403         return STOP;
1404 }
1405
1406 void Vertex2DArrayTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
1407 {
1408         const deUint32 programID = m_program->getProgram();
1409
1410         // SETUP ATTRIBUTES.
1411
1412         {
1413                 const int positionLoc = glGetAttribLocation(programID, "a_position");
1414                 if (positionLoc != -1)
1415                 {
1416                         glEnableVertexAttribArray(positionLoc);
1417                         glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
1418                 }
1419         }
1420
1421         {
1422                 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
1423                 if (texCoordLoc != -1)
1424                 {
1425                         glEnableVertexAttribArray(texCoordLoc);
1426                         glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
1427                 }
1428         }
1429
1430         // SETUP UNIFORMS.
1431
1432         {
1433                 const int lodLoc = glGetUniformLocation(programID, "u_lod");
1434                 if (lodLoc != -1)
1435                         glUniform1f(lodLoc, lod);
1436         }
1437
1438         glActiveTexture(GL_TEXTURE0);
1439         glBindTexture(GL_TEXTURE_2D_ARRAY, m_textures[textureNdx]->getGLTexture());
1440         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S,         m_wrapS);
1441         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T,         m_wrapT);
1442         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,     m_minFilter);
1443         glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,     m_magFilter);
1444
1445         {
1446                 const int texLoc = glGetUniformLocation(programID, "u_texture");
1447                 if (texLoc != -1)
1448                         glUniform1i(texLoc, 0);
1449         }
1450 }
1451
1452 // Renders one sub-image with given parameters.
1453 void Vertex2DArrayTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1454 {
1455         setupShaderInputs(textureNdx, lod, grid);
1456         glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1457 }
1458
1459 // Computes reference for one sub-image with given parameters.
1460 void Vertex2DArrayTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1461 {
1462         computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter), grid, dst, dstRegion);
1463 }
1464
1465 class Vertex3DTextureCase : public TestCase
1466 {
1467 public:
1468                                                                 Vertex3DTextureCase             (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR);
1469                                                                 ~Vertex3DTextureCase    (void);
1470
1471         void                                            init                                    (void);
1472         void                                            deinit                                  (void);
1473         IterateResult                           iterate                                 (void);
1474
1475 private:
1476         typedef PosTexCoordQuadGrid<TEXTURETYPE_3D> Grid;
1477
1478                                                                 Vertex3DTextureCase             (const Vertex3DTextureCase& other);
1479         Vertex3DTextureCase&            operator=                               (const Vertex3DTextureCase& other);
1480
1481         float                                           calculateLod                    (const Mat3& transf, const Vec2& dstSize, int textureNdx) const;
1482         void                                            setupShaderInputs               (int textureNdx, float lod, const Grid& grid) const;
1483         void                                            renderCell                              (int textureNdx, float lod, const Grid& grid) const;
1484         void                                            computeReferenceCell    (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const;
1485
1486         const deUint32                          m_minFilter;
1487         const deUint32                          m_magFilter;
1488         const deUint32                          m_wrapS;
1489         const deUint32                          m_wrapT;
1490         const deUint32                          m_wrapR;
1491
1492         const glu::ShaderProgram*       m_program;
1493         glu::Texture3D*                         m_textures[2];  // 2 textures, a gradient texture and a grid texture.
1494 };
1495
1496 Vertex3DTextureCase::Vertex3DTextureCase (Context& testCtx, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR)
1497         : TestCase                              (testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc)
1498         , m_minFilter                   (minFilter)
1499         , m_magFilter                   (magFilter)
1500         , m_wrapS                               (wrapS)
1501         , m_wrapT                               (wrapT)
1502         , m_wrapR                               (wrapR)
1503         , m_program                             (DE_NULL)
1504 {
1505         m_textures[0] = DE_NULL;
1506         m_textures[1] = DE_NULL;
1507 }
1508
1509 Vertex3DTextureCase::~Vertex3DTextureCase(void)
1510 {
1511         Vertex3DTextureCase::deinit();
1512 }
1513
1514 void Vertex3DTextureCase::init (void)
1515 {
1516         const char* const vertexShaderSource =
1517                 "#version 300 es\n"
1518                 "in highp vec2 a_position;\n"
1519                 "in highp vec3 a_texCoord;\n"
1520                 "uniform highp sampler3D u_texture;\n"
1521                 "uniform highp float u_lod;\n"
1522                 "out mediump vec4 v_color;\n"
1523                 "\n"
1524                 "void main()\n"
1525                 "{\n"
1526                 "       gl_Position = vec4(a_position, 0.0, 1.0);\n"
1527                 "       v_color = textureLod(u_texture, a_texCoord, u_lod);\n"
1528                 "}\n";
1529
1530         const char* const fragmentShaderSource =
1531                 "#version 300 es\n"
1532                 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
1533                 "in mediump vec4 v_color;\n"
1534                 "\n"
1535                 "void main()\n"
1536                 "{\n"
1537                 "       dEQP_FragColor = v_color;\n"
1538                 "}\n";
1539
1540         if (m_context.getRenderTarget().getNumSamples() != 0)
1541                 throw tcu::NotSupportedError("MSAA config not supported by this test");
1542
1543         // Create shader.
1544
1545         DE_ASSERT(!m_program);
1546         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
1547
1548         if(!m_program->isOk())
1549         {
1550                 m_testCtx.getLog() << *m_program;
1551
1552                 GLint maxVertexTextures;
1553                 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
1554
1555                 if (maxVertexTextures < 1)
1556                         throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
1557                 else
1558                         TCU_FAIL("Failed to compile shader");
1559         }
1560
1561         // Make the textures.
1562
1563         try
1564         {
1565                 const int texWidth      = WIDTH_3D;
1566                 const int texHeight     = HEIGHT_3D;
1567                 const int texDepth      = DEPTH_3D;
1568
1569                 for (int i = 0; i < 2; i++)
1570                 {
1571                         DE_ASSERT(!m_textures[i]);
1572                         m_textures[i] = new glu::Texture3D(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight, texDepth);
1573                 }
1574
1575                 const int                                               numLevels       = deLog2Floor32(de::max(de::max(texWidth, texHeight), texDepth)) + 1;
1576                 const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
1577                 const Vec4                                              cBias           = fmtInfo.valueMin;
1578                 const Vec4                                              cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
1579
1580                 // Fill first with gradient texture.
1581                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1582                 {
1583                         const Vec4 gMin = Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
1584                         const Vec4 gMax = Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
1585
1586                         m_textures[0]->getRefTexture().allocLevel(levelNdx);
1587                         tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
1588                 }
1589
1590                 // Fill second with grid texture.
1591                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1592                 {
1593                         const deUint32 step             = 0x00ffffff / numLevels;
1594                         const deUint32 rgb              = step*levelNdx;
1595                         const deUint32 colorA   = 0xff000000 | rgb;
1596                         const deUint32 colorB   = 0xff000000 | ~rgb;
1597
1598                         m_textures[1]->getRefTexture().allocLevel(levelNdx);
1599                         tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, toVec4(tcu::RGBA(colorA))*cScale + cBias, toVec4(tcu::RGBA(colorB))*cScale + cBias);
1600                 }
1601
1602                 // Upload.
1603                 for (int i = 0; i < 2; i++)
1604                         m_textures[i]->upload();
1605         }
1606         catch (const std::exception&)
1607         {
1608                 // Clean up to save memory.
1609                 Vertex3DTextureCase::deinit();
1610                 throw;
1611         }
1612 }
1613
1614 void Vertex3DTextureCase::deinit (void)
1615 {
1616         for (int i = 0; i < 2; i++)
1617         {
1618                 delete m_textures[i];
1619                 m_textures[i] = DE_NULL;
1620         }
1621
1622         delete m_program;
1623         m_program = DE_NULL;
1624 }
1625
1626 float Vertex3DTextureCase::calculateLod (const Mat3& transf, const Vec2& dstSize, int textureNdx) const
1627 {
1628         const tcu::Texture3D&   refTexture      = m_textures[textureNdx]->getRefTexture();
1629         const int                               srcWidth        = refTexture.getWidth();
1630         const int                               srcHeight       = refTexture.getHeight();
1631         const int                               srcDepth        = refTexture.getDepth();
1632
1633         // Calculate transformed coordinates of three screen corners.
1634         const Vec3                              trans00         = transf * Vec3(0.0f, 0.0f, 1.0f);
1635         const Vec3                              trans01         = transf * Vec3(0.0f, 1.0f, 1.0f);
1636         const Vec3                              trans10         = transf * Vec3(1.0f, 0.0f, 1.0f);
1637
1638         // Derivates.
1639         const float dudx = (trans10.x() - trans00.x()) * (float)srcWidth / dstSize.x();
1640         const float dudy = (trans01.x() - trans00.x()) * (float)srcWidth / dstSize.y();
1641         const float dvdx = (trans10.y() - trans00.y()) * (float)srcHeight / dstSize.x();
1642         const float dvdy = (trans01.y() - trans00.y()) * (float)srcHeight / dstSize.y();
1643         const float dwdx = (trans10.z() - trans00.z()) * (float)srcDepth / dstSize.x();
1644         const float dwdy = (trans01.z() - trans00.z()) * (float)srcDepth / dstSize.y();
1645
1646         return deFloatLog2(deFloatSqrt(de::max(dudx*dudx + dvdx*dvdx + dwdx*dwdx, dudy*dudy + dvdy*dvdy + dwdy*dwdy)));
1647 }
1648
1649 Vertex3DTextureCase::IterateResult Vertex3DTextureCase::iterate (void)
1650 {
1651         const int       viewportWidth           = deMin32(m_context.getRenderTarget().getWidth(), MAX_3D_RENDER_WIDTH);
1652         const int       viewportHeight          = deMin32(m_context.getRenderTarget().getHeight(), MAX_3D_RENDER_HEIGHT);
1653
1654         const int       viewportXOffsetMax      = m_context.getRenderTarget().getWidth() - viewportWidth;
1655         const int       viewportYOffsetMax      = m_context.getRenderTarget().getHeight() - viewportHeight;
1656
1657         de::Random      rnd                                     (deStringHash(getName()));
1658
1659         const int       viewportXOffset         = rnd.getInt(0, viewportXOffsetMax);
1660         const int       viewportYOffset         = rnd.getInt(0, viewportYOffsetMax);
1661
1662         glUseProgram(m_program->getProgram());
1663
1664         // Divide viewport into 4 cells.
1665         const int leftWidth             = viewportWidth / 2;
1666         const int rightWidth            = viewportWidth - leftWidth;
1667         const int bottomHeight  = viewportHeight / 2;
1668         const int topHeight             = viewportHeight - bottomHeight;
1669
1670         // Clear.
1671         glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
1672         glClear(GL_COLOR_BUFFER_BIT);
1673
1674         // Shear to get all slices visible.
1675         static const float depthShearTransfData[] =
1676         {
1677                 1.0f, 0.0f, 0.0f,
1678                 0.0f, 1.0f, 0.0f,
1679                 1.0f, 1.0f, 0.0f
1680         };
1681
1682         // Minification and magnification transformations.
1683         static const float texMinTransfData[] =
1684         {
1685                 2.2f,  0.0f, -0.3f,
1686                 0.0f,  2.2f, -0.3f,
1687                 0.0f,  0.0f,  1.0f
1688         };
1689         static const float texMagTransfData[] =
1690         {
1691                 0.4f,  0.0f,  0.8f,
1692                 0.0f,  0.4f,  0.8f,
1693                 0.0f,  0.0f,  1.0f
1694         };
1695
1696         // Transformation matrices for minification and magnification.
1697         const Mat3 texMinTransf = Mat3(depthShearTransfData) * Mat3(texMinTransfData);
1698         const Mat3 texMagTransf = Mat3(depthShearTransfData) * Mat3(texMagTransfData);
1699
1700         // Surface for the reference image.
1701         tcu::Surface refImage(viewportWidth, viewportHeight);
1702
1703         {
1704                 const struct Render
1705                 {
1706                         const Rect      region;
1707                         int                     textureNdx;
1708                         const Mat3              texTransform;
1709                         Render (const Rect& r, int tN, const Mat3& tT) : region(r), textureNdx(tN), texTransform(tT) {}
1710                 } renders[] =
1711                 {
1712                         Render(Rect(0,                          0,                              leftWidth,      bottomHeight),  0, texMinTransf),
1713                         Render(Rect(leftWidth,          0,                              rightWidth,     bottomHeight),  0, texMagTransf),
1714                         Render(Rect(0,                          bottomHeight,   leftWidth,      topHeight),             1, texMinTransf),
1715                         Render(Rect(leftWidth,          bottomHeight,   rightWidth,     topHeight),             1, texMagTransf)
1716                 };
1717
1718                 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
1719                 {
1720                         const Render&   rend                            = renders[renderNdx];
1721                         const float             lod                                     = calculateLod(rend.texTransform, rend.region.size().asFloat(), rend.textureNdx);
1722                         const bool              useSafeTexCoords        = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
1723                         const Grid              grid                            (GRID_SIZE_3D, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
1724                                                                                                  TexTypeCoordParams<TEXTURETYPE_3D>(rend.texTransform), useSafeTexCoords);
1725
1726                         glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
1727                         renderCell                              (rend.textureNdx, lod, grid);
1728                         computeReferenceCell    (rend.textureNdx, lod, grid, refImage, rend.region);
1729                 }
1730         }
1731
1732         // Read back rendered results.
1733         tcu::Surface resImage(viewportWidth, viewportHeight);
1734         glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
1735
1736         glUseProgram(0);
1737
1738         // Compare and log.
1739         {
1740                 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
1741
1742                 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
1743                                                                 isOk ? "Pass"                           : "Image comparison failed");
1744         }
1745
1746         return STOP;
1747 }
1748
1749 void Vertex3DTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
1750 {
1751         const deUint32 programID = m_program->getProgram();
1752
1753         // SETUP ATTRIBUTES.
1754
1755         {
1756                 const int positionLoc = glGetAttribLocation(programID, "a_position");
1757                 if (positionLoc != -1)
1758                 {
1759                         glEnableVertexAttribArray(positionLoc);
1760                         glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
1761                 }
1762         }
1763
1764         {
1765                 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
1766                 if (texCoordLoc != -1)
1767                 {
1768                         glEnableVertexAttribArray(texCoordLoc);
1769                         glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
1770                 }
1771         }
1772
1773         // SETUP UNIFORMS.
1774
1775         {
1776                 const int lodLoc = glGetUniformLocation(programID, "u_lod");
1777                 if (lodLoc != -1)
1778                         glUniform1f(lodLoc, lod);
1779         }
1780
1781         glActiveTexture(GL_TEXTURE0);
1782         glBindTexture(GL_TEXTURE_3D, m_textures[textureNdx]->getGLTexture());
1783         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,               m_wrapS);
1784         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,               m_wrapT);
1785         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,               m_wrapR);
1786         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,   m_minFilter);
1787         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,   m_magFilter);
1788
1789         {
1790                 const int texLoc = glGetUniformLocation(programID, "u_texture");
1791                 if (texLoc != -1)
1792                         glUniform1i(texLoc, 0);
1793         }
1794 }
1795
1796 // Renders one sub-image with given parameters.
1797 void Vertex3DTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1798 {
1799         setupShaderInputs(textureNdx, lod, grid);
1800         glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1801 }
1802
1803 // Computes reference for one sub-image with given parameters.
1804 void Vertex3DTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1805 {
1806         computeReference(m_textures[textureNdx]->getRefTexture(), lod, glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, m_magFilter), grid, dst, dstRegion);
1807 }
1808
1809 VertexTextureTests::VertexTextureTests (Context& context)
1810         : TestCaseGroup(context, "vertex", "Vertex Texture Tests")
1811 {
1812 }
1813
1814 VertexTextureTests::~VertexTextureTests(void)
1815 {
1816 }
1817
1818 void VertexTextureTests::init (void)
1819 {
1820         // 2D and cube map groups, and their filtering and wrap sub-groups.
1821         TestCaseGroup* const group2D                            = new TestCaseGroup(m_context, "2d",                    "2D Vertex Texture Tests");
1822         TestCaseGroup* const groupCube                          = new TestCaseGroup(m_context, "cube",                  "Cube Map Vertex Texture Tests");
1823         TestCaseGroup* const group2DArray                       = new TestCaseGroup(m_context, "2d_array",              "2D Array Vertex Texture Tests");
1824         TestCaseGroup* const group3D                            = new TestCaseGroup(m_context, "3d",                    "3D Vertex Texture Tests");
1825         TestCaseGroup* const filteringGroup2D           = new TestCaseGroup(m_context, "filtering",             "2D Vertex Texture Filtering Tests");
1826         TestCaseGroup* const wrapGroup2D                        = new TestCaseGroup(m_context, "wrap",                  "2D Vertex Texture Wrap Tests");
1827         TestCaseGroup* const filteringGroupCube         = new TestCaseGroup(m_context, "filtering",             "Cube Map Vertex Texture Filtering Tests");
1828         TestCaseGroup* const wrapGroupCube                      = new TestCaseGroup(m_context, "wrap",                  "Cube Map Vertex Texture Wrap Tests");
1829         TestCaseGroup* const filteringGroup2DArray      = new TestCaseGroup(m_context, "filtering",             "2D Array Vertex Texture Filtering Tests");
1830         TestCaseGroup* const wrapGroup2DArray           = new TestCaseGroup(m_context, "wrap",                  "2D Array Vertex Texture Wrap Tests");
1831         TestCaseGroup* const filteringGroup3D           = new TestCaseGroup(m_context, "filtering",             "3D Vertex Texture Filtering Tests");
1832         TestCaseGroup* const wrapGroup3D                        = new TestCaseGroup(m_context, "wrap",                  "3D Vertex Texture Wrap Tests");
1833
1834         group2D->addChild(filteringGroup2D);
1835         group2D->addChild(wrapGroup2D);
1836         groupCube->addChild(filteringGroupCube);
1837         groupCube->addChild(wrapGroupCube);
1838         group2DArray->addChild(filteringGroup2DArray);
1839         group2DArray->addChild(wrapGroup2DArray);
1840         group3D->addChild(filteringGroup3D);
1841         group3D->addChild(wrapGroup3D);
1842
1843         addChild(group2D);
1844         addChild(groupCube);
1845         addChild(group2DArray);
1846         addChild(group3D);
1847
1848         static const struct
1849         {
1850                 const char*             name;
1851                 GLenum                  mode;
1852         } wrapModes[] =
1853         {
1854                 { "clamp",              GL_CLAMP_TO_EDGE        },
1855                 { "repeat",             GL_REPEAT                       },
1856                 { "mirror",             GL_MIRRORED_REPEAT      }
1857         };
1858
1859         static const struct
1860         {
1861                 const char*             name;
1862                 GLenum                  mode;
1863         } minFilterModes[] =
1864         {
1865                 { "nearest",                            GL_NEAREST                                      },
1866                 { "linear",                                     GL_LINEAR                                       },
1867                 { "nearest_mipmap_nearest",     GL_NEAREST_MIPMAP_NEAREST       },
1868                 { "linear_mipmap_nearest",      GL_LINEAR_MIPMAP_NEAREST        },
1869                 { "nearest_mipmap_linear",      GL_NEAREST_MIPMAP_LINEAR        },
1870                 { "linear_mipmap_linear",       GL_LINEAR_MIPMAP_LINEAR         }
1871         };
1872
1873         static const struct
1874         {
1875                 const char*             name;
1876                 GLenum                  mode;
1877         } magFilterModes[] =
1878         {
1879                 { "nearest",    GL_NEAREST      },
1880                 { "linear",             GL_LINEAR       }
1881         };
1882
1883 #define FOR_EACH(ITERATOR, ARRAY, BODY) \
1884         for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++)        \
1885                 BODY
1886
1887         // 2D cases.
1888
1889         FOR_EACH(minFilter,             minFilterModes,
1890         FOR_EACH(magFilter,             magFilterModes,
1891         FOR_EACH(wrapMode,              wrapModes,
1892                 {
1893                         const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1894
1895                         filteringGroup2D->addChild(new Vertex2DTextureCase(m_context,
1896                                                                                                                            name.c_str(), "",
1897                                                                                                                            minFilterModes[minFilter].mode,
1898                                                                                                                            magFilterModes[magFilter].mode,
1899                                                                                                                            wrapModes[wrapMode].mode,
1900                                                                                                                            wrapModes[wrapMode].mode));
1901                 })));
1902
1903         FOR_EACH(wrapSMode,             wrapModes,
1904         FOR_EACH(wrapTMode,             wrapModes,
1905                 {
1906                         const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1907
1908                         wrapGroup2D->addChild(new Vertex2DTextureCase(m_context,
1909                                                                                                                   name.c_str(), "",
1910                                                                                                                   GL_LINEAR_MIPMAP_LINEAR,
1911                                                                                                                   GL_LINEAR,
1912                                                                                                                   wrapModes[wrapSMode].mode,
1913                                                                                                                   wrapModes[wrapTMode].mode));
1914                 }));
1915
1916         // Cube map cases.
1917
1918         FOR_EACH(minFilter,             minFilterModes,
1919         FOR_EACH(magFilter,             magFilterModes,
1920         FOR_EACH(wrapMode,              wrapModes,
1921                 {
1922                         const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1923
1924                         filteringGroupCube->addChild(new VertexCubeTextureCase(m_context,
1925                                                                                                                                    name.c_str(), "",
1926                                                                                                                                    minFilterModes[minFilter].mode,
1927                                                                                                                                    magFilterModes[magFilter].mode,
1928                                                                                                                                    wrapModes[wrapMode].mode,
1929                                                                                                                                    wrapModes[wrapMode].mode));
1930                 })));
1931
1932         FOR_EACH(wrapSMode,             wrapModes,
1933         FOR_EACH(wrapTMode,             wrapModes,
1934                 {
1935                         const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1936
1937                         wrapGroupCube->addChild(new VertexCubeTextureCase(m_context,
1938                                                                                                                           name.c_str(), "",
1939                                                                                                                           GL_LINEAR_MIPMAP_LINEAR,
1940                                                                                                                           GL_LINEAR,
1941                                                                                                                           wrapModes[wrapSMode].mode,
1942                                                                                                                           wrapModes[wrapTMode].mode));
1943                 }));
1944
1945         // 2D array cases.
1946
1947         FOR_EACH(minFilter,             minFilterModes,
1948         FOR_EACH(magFilter,             magFilterModes,
1949         FOR_EACH(wrapMode,              wrapModes,
1950                 {
1951                         const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1952
1953                         filteringGroup2DArray->addChild(new Vertex2DArrayTextureCase(m_context,
1954                                                                                                                                                  name.c_str(), "",
1955                                                                                                                                                  minFilterModes[minFilter].mode,
1956                                                                                                                                                  magFilterModes[magFilter].mode,
1957                                                                                                                                                  wrapModes[wrapMode].mode,
1958                                                                                                                                                  wrapModes[wrapMode].mode));
1959                 })));
1960
1961         FOR_EACH(wrapSMode,             wrapModes,
1962         FOR_EACH(wrapTMode,             wrapModes,
1963                 {
1964                         const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1965
1966                         wrapGroup2DArray->addChild(new Vertex2DArrayTextureCase(m_context,
1967                                                                                                                                         name.c_str(), "",
1968                                                                                                                                         GL_LINEAR_MIPMAP_LINEAR,
1969                                                                                                                                         GL_LINEAR,
1970                                                                                                                                         wrapModes[wrapSMode].mode,
1971                                                                                                                                         wrapModes[wrapTMode].mode));
1972                 }));
1973
1974         // 3D cases.
1975
1976         FOR_EACH(minFilter,             minFilterModes,
1977         FOR_EACH(magFilter,             magFilterModes,
1978         FOR_EACH(wrapMode,              wrapModes,
1979                 {
1980                         const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1981
1982                         filteringGroup3D->addChild(new Vertex3DTextureCase(m_context,
1983                                                                                                                            name.c_str(), "",
1984                                                                                                                            minFilterModes[minFilter].mode,
1985                                                                                                                            magFilterModes[magFilter].mode,
1986                                                                                                                            wrapModes[wrapMode].mode,
1987                                                                                                                            wrapModes[wrapMode].mode,
1988                                                                                                                            wrapModes[wrapMode].mode));
1989                 })));
1990
1991         FOR_EACH(wrapSMode,             wrapModes,
1992         FOR_EACH(wrapTMode,             wrapModes,
1993         FOR_EACH(wrapRMode,             wrapModes,
1994                 {
1995                         const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name + "_" + wrapModes[wrapRMode].name;
1996
1997                         wrapGroup3D->addChild(new Vertex3DTextureCase(m_context,
1998                                                                                                                   name.c_str(), "",
1999                                                                                                                   GL_LINEAR_MIPMAP_LINEAR,
2000                                                                                                                   GL_LINEAR,
2001                                                                                                                   wrapModes[wrapSMode].mode,
2002                                                                                                                   wrapModes[wrapTMode].mode,
2003                                                                                                                   wrapModes[wrapRMode].mode));
2004                 })));
2005 }
2006
2007 } // Functional
2008 } // gles3
2009 } // deqp