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::__anon240494230111::Rect119 Rect (int x_, int y_, int w_, int h_) : x(x_), y(y_), w(w_), h(h_) {}
posdeqp::gles2::Functional::__anon240494230111::Rect120 IVec2 pos (void) const { return IVec2(x, y); }
sizedeqp::gles2::Functional::__anon240494230111::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::__anon240494230111::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::__anon240494230111::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 m_isES3Capable = glu::IsES3Compatible(m_context.getRenderContext().getFunctions());
765
766 if (m_context.getRenderTarget().getNumSamples() != 0)
767 throw tcu::NotSupportedError("MSAA config not supported by this test");
768
769 DE_ASSERT(!m_program);
770 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShader, fragmentShader));
771
772 if(!m_program->isOk())
773 {
774 m_testCtx.getLog() << *m_program;
775
776 GLint maxVertexTextures;
777 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextures);
778
779 if (maxVertexTextures < 1)
780 throw tcu::NotSupportedError("Vertex texture image units not supported", "", __FILE__, __LINE__);
781 else
782 TCU_FAIL("Failed to compile shader");
783 }
784
785 // Make the textures.
786 try
787 {
788 // Compute suitable power-of-two sizes (for mipmaps).
789 const int texWidth = 1 << deLog2Ceil32(MAX_CUBE_RENDER_WIDTH / 3 / 2);
790 const int texHeight = 1 << deLog2Ceil32(MAX_CUBE_RENDER_HEIGHT / 2 / 2);
791
792 DE_ASSERT(texWidth == texHeight);
793 DE_UNREF(texHeight);
794
795 for (int i = 0; i < 2; i++)
796 {
797 DE_ASSERT(!m_textures[i]);
798 m_textures[i] = new glu::TextureCube(m_context.getRenderContext(), GL_RGB, GL_UNSIGNED_BYTE, texWidth);
799 }
800
801 const bool mipmaps = deIsPowerOfTwo32(texWidth) != DE_FALSE;
802 const int numLevels = mipmaps ? deLog2Floor32(texWidth)+1 : 1;
803 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
804 const Vec4 cBias = fmtInfo.valueMin;
805 const Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin;
806
807 // Fill first with gradient texture.
808 static const Vec4 gradients[tcu::CUBEFACE_LAST][2] =
809 {
810 { Vec4(-1.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
811 { Vec4( 0.0f, -1.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
812 { Vec4(-1.0f, 0.0f, -1.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
813 { Vec4(-1.0f, -1.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
814 { Vec4(-1.0f, -1.0f, -1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
815 { Vec4( 0.0f, 0.0f, 0.0f, 2.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f) } // positive z
816 };
817 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
818 {
819 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
820 {
821 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
822 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
823 }
824 }
825
826 // Fill second with grid texture.
827 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
828 {
829 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
830 {
831 const deUint32 step = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
832 const deUint32 rgb = step*levelNdx*face;
833 const deUint32 colorA = 0xff000000 | rgb;
834 const deUint32 colorB = 0xff000000 | ~rgb;
835
836 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
837 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
838 }
839 }
840
841 // Upload.
842 for (int i = 0; i < 2; i++)
843 m_textures[i]->upload();
844 }
845 catch (const std::exception&)
846 {
847 // Clean up to save memory.
848 VertexCubeTextureCase::deinit();
849 throw;
850 }
851 }
852
deinit(void)853 void VertexCubeTextureCase::deinit (void)
854 {
855 for (int i = 0; i < 2; i++)
856 {
857 delete m_textures[i];
858 m_textures[i] = DE_NULL;
859 }
860
861 delete m_program;
862 m_program = DE_NULL;
863 }
864
calculateLod(const Vec2 & texScale,const Vec2 & dstSize,int textureNdx) const865 float VertexCubeTextureCase::calculateLod (const Vec2& texScale, const Vec2& dstSize, int textureNdx) const
866 {
867 const tcu::TextureCube& refTexture = m_textures[textureNdx]->getRefTexture();
868 const Vec2 srcSize = Vec2((float)refTexture.getSize(), (float)refTexture.getSize());
869 const Vec2 sizeRatio = texScale*srcSize / dstSize;
870
871 // \note In this particular case, dv/dx and du/dy are zero, simplifying the expression.
872 return deFloatLog2(de::max(sizeRatio.x(), sizeRatio.y()));
873 }
874
iterate(void)875 VertexCubeTextureCase::IterateResult VertexCubeTextureCase::iterate (void)
876 {
877 const int viewportWidth = deMin32(m_context.getRenderTarget().getWidth(), MAX_CUBE_RENDER_WIDTH);
878 const int viewportHeight = deMin32(m_context.getRenderTarget().getHeight(), MAX_CUBE_RENDER_HEIGHT);
879
880 const int viewportXOffsetMax = m_context.getRenderTarget().getWidth() - viewportWidth;
881 const int viewportYOffsetMax = m_context.getRenderTarget().getHeight() - viewportHeight;
882
883 de::Random rnd (deStringHash(getName()));
884
885 const int viewportXOffset = rnd.getInt(0, viewportXOffsetMax);
886 const int viewportYOffset = rnd.getInt(0, viewportYOffsetMax);
887
888 glUseProgram(m_program->getProgram());
889
890 // Divide viewport into 4 areas.
891 const int leftWidth = viewportWidth / 2;
892 const int rightWidth = viewportWidth - leftWidth;
893 const int bottomHeight = viewportHeight / 2;
894 const int topHeight = viewportHeight - bottomHeight;
895
896 // Clear.
897 glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
898 glClear(GL_COLOR_BUFFER_BIT);
899
900 // Texture scaling and offsetting vectors.
901 const Vec2 texMinScale (1.0f, 1.0f);
902 const Vec2 texMinOffset (0.0f, 0.0f);
903 const Vec2 texMagScale (0.3f, 0.3f);
904 const Vec2 texMagOffset (0.5f, 0.3f);
905
906 // Surface for the reference image.
907 tcu::Surface refImage(viewportWidth, viewportHeight);
908
909 // Each of the four areas is divided into 6 cells.
910 const int defCellWidth = viewportWidth / 2 / 3;
911 const int defCellHeight = viewportHeight / 2 / 2;
912
913 for (int i = 0; i < tcu::CUBEFACE_LAST; i++)
914 {
915 const int cellOffsetX = defCellWidth * (i % 3);
916 const int cellOffsetY = defCellHeight * (i / 3);
917 const bool isRightmostCell = i == 2 || i == 5;
918 const bool isTopCell = i >= 3;
919 const int leftCellWidth = isRightmostCell ? leftWidth - cellOffsetX : defCellWidth;
920 const int rightCellWidth = isRightmostCell ? rightWidth - cellOffsetX : defCellWidth;
921 const int bottomCellHeight = isTopCell ? bottomHeight - cellOffsetY : defCellHeight;
922 const int topCellHeight = isTopCell ? topHeight - cellOffsetY : defCellHeight;
923
924 const struct Render
925 {
926 const Rect region;
927 int textureNdx;
928 const Vec2 texCoordScale;
929 const Vec2 texCoordOffset;
930 Render (const Rect& r, int tN, const Vec2& tS, const Vec2& tO) : region(r), textureNdx(tN), texCoordScale(tS), texCoordOffset(tO) {}
931 } renders[] =
932 {
933 Render(Rect(cellOffsetX + 0, cellOffsetY + 0, leftCellWidth, bottomCellHeight), 0, texMinScale, texMinOffset),
934 Render(Rect(cellOffsetX + leftWidth, cellOffsetY + 0, rightCellWidth, bottomCellHeight), 0, texMagScale, texMagOffset),
935 Render(Rect(cellOffsetX + 0, cellOffsetY + bottomHeight, leftCellWidth, topCellHeight), 1, texMinScale, texMinOffset),
936 Render(Rect(cellOffsetX + leftWidth, cellOffsetY + bottomHeight, rightCellWidth, topCellHeight), 1, texMagScale, texMagOffset)
937 };
938
939 for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renders); renderNdx++)
940 {
941 const Render& rend = renders[renderNdx];
942 const float lod = calculateLod(rend.texCoordScale, rend.region.size().asFloat(), rend.textureNdx);
943 const bool useSafeTexCoords = isLevelNearest(lod > 0.0f ? m_minFilter : m_magFilter);
944 const Grid grid (GRID_SIZE_CUBE, rend.region.size(), getTextureSize(*m_textures[rend.textureNdx]),
945 TexTypeCoordParams<TEXTURETYPE_CUBE>(rend.texCoordScale, rend.texCoordOffset, (tcu::CubeFace)i), useSafeTexCoords);
946
947 glViewport(viewportXOffset + rend.region.x, viewportYOffset + rend.region.y, rend.region.w, rend.region.h);
948 renderCell (rend.textureNdx, lod, grid);
949 computeReferenceCell (rend.textureNdx, lod, grid, refImage, rend.region);
950 }
951 }
952
953 // Read back rendered results.
954 tcu::Surface resImage(viewportWidth, viewportHeight);
955 glu::readPixels(m_context.getRenderContext(), viewportXOffset, viewportYOffset, resImage.getAccess());
956
957 glUseProgram(0);
958
959 // Compare and log.
960 {
961 const bool isOk = compareImages(m_context.getRenderContext(), m_testCtx.getLog(), refImage, resImage);
962
963 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
964 isOk ? "Pass" : "Image comparison failed");
965 }
966
967 return STOP;
968 }
969
setupShaderInputs(int textureNdx,float lod,const Grid & grid) const970 void VertexCubeTextureCase::setupShaderInputs (int textureNdx, float lod, const Grid& grid) const
971 {
972 const deUint32 programID = m_program->getProgram();
973
974 // SETUP ATTRIBUTES.
975
976 {
977 const int positionLoc = glGetAttribLocation(programID, "a_position");
978 if (positionLoc != -1)
979 {
980 glEnableVertexAttribArray(positionLoc);
981 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, grid.getPositionPtr());
982 }
983 }
984
985 {
986 const int texCoordLoc = glGetAttribLocation(programID, "a_texCoord");
987 if (texCoordLoc != -1)
988 {
989 glEnableVertexAttribArray(texCoordLoc);
990 glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, grid.getTexCoordPtr());
991 }
992 }
993
994 // SETUP UNIFORMS.
995
996 {
997 const int lodLoc = glGetUniformLocation(programID, "u_lod");
998 if (lodLoc != -1)
999 glUniform1f(lodLoc, lod);
1000 }
1001
1002 glActiveTexture(GL_TEXTURE0);
1003 glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[textureNdx]->getGLTexture());
1004 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
1005 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
1006 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
1007 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
1008
1009 {
1010 const int texLoc = glGetUniformLocation(programID, "u_texture");
1011 if (texLoc != -1)
1012 glUniform1i(texLoc, 0);
1013 }
1014 }
1015
1016 // Renders one cube face with given parameters.
renderCell(int textureNdx,float lod,const Grid & grid) const1017 void VertexCubeTextureCase::renderCell (int textureNdx, float lod, const Grid& grid) const
1018 {
1019 setupShaderInputs(textureNdx, lod, grid);
1020 glDrawElements(GL_TRIANGLES, grid.getNumIndices(), GL_UNSIGNED_SHORT, grid.getIndexPtr());
1021 }
1022
1023 // Computes reference for one cube face with given parameters.
computeReferenceCell(int textureNdx,float lod,const Grid & grid,tcu::Surface & dst,const Rect & dstRegion) const1024 void VertexCubeTextureCase::computeReferenceCell (int textureNdx, float lod, const Grid& grid, tcu::Surface& dst, const Rect& dstRegion) const
1025 {
1026 tcu::Sampler sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
1027 sampler.seamlessCubeMap = m_isES3Capable;
1028 computeReference(m_textures[textureNdx]->getRefTexture(), lod, sampler, grid, dst, dstRegion);
1029 }
1030
VertexTextureTests(Context & context)1031 VertexTextureTests::VertexTextureTests (Context& context)
1032 : TestCaseGroup(context, "vertex", "Vertex Texture Tests")
1033 {
1034 }
1035
~VertexTextureTests(void)1036 VertexTextureTests::~VertexTextureTests(void)
1037 {
1038 }
1039
init(void)1040 void VertexTextureTests::init (void)
1041 {
1042 // 2D and cube map groups, and their filtering and wrap sub-groups.
1043 TestCaseGroup* const group2D = new TestCaseGroup(m_context, "2d", "2D Vertex Texture Tests");
1044 TestCaseGroup* const groupCube = new TestCaseGroup(m_context, "cube", "Cube Map Vertex Texture Tests");
1045 TestCaseGroup* const filteringGroup2D = new TestCaseGroup(m_context, "filtering", "2D Vertex Texture Filtering Tests");
1046 TestCaseGroup* const wrapGroup2D = new TestCaseGroup(m_context, "wrap", "2D Vertex Texture Wrap Tests");
1047 TestCaseGroup* const filteringGroupCube = new TestCaseGroup(m_context, "filtering", "Cube Map Vertex Texture Filtering Tests");
1048 TestCaseGroup* const wrapGroupCube = new TestCaseGroup(m_context, "wrap", "Cube Map Vertex Texture Wrap Tests");
1049
1050 group2D->addChild(filteringGroup2D);
1051 group2D->addChild(wrapGroup2D);
1052 groupCube->addChild(filteringGroupCube);
1053 groupCube->addChild(wrapGroupCube);
1054
1055 addChild(group2D);
1056 addChild(groupCube);
1057
1058 static const struct
1059 {
1060 const char* name;
1061 GLenum mode;
1062 } wrapModes[] =
1063 {
1064 { "clamp", GL_CLAMP_TO_EDGE },
1065 { "repeat", GL_REPEAT },
1066 { "mirror", GL_MIRRORED_REPEAT }
1067 };
1068
1069 static const struct
1070 {
1071 const char* name;
1072 GLenum mode;
1073 } minFilterModes[] =
1074 {
1075 { "nearest", GL_NEAREST },
1076 { "linear", GL_LINEAR },
1077 { "nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST },
1078 { "linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST },
1079 { "nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR },
1080 { "linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR }
1081 };
1082
1083 static const struct
1084 {
1085 const char* name;
1086 GLenum mode;
1087 } magFilterModes[] =
1088 {
1089 { "nearest", GL_NEAREST },
1090 { "linear", GL_LINEAR }
1091 };
1092
1093 #define FOR_EACH(ITERATOR, ARRAY, BODY) \
1094 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \
1095 BODY
1096
1097 // 2D cases.
1098
1099 FOR_EACH(minFilter, minFilterModes,
1100 FOR_EACH(magFilter, magFilterModes,
1101 FOR_EACH(wrapMode, wrapModes,
1102 {
1103 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1104
1105 filteringGroup2D->addChild(new Vertex2DTextureCase(m_context,
1106 name.c_str(), "",
1107 minFilterModes[minFilter].mode,
1108 magFilterModes[magFilter].mode,
1109 wrapModes[wrapMode].mode,
1110 wrapModes[wrapMode].mode));
1111 })))
1112
1113 FOR_EACH(wrapSMode, wrapModes,
1114 FOR_EACH(wrapTMode, wrapModes,
1115 {
1116 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1117
1118 wrapGroup2D->addChild(new Vertex2DTextureCase(m_context,
1119 name.c_str(), "",
1120 GL_LINEAR_MIPMAP_LINEAR,
1121 GL_LINEAR,
1122 wrapModes[wrapSMode].mode,
1123 wrapModes[wrapTMode].mode));
1124 }))
1125
1126 // Cube map cases.
1127
1128 FOR_EACH(minFilter, minFilterModes,
1129 FOR_EACH(magFilter, magFilterModes,
1130 FOR_EACH(wrapMode, wrapModes,
1131 {
1132 const string name = string("") + minFilterModes[minFilter].name + "_" + magFilterModes[magFilter].name + "_" + wrapModes[wrapMode].name;
1133
1134 filteringGroupCube->addChild(new VertexCubeTextureCase(m_context,
1135 name.c_str(), "",
1136 minFilterModes[minFilter].mode,
1137 magFilterModes[magFilter].mode,
1138 wrapModes[wrapMode].mode,
1139 wrapModes[wrapMode].mode));
1140 })))
1141
1142 FOR_EACH(wrapSMode, wrapModes,
1143 FOR_EACH(wrapTMode, wrapModes,
1144 {
1145 const string name = string("") + wrapModes[wrapSMode].name + "_" + wrapModes[wrapTMode].name;
1146
1147 wrapGroupCube->addChild(new VertexCubeTextureCase(m_context,
1148 name.c_str(), "",
1149 GL_LINEAR_MIPMAP_LINEAR,
1150 GL_LINEAR,
1151 wrapModes[wrapSMode].mode,
1152 wrapModes[wrapTMode].mode));
1153 }))
1154 }
1155
1156 } // Functional
1157 } // gles2
1158 } // deqp
1159