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