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 ®ion, 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