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