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