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