1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 GLSL textureGather[Offset[s]] tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fTextureGatherTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluTexture.hpp"
28 #include "gluDrawUtil.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "gluTextureUtil.hpp"
31 #include "gluStrUtil.hpp"
32 #include "gluObjectWrapper.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuSurface.hpp"
35 #include "tcuTestLog.hpp"
36 #include "tcuVectorUtil.hpp"
37 #include "tcuTexLookupVerifier.hpp"
38 #include "tcuTexCompareVerifier.hpp"
39 #include "tcuCommandLine.hpp"
40 #include "deUniquePtr.hpp"
41 #include "deStringUtil.hpp"
42 #include "deRandom.hpp"
43 #include "deString.h"
44
45 #include "glwEnums.hpp"
46 #include "glwFunctions.hpp"
47
48 using glu::ShaderProgram;
49 using tcu::ConstPixelBufferAccess;
50 using tcu::PixelBufferAccess;
51 using tcu::TestLog;
52 using tcu::IVec2;
53 using tcu::IVec3;
54 using tcu::IVec4;
55 using tcu::UVec4;
56 using tcu::Vec2;
57 using tcu::Vec3;
58 using tcu::Vec4;
59 using de::MovePtr;
60
61 using std::string;
62 using std::vector;
63
64 namespace deqp
65 {
66
67 using gls::TextureTestUtil::TextureType;
68 using gls::TextureTestUtil::TEXTURETYPE_2D;
69 using gls::TextureTestUtil::TEXTURETYPE_2D_ARRAY;
70 using gls::TextureTestUtil::TEXTURETYPE_CUBE;
71
72 namespace gles31
73 {
74 namespace Functional
75 {
76
77 namespace
78 {
79
80 // Round-to-zero int division, because pre-c++11 it's somewhat implementation-defined for negative values.
divRoundToZero(int a,int b)81 static inline int divRoundToZero (int a, int b)
82 {
83 return de::abs(a) / de::abs(b) * deSign32(a) * deSign32(b);
84 }
85
fillWithRandomColorTiles(const PixelBufferAccess & dst,const Vec4 & minVal,const Vec4 & maxVal,deUint32 seed)86 static void fillWithRandomColorTiles (const PixelBufferAccess& dst, const Vec4& minVal, const Vec4& maxVal, deUint32 seed)
87 {
88 const int numCols = dst.getWidth() >= 7 ? 7 : dst.getWidth();
89 const int numRows = dst.getHeight() >= 5 ? 5 : dst.getHeight();
90 de::Random rnd (seed);
91
92 for (int slice = 0; slice < dst.getDepth(); slice++)
93 for (int row = 0; row < numRows; row++)
94 for (int col = 0; col < numCols; col++)
95 {
96 const int yBegin = (row+0)*dst.getHeight()/numRows;
97 const int yEnd = (row+1)*dst.getHeight()/numRows;
98 const int xBegin = (col+0)*dst.getWidth()/numCols;
99 const int xEnd = (col+1)*dst.getWidth()/numCols;
100 Vec4 color;
101 for (int i = 0; i < 4; i++)
102 color[i] = rnd.getFloat(minVal[i], maxVal[i]);
103 tcu::clear(tcu::getSubregion(dst, xBegin, yBegin, slice, xEnd-xBegin, yEnd-yBegin, 1), color);
104 }
105 }
106
isDepthFormat(const tcu::TextureFormat & fmt)107 static inline bool isDepthFormat (const tcu::TextureFormat& fmt)
108 {
109 return fmt.order == tcu::TextureFormat::D || fmt.order == tcu::TextureFormat::DS;
110 }
111
isUnormFormatType(tcu::TextureFormat::ChannelType type)112 static inline bool isUnormFormatType (tcu::TextureFormat::ChannelType type)
113 {
114 return type == tcu::TextureFormat::UNORM_INT8 ||
115 type == tcu::TextureFormat::UNORM_INT16 ||
116 type == tcu::TextureFormat::UNORM_INT32;
117 }
118
isSIntFormatType(tcu::TextureFormat::ChannelType type)119 static inline bool isSIntFormatType (tcu::TextureFormat::ChannelType type)
120 {
121 return type == tcu::TextureFormat::SIGNED_INT8 ||
122 type == tcu::TextureFormat::SIGNED_INT16 ||
123 type == tcu::TextureFormat::SIGNED_INT32;
124 }
125
isUIntFormatType(tcu::TextureFormat::ChannelType type)126 static inline bool isUIntFormatType (tcu::TextureFormat::ChannelType type)
127 {
128 return type == tcu::TextureFormat::UNSIGNED_INT8 ||
129 type == tcu::TextureFormat::UNSIGNED_INT16 ||
130 type == tcu::TextureFormat::UNSIGNED_INT32;
131 }
132
getPixels(const glu::RenderContext & renderCtx,const IVec2 & size,const tcu::TextureFormat & colorBufferFormat)133 static tcu::TextureLevel getPixels (const glu::RenderContext& renderCtx, const IVec2& size, const tcu::TextureFormat& colorBufferFormat)
134 {
135 tcu::TextureLevel result(colorBufferFormat, size.x(), size.y());
136
137 // only a few pixel formats are guaranteed to be valid targets for readPixels, convert the rest
138 if (colorBufferFormat.order == tcu::TextureFormat::RGBA &&
139 (colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8 ||
140 colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT32 ||
141 colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT32))
142 {
143 // valid as is
144 glu::readPixels(renderCtx, 0, 0, result.getAccess());
145 }
146 else if (colorBufferFormat.order == tcu::TextureFormat::RGBA &&
147 (isSIntFormatType(colorBufferFormat.type) ||
148 isUIntFormatType(colorBufferFormat.type)))
149 {
150 // signed and unsigned integers must be read using 32-bit values
151 const bool isSigned = isSIntFormatType(colorBufferFormat.type);
152 tcu::TextureLevel readResult (tcu::TextureFormat(tcu::TextureFormat::RGBA,
153 (isSigned) ? (tcu::TextureFormat::SIGNED_INT32) : (tcu::TextureFormat::UNSIGNED_INT32)),
154 size.x(),
155 size.y());
156
157 glu::readPixels(renderCtx, 0, 0, readResult.getAccess());
158 tcu::copy(result.getAccess(), readResult.getAccess());
159 }
160 else
161 {
162 // unreadable format
163 DE_ASSERT(false);
164 }
165
166 return result;
167 }
168
169 enum TextureSwizzleComponent
170 {
171 TEXTURESWIZZLECOMPONENT_R = 0,
172 TEXTURESWIZZLECOMPONENT_G,
173 TEXTURESWIZZLECOMPONENT_B,
174 TEXTURESWIZZLECOMPONENT_A,
175 TEXTURESWIZZLECOMPONENT_ZERO,
176 TEXTURESWIZZLECOMPONENT_ONE,
177
178 TEXTURESWIZZLECOMPONENT_LAST
179 };
180
operator <<(std::ostream & stream,TextureSwizzleComponent comp)181 static std::ostream& operator<< (std::ostream& stream, TextureSwizzleComponent comp)
182 {
183 switch (comp)
184 {
185 case TEXTURESWIZZLECOMPONENT_R: return stream << "RED";
186 case TEXTURESWIZZLECOMPONENT_G: return stream << "GREEN";
187 case TEXTURESWIZZLECOMPONENT_B: return stream << "BLUE";
188 case TEXTURESWIZZLECOMPONENT_A: return stream << "ALPHA";
189 case TEXTURESWIZZLECOMPONENT_ZERO: return stream << "ZERO";
190 case TEXTURESWIZZLECOMPONENT_ONE: return stream << "ONE";
191 default: DE_ASSERT(false); return stream;
192 }
193 }
194
195 struct MaybeTextureSwizzle
196 {
197 public:
198 static MaybeTextureSwizzle createNoneTextureSwizzle (void);
199 static MaybeTextureSwizzle createSomeTextureSwizzle (void);
200
201 bool isSome (void) const;
202 bool isNone (void) const;
203 bool isIdentitySwizzle (void) const;
204
205 tcu::Vector<TextureSwizzleComponent, 4>& getSwizzle (void);
206 const tcu::Vector<TextureSwizzleComponent, 4>& getSwizzle (void) const;
207
208 private:
209 MaybeTextureSwizzle (void);
210
211 tcu::Vector<TextureSwizzleComponent, 4> m_swizzle;
212 bool m_isSome;
213 };
214
operator <<(std::ostream & stream,const MaybeTextureSwizzle & comp)215 static std::ostream& operator<< (std::ostream& stream, const MaybeTextureSwizzle& comp)
216 {
217 if (comp.isNone())
218 stream << "[default swizzle state]";
219 else
220 stream << "(" << comp.getSwizzle()[0]
221 << ", " << comp.getSwizzle()[1]
222 << ", " << comp.getSwizzle()[2]
223 << ", " << comp.getSwizzle()[3]
224 << ")";
225
226 return stream;
227 }
228
createNoneTextureSwizzle(void)229 MaybeTextureSwizzle MaybeTextureSwizzle::createNoneTextureSwizzle (void)
230 {
231 MaybeTextureSwizzle swizzle;
232
233 swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_LAST;
234 swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_LAST;
235 swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_LAST;
236 swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_LAST;
237 swizzle.m_isSome = false;
238
239 return swizzle;
240 }
241
createSomeTextureSwizzle(void)242 MaybeTextureSwizzle MaybeTextureSwizzle::createSomeTextureSwizzle (void)
243 {
244 MaybeTextureSwizzle swizzle;
245
246 swizzle.m_swizzle[0] = TEXTURESWIZZLECOMPONENT_R;
247 swizzle.m_swizzle[1] = TEXTURESWIZZLECOMPONENT_G;
248 swizzle.m_swizzle[2] = TEXTURESWIZZLECOMPONENT_B;
249 swizzle.m_swizzle[3] = TEXTURESWIZZLECOMPONENT_A;
250 swizzle.m_isSome = true;
251
252 return swizzle;
253 }
254
isSome(void) const255 bool MaybeTextureSwizzle::isSome (void) const
256 {
257 return m_isSome;
258 }
259
isNone(void) const260 bool MaybeTextureSwizzle::isNone (void) const
261 {
262 return !m_isSome;
263 }
264
isIdentitySwizzle(void) const265 bool MaybeTextureSwizzle::isIdentitySwizzle (void) const
266 {
267 return m_isSome &&
268 m_swizzle[0] == TEXTURESWIZZLECOMPONENT_R &&
269 m_swizzle[1] == TEXTURESWIZZLECOMPONENT_G &&
270 m_swizzle[2] == TEXTURESWIZZLECOMPONENT_B &&
271 m_swizzle[3] == TEXTURESWIZZLECOMPONENT_A;
272 }
273
getSwizzle(void)274 tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void)
275 {
276 return m_swizzle;
277 }
278
getSwizzle(void) const279 const tcu::Vector<TextureSwizzleComponent, 4>& MaybeTextureSwizzle::getSwizzle (void) const
280 {
281 return m_swizzle;
282 }
283
MaybeTextureSwizzle(void)284 MaybeTextureSwizzle::MaybeTextureSwizzle (void)
285 : m_swizzle (TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST, TEXTURESWIZZLECOMPONENT_LAST)
286 , m_isSome (false)
287 {
288 }
289
getGLTextureSwizzleComponent(TextureSwizzleComponent c)290 static deUint32 getGLTextureSwizzleComponent (TextureSwizzleComponent c)
291 {
292 switch (c)
293 {
294 case TEXTURESWIZZLECOMPONENT_R: return GL_RED;
295 case TEXTURESWIZZLECOMPONENT_G: return GL_GREEN;
296 case TEXTURESWIZZLECOMPONENT_B: return GL_BLUE;
297 case TEXTURESWIZZLECOMPONENT_A: return GL_ALPHA;
298 case TEXTURESWIZZLECOMPONENT_ZERO: return GL_ZERO;
299 case TEXTURESWIZZLECOMPONENT_ONE: return GL_ONE;
300 default: DE_ASSERT(false); return (deUint32)-1;
301 }
302 }
303
304 template <typename T>
swizzleColorChannel(const tcu::Vector<T,4> & src,TextureSwizzleComponent swizzle)305 static inline T swizzleColorChannel (const tcu::Vector<T, 4>& src, TextureSwizzleComponent swizzle)
306 {
307 switch (swizzle)
308 {
309 case TEXTURESWIZZLECOMPONENT_R: return src[0];
310 case TEXTURESWIZZLECOMPONENT_G: return src[1];
311 case TEXTURESWIZZLECOMPONENT_B: return src[2];
312 case TEXTURESWIZZLECOMPONENT_A: return src[3];
313 case TEXTURESWIZZLECOMPONENT_ZERO: return (T)0;
314 case TEXTURESWIZZLECOMPONENT_ONE: return (T)1;
315 default: DE_ASSERT(false); return (T)-1;
316 }
317 }
318
319 template <typename T>
swizzleColor(const tcu::Vector<T,4> & src,const MaybeTextureSwizzle & swizzle)320 static inline tcu::Vector<T, 4> swizzleColor (const tcu::Vector<T, 4>& src, const MaybeTextureSwizzle& swizzle)
321 {
322 DE_ASSERT(swizzle.isSome());
323
324 tcu::Vector<T, 4> result;
325 for (int i = 0; i < 4; i++)
326 result[i] = swizzleColorChannel(src, swizzle.getSwizzle()[i]);
327 return result;
328 }
329
330 template <typename T>
swizzlePixels(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,const MaybeTextureSwizzle & swizzle)331 static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle)
332 {
333 DE_ASSERT(dst.getWidth() == src.getWidth() &&
334 dst.getHeight() == src.getHeight() &&
335 dst.getDepth() == src.getDepth());
336 for (int z = 0; z < src.getDepth(); z++)
337 for (int y = 0; y < src.getHeight(); y++)
338 for (int x = 0; x < src.getWidth(); x++)
339 dst.setPixel(swizzleColor(src.getPixelT<T>(x, y, z), swizzle), x, y, z);
340 }
341
swizzlePixels(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,const MaybeTextureSwizzle & swizzle)342 static void swizzlePixels (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, const MaybeTextureSwizzle& swizzle)
343 {
344 if (isDepthFormat(dst.getFormat()))
345 DE_ASSERT(swizzle.isNone() || swizzle.isIdentitySwizzle());
346
347 if (swizzle.isNone() || swizzle.isIdentitySwizzle())
348 tcu::copy(dst, src);
349 else if (isUnormFormatType(dst.getFormat().type))
350 swizzlePixels<float>(dst, src, swizzle);
351 else if (isUIntFormatType(dst.getFormat().type))
352 swizzlePixels<deUint32>(dst, src, swizzle);
353 else if (isSIntFormatType(dst.getFormat().type))
354 swizzlePixels<deInt32>(dst, src, swizzle);
355 else
356 DE_ASSERT(false);
357 }
358
swizzleTexture(tcu::Texture2D & dst,const tcu::Texture2D & src,const MaybeTextureSwizzle & swizzle)359 static void swizzleTexture (tcu::Texture2D& dst, const tcu::Texture2D& src, const MaybeTextureSwizzle& swizzle)
360 {
361 dst = tcu::Texture2D(src.getFormat(), src.getWidth(), src.getHeight());
362 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
363 {
364 if (src.isLevelEmpty(levelNdx))
365 continue;
366 dst.allocLevel(levelNdx);
367 swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle);
368 }
369 }
370
swizzleTexture(tcu::Texture2DArray & dst,const tcu::Texture2DArray & src,const MaybeTextureSwizzle & swizzle)371 static void swizzleTexture (tcu::Texture2DArray& dst, const tcu::Texture2DArray& src, const MaybeTextureSwizzle& swizzle)
372 {
373 dst = tcu::Texture2DArray(src.getFormat(), src.getWidth(), src.getHeight(), src.getNumLayers());
374 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
375 {
376 if (src.isLevelEmpty(levelNdx))
377 continue;
378 dst.allocLevel(levelNdx);
379 swizzlePixels(dst.getLevel(levelNdx), src.getLevel(levelNdx), swizzle);
380 }
381 }
382
swizzleTexture(tcu::TextureCube & dst,const tcu::TextureCube & src,const MaybeTextureSwizzle & swizzle)383 static void swizzleTexture (tcu::TextureCube& dst, const tcu::TextureCube& src, const MaybeTextureSwizzle& swizzle)
384 {
385 dst = tcu::TextureCube(src.getFormat(), src.getSize());
386 for (int faceI = 0; faceI < tcu::CUBEFACE_LAST; faceI++)
387 {
388 const tcu::CubeFace face = (tcu::CubeFace)faceI;
389 for (int levelNdx = 0; levelNdx < src.getNumLevels(); levelNdx++)
390 {
391 if (src.isLevelEmpty(face, levelNdx))
392 continue;
393 dst.allocLevel(face, levelNdx);
394 swizzlePixels(dst.getLevelFace(levelNdx, face), src.getLevelFace(levelNdx, face), swizzle);
395 }
396 }
397 }
398
getOneLevelSubView(const tcu::Texture2DView & view,int level)399 static tcu::Texture2DView getOneLevelSubView (const tcu::Texture2DView& view, int level)
400 {
401 return tcu::Texture2DView(1, view.getLevels() + level);
402 }
403
getOneLevelSubView(const tcu::Texture2DArrayView & view,int level)404 static tcu::Texture2DArrayView getOneLevelSubView (const tcu::Texture2DArrayView& view, int level)
405 {
406 return tcu::Texture2DArrayView(1, view.getLevels() + level);
407 }
408
getOneLevelSubView(const tcu::TextureCubeView & view,int level)409 static tcu::TextureCubeView getOneLevelSubView (const tcu::TextureCubeView& view, int level)
410 {
411 const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST];
412
413 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
414 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + level;
415
416 return tcu::TextureCubeView(1, levels);
417 }
418
419 class PixelOffsets
420 {
421 public:
422 virtual void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const = 0;
~PixelOffsets(void)423 virtual ~PixelOffsets (void) {}
424 };
425
426 class MultiplePixelOffsets : public PixelOffsets
427 {
428 public:
MultiplePixelOffsets(const IVec2 & a,const IVec2 & b,const IVec2 & c,const IVec2 & d)429 MultiplePixelOffsets (const IVec2& a,
430 const IVec2& b,
431 const IVec2& c,
432 const IVec2& d)
433 {
434 m_offsets[0] = a;
435 m_offsets[1] = b;
436 m_offsets[2] = c;
437 m_offsets[3] = d;
438 }
439
operator ()(const IVec2 &,IVec2 (& dst)[4]) const440 void operator() (const IVec2& /* pixCoord */, IVec2 (&dst)[4]) const
441 {
442 for (int i = 0; i < DE_LENGTH_OF_ARRAY(dst); i++)
443 dst[i] = m_offsets[i];
444 }
445
446 private:
447 IVec2 m_offsets[4];
448 };
449
450 class SinglePixelOffsets : public MultiplePixelOffsets
451 {
452 public:
SinglePixelOffsets(const IVec2 & offset)453 SinglePixelOffsets (const IVec2& offset)
454 : MultiplePixelOffsets(offset + IVec2(0, 1),
455 offset + IVec2(1, 1),
456 offset + IVec2(1, 0),
457 offset + IVec2(0, 0))
458 {
459 }
460 };
461
462 class DynamicSinglePixelOffsets : public PixelOffsets
463 {
464 public:
DynamicSinglePixelOffsets(const IVec2 & offsetRange)465 DynamicSinglePixelOffsets (const IVec2& offsetRange) : m_offsetRange(offsetRange) {}
466
operator ()(const IVec2 & pixCoord,IVec2 (& dst)[4]) const467 void operator() (const IVec2& pixCoord, IVec2 (&dst)[4]) const
468 {
469 const int offsetRangeSize = m_offsetRange.y() - m_offsetRange.x() + 1;
470 SinglePixelOffsets(tcu::mod(pixCoord.swizzle(1,0), IVec2(offsetRangeSize)) + m_offsetRange.x())(IVec2(), dst);
471 }
472
473 private:
474 IVec2 m_offsetRange;
475 };
476
477 template <typename T>
triQuadInterpolate(const T (& values)[4],float xFactor,float yFactor)478 static inline T triQuadInterpolate (const T (&values)[4], float xFactor, float yFactor)
479 {
480 if (xFactor + yFactor < 1.0f)
481 return values[0] + (values[2]-values[0])*xFactor + (values[1]-values[0])*yFactor;
482 else
483 return values[3] + (values[1]-values[3])*(1.0f-xFactor) + (values[2]-values[3])*(1.0f-yFactor);
484 }
485
486 template <int N>
computeTexCoordVecs(const vector<float> & texCoords,tcu::Vector<float,N> (& dst)[4])487 static inline void computeTexCoordVecs (const vector<float>& texCoords, tcu::Vector<float, N> (&dst)[4])
488 {
489 DE_ASSERT((int)texCoords.size() == 4*N);
490 for (int i = 0; i < 4; i++)
491 for (int j = 0; j < N; j++)
492 dst[i][j] = texCoords[i*N + j];
493 }
494
495 #if defined(DE_DEBUG)
496 // Whether offsets correspond to the sample offsets used with plain textureGather().
isZeroOffsetOffsets(const IVec2 (& offsets)[4])497 static inline bool isZeroOffsetOffsets (const IVec2 (&offsets)[4])
498 {
499 IVec2 ref[4];
500 SinglePixelOffsets(IVec2(0))(IVec2(), ref);
501 return std::equal(DE_ARRAY_BEGIN(offsets),
502 DE_ARRAY_END(offsets),
503 DE_ARRAY_BEGIN(ref));
504 }
505 #endif
506
507 template <typename ColorScalarType>
gatherOffsets(const tcu::Texture2DView & texture,const tcu::Sampler & sampler,const Vec2 & coord,int componentNdx,const IVec2 (& offsets)[4])508 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, const Vec2& coord, int componentNdx, const IVec2 (&offsets)[4])
509 {
510 return texture.gatherOffsets(sampler, coord.x(), coord.y(), componentNdx, offsets).cast<ColorScalarType>();
511 }
512
513 template <typename ColorScalarType>
gatherOffsets(const tcu::Texture2DArrayView & texture,const tcu::Sampler & sampler,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4])514 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4])
515 {
516 return texture.gatherOffsets(sampler, coord.x(), coord.y(), coord.z(), componentNdx, offsets).cast<ColorScalarType>();
517 }
518
519 template <typename ColorScalarType>
gatherOffsets(const tcu::TextureCubeView & texture,const tcu::Sampler & sampler,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4])520 static tcu::Vector<ColorScalarType, 4> gatherOffsets (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, const Vec3& coord, int componentNdx, const IVec2 (&offsets)[4])
521 {
522 DE_ASSERT(isZeroOffsetOffsets(offsets));
523 DE_UNREF(offsets);
524 return texture.gather(sampler, coord.x(), coord.y(), coord.z(), componentNdx).cast<ColorScalarType>();
525 }
526
gatherOffsetsCompare(const tcu::Texture2DView & texture,const tcu::Sampler & sampler,float refZ,const Vec2 & coord,const IVec2 (& offsets)[4])527 static Vec4 gatherOffsetsCompare (const tcu::Texture2DView& texture, const tcu::Sampler& sampler, float refZ, const Vec2& coord, const IVec2 (&offsets)[4])
528 {
529 return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), offsets);
530 }
531
gatherOffsetsCompare(const tcu::Texture2DArrayView & texture,const tcu::Sampler & sampler,float refZ,const Vec3 & coord,const IVec2 (& offsets)[4])532 static Vec4 gatherOffsetsCompare (const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4])
533 {
534 return texture.gatherOffsetsCompare(sampler, refZ, coord.x(), coord.y(), coord.z(), offsets);
535 }
536
gatherOffsetsCompare(const tcu::TextureCubeView & texture,const tcu::Sampler & sampler,float refZ,const Vec3 & coord,const IVec2 (& offsets)[4])537 static Vec4 gatherOffsetsCompare (const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, float refZ, const Vec3& coord, const IVec2 (&offsets)[4])
538 {
539 DE_ASSERT(isZeroOffsetOffsets(offsets));
540 DE_UNREF(offsets);
541 return texture.gatherCompare(sampler, refZ, coord.x(), coord.y(), coord.z());
542 }
543
544 template <typename PrecType, typename ColorScalarT>
isGatherOffsetsResultValid(const tcu::TextureCubeView & texture,const tcu::Sampler & sampler,const PrecType & prec,const Vec3 & coord,int componentNdx,const IVec2 (& offsets)[4],const tcu::Vector<ColorScalarT,4> & result)545 static bool isGatherOffsetsResultValid (const tcu::TextureCubeView& texture,
546 const tcu::Sampler& sampler,
547 const PrecType& prec,
548 const Vec3& coord,
549 int componentNdx,
550 const IVec2 (&offsets)[4],
551 const tcu::Vector<ColorScalarT, 4>& result)
552 {
553 DE_ASSERT(isZeroOffsetOffsets(offsets));
554 DE_UNREF(offsets);
555 return tcu::isGatherResultValid(texture, sampler, prec, coord, componentNdx, result);
556 }
557
isGatherOffsetsCompareResultValid(const tcu::TextureCubeView & texture,const tcu::Sampler & sampler,const tcu::TexComparePrecision & prec,const Vec3 & coord,const IVec2 (& offsets)[4],float cmpReference,const Vec4 & result)558 static bool isGatherOffsetsCompareResultValid (const tcu::TextureCubeView& texture,
559 const tcu::Sampler& sampler,
560 const tcu::TexComparePrecision& prec,
561 const Vec3& coord,
562 const IVec2 (&offsets)[4],
563 float cmpReference,
564 const Vec4& result)
565 {
566 DE_ASSERT(isZeroOffsetOffsets(offsets));
567 DE_UNREF(offsets);
568 return tcu::isGatherCompareResultValid(texture, sampler, prec, coord, cmpReference, result);
569 }
570
571 template <typename ColorScalarType, typename PrecType, typename TexViewT, typename TexCoordT>
verifyGatherOffsets(TestLog & log,const ConstPixelBufferAccess & result,const TexViewT & texture,const TexCoordT (& texCoords)[4],const tcu::Sampler & sampler,const PrecType & lookupPrec,int componentNdx,const PixelOffsets & getPixelOffsets)572 static bool verifyGatherOffsets (TestLog& log,
573 const ConstPixelBufferAccess& result,
574 const TexViewT& texture,
575 const TexCoordT (&texCoords)[4],
576 const tcu::Sampler& sampler,
577 const PrecType& lookupPrec,
578 int componentNdx,
579 const PixelOffsets& getPixelOffsets)
580 {
581 typedef tcu::Vector<ColorScalarType, 4> ColorVec;
582
583 const int width = result.getWidth();
584 const int height = result.getWidth();
585 tcu::TextureLevel ideal (result.getFormat(), width, height);
586 const PixelBufferAccess idealAccess = ideal.getAccess();
587 tcu::Surface errorMask (width, height);
588 bool success = true;
589
590 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
591
592 for (int py = 0; py < height; py++)
593 for (int px = 0; px < width; px++)
594 {
595 IVec2 offsets[4];
596 getPixelOffsets(IVec2(px, py), offsets);
597
598 const Vec2 viewportCoord = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height);
599 const TexCoordT texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
600 const ColorVec resultPix = result.getPixelT<ColorScalarType>(px, py);
601 const ColorVec idealPix = gatherOffsets<ColorScalarType>(texture, sampler, texCoord, componentNdx, offsets);
602
603 idealAccess.setPixel(idealPix, px, py);
604
605 if (tcu::boolAny(tcu::logicalAnd(lookupPrec.colorMask,
606 tcu::greaterThan(tcu::absDiff(resultPix, idealPix),
607 lookupPrec.colorThreshold.template cast<ColorScalarType>()))))
608 {
609 if (!isGatherOffsetsResultValid(texture, sampler, lookupPrec, texCoord, componentNdx, offsets, resultPix))
610 {
611 errorMask.setPixel(px, py, tcu::RGBA::red());
612 success = false;
613 }
614 }
615 }
616
617 log << TestLog::ImageSet("VerifyResult", "Verification result")
618 << TestLog::Image("Rendered", "Rendered image", result);
619
620 if (!success)
621 {
622 log << TestLog::Image("Reference", "Ideal reference image", ideal)
623 << TestLog::Image("ErrorMask", "Error mask", errorMask);
624 }
625
626 log << TestLog::EndImageSet;
627
628 return success;
629 }
630
631 class PixelCompareRefZ
632 {
633 public:
634 virtual float operator() (const IVec2& pixCoord) const = 0;
635 };
636
637 class PixelCompareRefZDefault : public PixelCompareRefZ
638 {
639 public:
PixelCompareRefZDefault(const IVec2 & renderSize)640 PixelCompareRefZDefault (const IVec2& renderSize) : m_renderSize(renderSize) {}
641
operator ()(const IVec2 & pixCoord) const642 float operator() (const IVec2& pixCoord) const
643 {
644 return ((float)pixCoord.x() + 0.5f) / (float)m_renderSize.x();
645 }
646
647 private:
648 IVec2 m_renderSize;
649 };
650
651 template <typename TexViewT, typename TexCoordT>
verifyGatherOffsetsCompare(TestLog & log,const ConstPixelBufferAccess & result,const TexViewT & texture,const TexCoordT (& texCoords)[4],const tcu::Sampler & sampler,const tcu::TexComparePrecision & compPrec,const PixelCompareRefZ & getPixelRefZ,const PixelOffsets & getPixelOffsets)652 static bool verifyGatherOffsetsCompare (TestLog& log,
653 const ConstPixelBufferAccess& result,
654 const TexViewT& texture,
655 const TexCoordT (&texCoords)[4],
656 const tcu::Sampler& sampler,
657 const tcu::TexComparePrecision& compPrec,
658 const PixelCompareRefZ& getPixelRefZ,
659 const PixelOffsets& getPixelOffsets)
660 {
661 const int width = result.getWidth();
662 const int height = result.getWidth();
663 tcu::Surface ideal (width, height);
664 const PixelBufferAccess idealAccess = ideal.getAccess();
665 tcu::Surface errorMask (width, height);
666 bool success = true;
667
668 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
669
670 for (int py = 0; py < height; py++)
671 for (int px = 0; px < width; px++)
672 {
673 IVec2 offsets[4];
674 getPixelOffsets(IVec2(px, py), offsets);
675
676 const Vec2 viewportCoord = (Vec2((float)px, (float)py) + 0.5f) / Vec2((float)width, (float)height);
677 const TexCoordT texCoord = triQuadInterpolate(texCoords, viewportCoord.x(), viewportCoord.y());
678 const float refZ = getPixelRefZ(IVec2(px, py));
679 const Vec4 resultPix = result.getPixel(px, py);
680 const Vec4 idealPix = gatherOffsetsCompare(texture, sampler, refZ, texCoord, offsets);
681
682 idealAccess.setPixel(idealPix, px, py);
683
684 if (!tcu::boolAll(tcu::equal(resultPix, idealPix)))
685 {
686 if (!isGatherOffsetsCompareResultValid(texture, sampler, compPrec, texCoord, offsets, refZ, resultPix))
687 {
688 errorMask.setPixel(px, py, tcu::RGBA::red());
689 success = false;
690 }
691 }
692 }
693
694 log << TestLog::ImageSet("VerifyResult", "Verification result")
695 << TestLog::Image("Rendered", "Rendered image", result);
696
697 if (!success)
698 {
699 log << TestLog::Image("Reference", "Ideal reference image", ideal)
700 << TestLog::Image("ErrorMask", "Error mask", errorMask);
701 }
702
703 log << TestLog::EndImageSet;
704
705 return success;
706 }
707
verifySingleColored(TestLog & log,const ConstPixelBufferAccess & result,const Vec4 & refColor)708 static bool verifySingleColored (TestLog& log, const ConstPixelBufferAccess& result, const Vec4& refColor)
709 {
710 const int width = result.getWidth();
711 const int height = result.getWidth();
712 tcu::Surface ideal (width, height);
713 const PixelBufferAccess idealAccess = ideal.getAccess();
714 tcu::Surface errorMask (width, height);
715 bool success = true;
716
717 tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
718 tcu::clear(idealAccess, refColor);
719
720 for (int py = 0; py < height; py++)
721 for (int px = 0; px < width; px++)
722 {
723 if (result.getPixel(px, py) != refColor)
724 {
725 errorMask.setPixel(px, py, tcu::RGBA::red());
726 success = false;
727 }
728 }
729
730 log << TestLog::ImageSet("VerifyResult", "Verification result")
731 << TestLog::Image("Rendered", "Rendered image", result);
732
733 if (!success)
734 {
735 log << TestLog::Image("Reference", "Ideal reference image", ideal)
736 << TestLog::Image("ErrorMask", "Error mask", errorMask);
737 }
738
739 log << TestLog::EndImageSet;
740
741 return success;
742 }
743
744 enum GatherType
745 {
746 GATHERTYPE_BASIC = 0,
747 GATHERTYPE_OFFSET,
748 GATHERTYPE_OFFSET_DYNAMIC,
749 GATHERTYPE_OFFSETS,
750
751 GATHERTYPE_LAST
752 };
753
754 enum GatherCaseFlags
755 {
756 GATHERCASE_MIPMAP_INCOMPLETE = (1<<0), //!< Excercise special case of sampling mipmap-incomplete texture
757 GATHERCASE_DONT_SAMPLE_CUBE_CORNERS = (1<<1) //!< For cube map cases: do not sample cube corners
758 };
759
gatherTypeName(GatherType type)760 static inline const char* gatherTypeName (GatherType type)
761 {
762 switch (type)
763 {
764 case GATHERTYPE_BASIC: return "basic";
765 case GATHERTYPE_OFFSET: return "offset";
766 case GATHERTYPE_OFFSET_DYNAMIC: return "offset_dynamic";
767 case GATHERTYPE_OFFSETS: return "offsets";
768 default: DE_ASSERT(false); return DE_NULL;
769 }
770 }
771
gatherTypeDescription(GatherType type)772 static inline const char* gatherTypeDescription (GatherType type)
773 {
774 switch (type)
775 {
776 case GATHERTYPE_BASIC: return "textureGather";
777 case GATHERTYPE_OFFSET: return "textureGatherOffset";
778 case GATHERTYPE_OFFSET_DYNAMIC: return "textureGatherOffset with dynamic offsets";
779 case GATHERTYPE_OFFSETS: return "textureGatherOffsets";
780 default: DE_ASSERT(false); return DE_NULL;
781 }
782 }
783
requireGpuShader5(GatherType gatherType)784 static inline bool requireGpuShader5 (GatherType gatherType)
785 {
786 return gatherType == GATHERTYPE_OFFSET_DYNAMIC || gatherType == GATHERTYPE_OFFSETS;
787 }
788
789 struct GatherArgs
790 {
791 int componentNdx; // If negative, implicit component index 0 is used (i.e. the parameter is not given).
792 IVec2 offsets[4]; // \note Unless GATHERTYPE_OFFSETS is used, only offsets[0] is relevant; also, for GATHERTYPE_OFFSET_DYNAMIC, none are relevant.
793
GatherArgsdeqp::gles31::Functional::__anon39ed81040111::GatherArgs794 GatherArgs (void)
795 : componentNdx(-1)
796 {
797 std::fill(DE_ARRAY_BEGIN(offsets), DE_ARRAY_END(offsets), IVec2());
798 }
799
GatherArgsdeqp::gles31::Functional::__anon39ed81040111::GatherArgs800 GatherArgs (int comp,
801 const IVec2& off0 = IVec2(),
802 const IVec2& off1 = IVec2(),
803 const IVec2& off2 = IVec2(),
804 const IVec2& off3 = IVec2())
805 : componentNdx(comp)
806 {
807 offsets[0] = off0;
808 offsets[1] = off1;
809 offsets[2] = off2;
810 offsets[3] = off3;
811 }
812 };
813
makePixelOffsetsFunctor(GatherType gatherType,const GatherArgs & gatherArgs,const IVec2 & offsetRange)814 static MovePtr<PixelOffsets> makePixelOffsetsFunctor (GatherType gatherType, const GatherArgs& gatherArgs, const IVec2& offsetRange)
815 {
816 if (gatherType == GATHERTYPE_BASIC || gatherType == GATHERTYPE_OFFSET)
817 {
818 const IVec2 offset = gatherType == GATHERTYPE_BASIC ? IVec2(0) : gatherArgs.offsets[0];
819 return MovePtr<PixelOffsets>(new SinglePixelOffsets(offset));
820 }
821 else if (gatherType == GATHERTYPE_OFFSET_DYNAMIC)
822 {
823 return MovePtr<PixelOffsets>(new DynamicSinglePixelOffsets(offsetRange));
824 }
825 else if (gatherType == GATHERTYPE_OFFSETS)
826 return MovePtr<PixelOffsets>(new MultiplePixelOffsets(gatherArgs.offsets[0],
827 gatherArgs.offsets[1],
828 gatherArgs.offsets[2],
829 gatherArgs.offsets[3]));
830 else
831 {
832 DE_ASSERT(false);
833 return MovePtr<PixelOffsets>(DE_NULL);
834 }
835 }
836
getSamplerType(TextureType textureType,const tcu::TextureFormat & format)837 static inline glu::DataType getSamplerType (TextureType textureType, const tcu::TextureFormat& format)
838 {
839 if (isDepthFormat(format))
840 {
841 switch (textureType)
842 {
843 case TEXTURETYPE_2D: return glu::TYPE_SAMPLER_2D_SHADOW;
844 case TEXTURETYPE_2D_ARRAY: return glu::TYPE_SAMPLER_2D_ARRAY_SHADOW;
845 case TEXTURETYPE_CUBE: return glu::TYPE_SAMPLER_CUBE_SHADOW;
846 default: DE_ASSERT(false); return glu::TYPE_LAST;
847 }
848 }
849 else
850 {
851 switch (textureType)
852 {
853 case TEXTURETYPE_2D: return glu::getSampler2DType(format);
854 case TEXTURETYPE_2D_ARRAY: return glu::getSampler2DArrayType(format);
855 case TEXTURETYPE_CUBE: return glu::getSamplerCubeType(format);
856 default: DE_ASSERT(false); return glu::TYPE_LAST;
857 }
858 }
859 }
860
getSamplerGatherResultType(glu::DataType samplerType)861 static inline glu::DataType getSamplerGatherResultType (glu::DataType samplerType)
862 {
863 switch (samplerType)
864 {
865 case glu::TYPE_SAMPLER_2D_SHADOW:
866 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
867 case glu::TYPE_SAMPLER_CUBE_SHADOW:
868 case glu::TYPE_SAMPLER_2D:
869 case glu::TYPE_SAMPLER_2D_ARRAY:
870 case glu::TYPE_SAMPLER_CUBE:
871 return glu::TYPE_FLOAT_VEC4;
872
873 case glu::TYPE_INT_SAMPLER_2D:
874 case glu::TYPE_INT_SAMPLER_2D_ARRAY:
875 case glu::TYPE_INT_SAMPLER_CUBE:
876 return glu::TYPE_INT_VEC4;
877
878 case glu::TYPE_UINT_SAMPLER_2D:
879 case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
880 case glu::TYPE_UINT_SAMPLER_CUBE:
881 return glu::TYPE_UINT_VEC4;
882
883 default:
884 DE_ASSERT(false);
885 return glu::TYPE_LAST;
886 }
887 }
888
getNumTextureSamplingDimensions(TextureType type)889 static inline int getNumTextureSamplingDimensions (TextureType type)
890 {
891 switch (type)
892 {
893 case TEXTURETYPE_2D: return 2;
894 case TEXTURETYPE_2D_ARRAY: return 3;
895 case TEXTURETYPE_CUBE: return 3;
896 default: DE_ASSERT(false); return -1;
897 }
898 }
899
getGLTextureType(TextureType type)900 static deUint32 getGLTextureType (TextureType type)
901 {
902 switch (type)
903 {
904 case TEXTURETYPE_2D: return GL_TEXTURE_2D;
905 case TEXTURETYPE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY;
906 case TEXTURETYPE_CUBE: return GL_TEXTURE_CUBE_MAP;
907 default: DE_ASSERT(false); return (deUint32)-1;
908 }
909 }
910
911 enum OffsetSize
912 {
913 OFFSETSIZE_NONE = 0,
914 OFFSETSIZE_MINIMUM_REQUIRED,
915 OFFSETSIZE_IMPLEMENTATION_MAXIMUM,
916
917 OFFSETSIZE_LAST
918 };
919
isMipmapFilter(tcu::Sampler::FilterMode filter)920 static inline bool isMipmapFilter (tcu::Sampler::FilterMode filter)
921 {
922 switch (filter)
923 {
924 case tcu::Sampler::NEAREST:
925 case tcu::Sampler::LINEAR:
926 return false;
927
928 case tcu::Sampler::NEAREST_MIPMAP_NEAREST:
929 case tcu::Sampler::NEAREST_MIPMAP_LINEAR:
930 case tcu::Sampler::LINEAR_MIPMAP_NEAREST:
931 case tcu::Sampler::LINEAR_MIPMAP_LINEAR:
932 return true;
933
934 default:
935 DE_ASSERT(false);
936 return false;
937 }
938 }
939
940 class TextureGatherCase : public TestCase
941 {
942 public:
943 TextureGatherCase (Context& context,
944 const char* name,
945 const char* description,
946 TextureType textureType,
947 GatherType gatherType,
948 OffsetSize offsetSize,
949 tcu::TextureFormat textureFormat,
950 tcu::Sampler::CompareMode shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureFormat is a depth format.
951 tcu::Sampler::WrapMode wrapS,
952 tcu::Sampler::WrapMode wrapT,
953 const MaybeTextureSwizzle& texSwizzle,
954 // \note Filter modes have no effect on gather (except when it comes to
955 // texture completeness); these are supposed to test just that.
956 tcu::Sampler::FilterMode minFilter,
957 tcu::Sampler::FilterMode magFilter,
958 int baseLevel,
959 deUint32 flags);
960
961 void init (void);
962 void deinit (void);
963 IterateResult iterate (void);
964
965 protected:
966 IVec2 getOffsetRange (void) const;
967
968 template <typename TexViewT, typename TexCoordT>
969 bool verify (const ConstPixelBufferAccess& rendered,
970 const TexViewT& texture,
971 const TexCoordT (&bottomLeft)[4],
972 const GatherArgs& gatherArgs) const;
973
974 virtual void generateIterations (void) = 0;
975 virtual void createAndUploadTexture (void) = 0;
976 virtual int getNumIterations (void) const = 0;
977 virtual GatherArgs getGatherArgs (int iterationNdx) const = 0;
978 virtual vector<float> computeQuadTexCoord (int iterationNdx) const = 0;
979 virtual bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const = 0;
980
981 const GatherType m_gatherType;
982 const OffsetSize m_offsetSize;
983 const tcu::TextureFormat m_textureFormat;
984 const tcu::Sampler::CompareMode m_shadowCompareMode;
985 const tcu::Sampler::WrapMode m_wrapS;
986 const tcu::Sampler::WrapMode m_wrapT;
987 const MaybeTextureSwizzle m_textureSwizzle;
988 const tcu::Sampler::FilterMode m_minFilter;
989 const tcu::Sampler::FilterMode m_magFilter;
990 const int m_baseLevel;
991 const deUint32 m_flags;
992
993 private:
994 enum
995 {
996 SPEC_MAX_MIN_OFFSET = -8,
997 SPEC_MIN_MAX_OFFSET = 7
998 };
999
1000 static const IVec2 RENDER_SIZE;
1001
1002 static glu::VertexSource genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput);
1003 static glu::FragmentSource genFragmentShaderSource (bool requireGpuShader5, int numTexCoordComponents, glu::DataType samplerType, const string& funcCall, bool useNormalizedCoordInput, bool usePixCoord);
1004 static string genGatherFuncCall (GatherType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange, int indentationDepth);
1005 static glu::ProgramSources genProgramSources (GatherType, TextureType, const tcu::TextureFormat&, const GatherArgs&, const string& refZExpr, const IVec2& offsetRange);
1006
1007 const TextureType m_textureType;
1008
1009 const tcu::TextureFormat m_colorBufferFormat;
1010 MovePtr<glu::Renderbuffer> m_colorBuffer;
1011 MovePtr<glu::Framebuffer> m_fbo;
1012
1013 int m_currentIteration;
1014 MovePtr<ShaderProgram> m_program;
1015 };
1016
1017 const IVec2 TextureGatherCase::RENDER_SIZE = IVec2(64, 64);
1018
TextureGatherCase(Context & context,const char * name,const char * description,TextureType textureType,GatherType gatherType,OffsetSize offsetSize,tcu::TextureFormat textureFormat,tcu::Sampler::CompareMode shadowCompareMode,tcu::Sampler::WrapMode wrapS,tcu::Sampler::WrapMode wrapT,const MaybeTextureSwizzle & textureSwizzle,tcu::Sampler::FilterMode minFilter,tcu::Sampler::FilterMode magFilter,int baseLevel,deUint32 flags)1019 TextureGatherCase::TextureGatherCase (Context& context,
1020 const char* name,
1021 const char* description,
1022 TextureType textureType,
1023 GatherType gatherType,
1024 OffsetSize offsetSize,
1025 tcu::TextureFormat textureFormat,
1026 tcu::Sampler::CompareMode shadowCompareMode, //!< Should be COMPAREMODE_NONE iff textureType == TEXTURETYPE_NORMAL.
1027 tcu::Sampler::WrapMode wrapS,
1028 tcu::Sampler::WrapMode wrapT,
1029 const MaybeTextureSwizzle& textureSwizzle,
1030 tcu::Sampler::FilterMode minFilter,
1031 tcu::Sampler::FilterMode magFilter,
1032 int baseLevel,
1033 deUint32 flags)
1034 : TestCase (context, name, description)
1035 , m_gatherType (gatherType)
1036 , m_offsetSize (offsetSize)
1037 , m_textureFormat (textureFormat)
1038 , m_shadowCompareMode (shadowCompareMode)
1039 , m_wrapS (wrapS)
1040 , m_wrapT (wrapT)
1041 , m_textureSwizzle (textureSwizzle)
1042 , m_minFilter (minFilter)
1043 , m_magFilter (magFilter)
1044 , m_baseLevel (baseLevel)
1045 , m_flags (flags)
1046 , m_textureType (textureType)
1047 , m_colorBufferFormat (tcu::TextureFormat(tcu::TextureFormat::RGBA,
1048 isDepthFormat(textureFormat) ? tcu::TextureFormat::UNORM_INT8 : textureFormat.type))
1049 , m_currentIteration (0)
1050 {
1051 DE_ASSERT((m_gatherType == GATHERTYPE_BASIC) == (m_offsetSize == OFFSETSIZE_NONE));
1052 DE_ASSERT((m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE) == isDepthFormat(m_textureFormat));
1053 DE_ASSERT(isUnormFormatType(m_colorBufferFormat.type) ||
1054 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 ||
1055 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT16 ||
1056 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
1057 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT16);
1058 DE_ASSERT(glu::isGLInternalColorFormatFilterable(glu::getInternalFormat(m_colorBufferFormat)) ||
1059 (m_magFilter == tcu::Sampler::NEAREST && (m_minFilter == tcu::Sampler::NEAREST || m_minFilter == tcu::Sampler::NEAREST_MIPMAP_NEAREST)));
1060 DE_ASSERT(isMipmapFilter(m_minFilter) || !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE));
1061 DE_ASSERT(m_textureType == TEXTURETYPE_CUBE || !(m_flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS));
1062 DE_ASSERT(!((m_flags & GATHERCASE_MIPMAP_INCOMPLETE) && isDepthFormat(m_textureFormat))); // It's not clear what shadow textures should return when incomplete.
1063 }
1064
getOffsetRange(void) const1065 IVec2 TextureGatherCase::getOffsetRange (void) const
1066 {
1067 switch (m_offsetSize)
1068 {
1069 case OFFSETSIZE_NONE:
1070 return IVec2(0);
1071 break;
1072
1073 case OFFSETSIZE_MINIMUM_REQUIRED:
1074 // \note Defined by spec.
1075 return IVec2(SPEC_MAX_MIN_OFFSET,
1076 SPEC_MIN_MAX_OFFSET);
1077 break;
1078
1079 case OFFSETSIZE_IMPLEMENTATION_MAXIMUM:
1080 return IVec2(m_context.getContextInfo().getInt(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET),
1081 m_context.getContextInfo().getInt(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET));
1082 break;
1083
1084 default:
1085 DE_ASSERT(false);
1086 return IVec2(-1);
1087 }
1088 }
1089
genVertexShaderSource(bool requireGpuShader5,int numTexCoordComponents,bool useNormalizedCoordInput)1090 glu::VertexSource TextureGatherCase::genVertexShaderSource (bool requireGpuShader5, int numTexCoordComponents, bool useNormalizedCoordInput)
1091 {
1092 DE_ASSERT(numTexCoordComponents == 2 || numTexCoordComponents == 3);
1093 const string texCoordType = "vec" + de::toString(numTexCoordComponents);
1094 return glu::VertexSource("#version 310 es\n"
1095 + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") +
1096 "\n"
1097 "in highp vec2 a_position;\n"
1098 "in highp " + texCoordType + " a_texCoord;\n"
1099 + (useNormalizedCoordInput ? "in highp vec2 a_normalizedCoord; // (0,0) to (1,1)\n" : "") +
1100 "\n"
1101 "out highp " + texCoordType + " v_texCoord;\n"
1102 + (useNormalizedCoordInput ? "out highp vec2 v_normalizedCoord;\n" : "") +
1103 "\n"
1104 "void main (void)\n"
1105 "{\n"
1106 " gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n"
1107 " v_texCoord = a_texCoord;\n"
1108 + (useNormalizedCoordInput ? "\tv_normalizedCoord = a_normalizedCoord;\n" : "") +
1109 "}\n");
1110 }
1111
genFragmentShaderSource(bool requireGpuShader5,int numTexCoordComponents,glu::DataType samplerType,const string & funcCall,bool useNormalizedCoordInput,bool usePixCoord)1112 glu::FragmentSource TextureGatherCase::genFragmentShaderSource (bool requireGpuShader5,
1113 int numTexCoordComponents,
1114 glu::DataType samplerType,
1115 const string& funcCall,
1116 bool useNormalizedCoordInput,
1117 bool usePixCoord)
1118 {
1119 DE_ASSERT(glu::isDataTypeSampler(samplerType));
1120 DE_ASSERT(de::inRange(numTexCoordComponents, 2, 3));
1121 DE_ASSERT(!usePixCoord || useNormalizedCoordInput);
1122
1123 const string texCoordType = "vec" + de::toString(numTexCoordComponents);
1124
1125 return glu::FragmentSource("#version 310 es\n"
1126 + string(requireGpuShader5 ? "#extension GL_EXT_gpu_shader5 : require\n" : "") +
1127 "\n"
1128 "layout (location = 0) out mediump " + glu::getDataTypeName(getSamplerGatherResultType(samplerType)) + " o_color;\n"
1129 "\n"
1130 "in highp " + texCoordType + " v_texCoord;\n"
1131 + (useNormalizedCoordInput ? "in highp vec2 v_normalizedCoord;\n" : "") +
1132 "\n"
1133 "uniform highp " + string(glu::getDataTypeName(samplerType)) + " u_sampler;\n"
1134 + (useNormalizedCoordInput ? "uniform highp vec2 u_viewportSize;\n" : "") +
1135 "\n"
1136 "void main(void)\n"
1137 "{\n"
1138 + (usePixCoord ? "\tivec2 pixCoord = ivec2(v_normalizedCoord*u_viewportSize);\n" : "") +
1139 " o_color = " + funcCall + ";\n"
1140 "}\n");
1141 }
1142
genGatherFuncCall(GatherType gatherType,const tcu::TextureFormat & textureFormat,const GatherArgs & gatherArgs,const string & refZExpr,const IVec2 & offsetRange,int indentationDepth)1143 string TextureGatherCase::genGatherFuncCall (GatherType gatherType, const tcu::TextureFormat& textureFormat, const GatherArgs& gatherArgs, const string& refZExpr, const IVec2& offsetRange, int indentationDepth)
1144 {
1145 string result;
1146
1147 switch (gatherType)
1148 {
1149 case GATHERTYPE_BASIC:
1150 result += "textureGather";
1151 break;
1152 case GATHERTYPE_OFFSET: // \note Fallthrough.
1153 case GATHERTYPE_OFFSET_DYNAMIC:
1154 result += "textureGatherOffset";
1155 break;
1156 case GATHERTYPE_OFFSETS:
1157 result += "textureGatherOffsets";
1158 break;
1159 default:
1160 DE_ASSERT(false);
1161 }
1162
1163 result += "(u_sampler, v_texCoord";
1164
1165 if (isDepthFormat(textureFormat))
1166 {
1167 DE_ASSERT(gatherArgs.componentNdx < 0);
1168 result += ", " + refZExpr;
1169 }
1170
1171 if (gatherType == GATHERTYPE_OFFSET ||
1172 gatherType == GATHERTYPE_OFFSET_DYNAMIC ||
1173 gatherType == GATHERTYPE_OFFSETS)
1174 {
1175 result += ", ";
1176 switch (gatherType)
1177 {
1178 case GATHERTYPE_OFFSET:
1179 result += "ivec2" + de::toString(gatherArgs.offsets[0]);
1180 break;
1181
1182 case GATHERTYPE_OFFSET_DYNAMIC:
1183 result += "pixCoord.yx % ivec2(" + de::toString(offsetRange.y() - offsetRange.x() + 1) + ") + " + de::toString(offsetRange.x());
1184 break;
1185
1186 case GATHERTYPE_OFFSETS:
1187 result += "ivec2[4](\n"
1188 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[0]) + ",\n"
1189 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[1]) + ",\n"
1190 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[2]) + ",\n"
1191 + string(indentationDepth, '\t') + "\tivec2" + de::toString(gatherArgs.offsets[3]) + ")\n"
1192 + string(indentationDepth, '\t') + "\t";
1193 break;
1194
1195 default:
1196 DE_ASSERT(false);
1197 }
1198 }
1199
1200 if (gatherArgs.componentNdx >= 0)
1201 {
1202 DE_ASSERT(gatherArgs.componentNdx < 4);
1203 result += ", " + de::toString(gatherArgs.componentNdx);
1204 }
1205
1206 result += ")";
1207
1208 return result;
1209 }
1210
1211 // \note If componentNdx for genProgramSources() is -1, component index is not specified.
genProgramSources(GatherType gatherType,TextureType textureType,const tcu::TextureFormat & textureFormat,const GatherArgs & gatherArgs,const string & refZExpr,const IVec2 & offsetRange)1212 glu::ProgramSources TextureGatherCase::genProgramSources (GatherType gatherType,
1213 TextureType textureType,
1214 const tcu::TextureFormat& textureFormat,
1215 const GatherArgs& gatherArgs,
1216 const string& refZExpr,
1217 const IVec2& offsetRange)
1218 {
1219 const bool usePixCoord = gatherType == GATHERTYPE_OFFSET_DYNAMIC;
1220 const bool useNormalizedCoord = usePixCoord || isDepthFormat(textureFormat);
1221 const bool isDynamicOffset = gatherType == GATHERTYPE_OFFSET_DYNAMIC;
1222 const bool isShadow = isDepthFormat(textureFormat);
1223 const glu::DataType samplerType = getSamplerType(textureType, textureFormat);
1224 const int numDims = getNumTextureSamplingDimensions(textureType);
1225 const string funcCall = genGatherFuncCall(gatherType, textureFormat, gatherArgs, refZExpr, offsetRange, 1);
1226
1227 return glu::ProgramSources() << genVertexShaderSource(requireGpuShader5(gatherType), numDims, isDynamicOffset || isShadow)
1228 << genFragmentShaderSource(requireGpuShader5(gatherType), numDims, samplerType, funcCall, useNormalizedCoord, usePixCoord);
1229 }
1230
init(void)1231 void TextureGatherCase::init (void)
1232 {
1233 TestLog& log = m_testCtx.getLog();
1234 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1235 const glw::Functions& gl = renderCtx.getFunctions();
1236 const deUint32 texTypeGL = getGLTextureType(m_textureType);
1237
1238 // Check prerequisites.
1239 if (requireGpuShader5(m_gatherType) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"))
1240 throw tcu::NotSupportedError("GL_EXT_gpu_shader5 required");
1241
1242 // Log and check implementation offset limits, if appropriate.
1243 if (m_offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM)
1244 {
1245 const IVec2 offsetRange = getOffsetRange();
1246 log << TestLog::Integer("ImplementationMinTextureGatherOffset", "Implementation's value for GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[0])
1247 << TestLog::Integer("ImplementationMaxTextureGatherOffset", "Implementation's value for GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET", "", QP_KEY_TAG_NONE, offsetRange[1]);
1248 TCU_CHECK_MSG(offsetRange[0] <= SPEC_MAX_MIN_OFFSET, ("GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be at most " + de::toString((int)SPEC_MAX_MIN_OFFSET)).c_str());
1249 TCU_CHECK_MSG(offsetRange[1] >= SPEC_MIN_MAX_OFFSET, ("GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be at least " + de::toString((int)SPEC_MIN_MAX_OFFSET)).c_str());
1250 }
1251
1252 // Create rbo and fbo.
1253
1254 m_colorBuffer = MovePtr<glu::Renderbuffer>(new glu::Renderbuffer(renderCtx));
1255 gl.bindRenderbuffer(GL_RENDERBUFFER, **m_colorBuffer);
1256 gl.renderbufferStorage(GL_RENDERBUFFER, glu::getInternalFormat(m_colorBufferFormat), RENDER_SIZE.x(), RENDER_SIZE.y());
1257 GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup renderbuffer object");
1258
1259 m_fbo = MovePtr<glu::Framebuffer>(new glu::Framebuffer(renderCtx));
1260 gl.bindFramebuffer(GL_FRAMEBUFFER, **m_fbo);
1261 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, **m_colorBuffer);
1262 GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup framebuffer object");
1263
1264 log << TestLog::Message << "Using a framebuffer object with renderbuffer with format "
1265 << glu::getTextureFormatName(glu::getInternalFormat(m_colorBufferFormat))
1266 << " and size " << RENDER_SIZE << TestLog::EndMessage;
1267
1268 // Generate subclass-specific iterations.
1269
1270 generateIterations();
1271 m_currentIteration = 0;
1272
1273 // Initialize texture.
1274
1275 createAndUploadTexture();
1276 gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(m_wrapS));
1277 gl.texParameteri(texTypeGL, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(m_wrapT));
1278 gl.texParameteri(texTypeGL, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(m_minFilter));
1279 gl.texParameteri(texTypeGL, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(m_magFilter));
1280
1281 if (m_baseLevel != 0)
1282 gl.texParameteri(texTypeGL, GL_TEXTURE_BASE_LEVEL, m_baseLevel);
1283
1284 if (isDepthFormat(m_textureFormat))
1285 {
1286 gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
1287 gl.texParameteri(texTypeGL, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(m_shadowCompareMode));
1288 }
1289
1290 if (m_textureSwizzle.isSome())
1291 {
1292 const deUint32 swizzleNamesGL[4] =
1293 {
1294 GL_TEXTURE_SWIZZLE_R,
1295 GL_TEXTURE_SWIZZLE_G,
1296 GL_TEXTURE_SWIZZLE_B,
1297 GL_TEXTURE_SWIZZLE_A
1298 };
1299
1300 for (int i = 0; i < 4; i++)
1301 {
1302 const deUint32 curGLSwizzle = getGLTextureSwizzleComponent(m_textureSwizzle.getSwizzle()[i]);
1303 gl.texParameteri(texTypeGL, swizzleNamesGL[i], curGLSwizzle);
1304 }
1305 }
1306
1307 GLU_EXPECT_NO_ERROR(gl.getError(), "Set texture parameters");
1308
1309 log << TestLog::Message << "Texture base level is " << m_baseLevel << TestLog::EndMessage
1310 << TestLog::Message << "s and t wrap modes are "
1311 << glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapS)) << " and "
1312 << glu::getTextureWrapModeName(glu::getGLWrapMode(m_wrapT)) << ", respectively" << TestLog::EndMessage
1313 << TestLog::Message << "Minification and magnification filter modes are "
1314 << glu::getTextureFilterName(glu::getGLFilterMode(m_minFilter)) << " and "
1315 << glu::getTextureFilterName(glu::getGLFilterMode(m_magFilter)) << ", respectively "
1316 << ((m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ?
1317 "(note that they cause the texture to be incomplete)" :
1318 "(note that they should have no effect on gather result)")
1319 << TestLog::EndMessage
1320 << TestLog::Message << "Using texture swizzle " << m_textureSwizzle << TestLog::EndMessage;
1321
1322 if (m_shadowCompareMode != tcu::Sampler::COMPAREMODE_NONE)
1323 log << TestLog::Message << "Using texture compare func " << glu::getCompareFuncName(glu::getGLCompareFunc(m_shadowCompareMode)) << TestLog::EndMessage;
1324 }
1325
deinit(void)1326 void TextureGatherCase::deinit (void)
1327 {
1328 m_program = MovePtr<ShaderProgram>(DE_NULL);
1329 m_fbo = MovePtr<glu::Framebuffer>(DE_NULL);
1330 m_colorBuffer = MovePtr<glu::Renderbuffer>(DE_NULL);
1331 }
1332
iterate(void)1333 TextureGatherCase::IterateResult TextureGatherCase::iterate (void)
1334 {
1335 TestLog& log = m_testCtx.getLog();
1336 const tcu::ScopedLogSection iterationSection (log, "Iteration" + de::toString(m_currentIteration), "Iteration " + de::toString(m_currentIteration));
1337 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1338 const glw::Functions& gl = renderCtx.getFunctions();
1339 const GatherArgs& gatherArgs = getGatherArgs(m_currentIteration);
1340 const string refZExpr = "v_normalizedCoord.x";
1341 const bool needPixelCoordInShader = m_gatherType == GATHERTYPE_OFFSET_DYNAMIC;
1342 const bool needNormalizedCoordInShader = needPixelCoordInShader || isDepthFormat(m_textureFormat);
1343
1344 // Generate a program appropriate for this iteration.
1345
1346 m_program = MovePtr<ShaderProgram>(new ShaderProgram(renderCtx, genProgramSources(m_gatherType, m_textureType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange())));
1347 if (m_currentIteration == 0)
1348 m_testCtx.getLog() << *m_program;
1349 else
1350 m_testCtx.getLog() << TestLog::Message << "Using a program similar to the previous one, except with a gather function call as follows:\n"
1351 << genGatherFuncCall(m_gatherType, m_textureFormat, gatherArgs, refZExpr, getOffsetRange(), 0)
1352 << TestLog::EndMessage;
1353 if (!m_program->isOk())
1354 {
1355 if (m_currentIteration != 0)
1356 m_testCtx.getLog() << *m_program;
1357 TCU_FAIL("Failed to build program");
1358 }
1359
1360 // Render.
1361
1362 gl.viewport(0, 0, RENDER_SIZE.x(), RENDER_SIZE.y());
1363 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1364 gl.clear(GL_COLOR_BUFFER_BIT);
1365
1366 {
1367 const float position[4*2] =
1368 {
1369 -1.0f, -1.0f,
1370 -1.0f, +1.0f,
1371 +1.0f, -1.0f,
1372 +1.0f, +1.0f,
1373 };
1374
1375 const float normalizedCoord[4*2] =
1376 {
1377 0.0f, 0.0f,
1378 0.0f, 1.0f,
1379 1.0f, 0.0f,
1380 1.0f, 1.0f,
1381 };
1382
1383 const vector<float> texCoord = computeQuadTexCoord(m_currentIteration);
1384
1385 vector<glu::VertexArrayBinding> attrBindings;
1386 attrBindings.push_back(glu::va::Float("a_position", 2, 4, 0, &position[0]));
1387 attrBindings.push_back(glu::va::Float("a_texCoord", (int)texCoord.size()/4, 4, 0, &texCoord[0]));
1388 if (needNormalizedCoordInShader)
1389 attrBindings.push_back(glu::va::Float("a_normalizedCoord", 2, 4, 0, &normalizedCoord[0]));
1390
1391 const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 };
1392
1393 gl.useProgram(m_program->getProgram());
1394
1395 {
1396 const int samplerUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1397 TCU_CHECK(samplerUniformLocation >= 0);
1398 gl.uniform1i(samplerUniformLocation, 0);
1399 }
1400
1401 if (needPixelCoordInShader)
1402 {
1403 const int viewportSizeUniformLocation = gl.getUniformLocation(m_program->getProgram(), "u_viewportSize");
1404 TCU_CHECK(viewportSizeUniformLocation >= 0);
1405 gl.uniform2f(viewportSizeUniformLocation, (float)RENDER_SIZE.x(), (float)RENDER_SIZE.y());
1406 }
1407
1408 if (texCoord.size() == 2*4)
1409 {
1410 Vec2 texCoordVec[4];
1411 computeTexCoordVecs(texCoord, texCoordVec);
1412 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage;
1413 }
1414 else if (texCoord.size() == 3*4)
1415 {
1416 Vec3 texCoordVec[4];
1417 computeTexCoordVecs(texCoord, texCoordVec);
1418 log << TestLog::Message << "Texture coordinates run from " << texCoordVec[0] << " to " << texCoordVec[3] << TestLog::EndMessage;
1419 }
1420 else
1421 DE_ASSERT(false);
1422
1423 glu::draw(renderCtx, m_program->getProgram(), (int)attrBindings.size(), &attrBindings[0],
1424 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1425 }
1426
1427 // Verify result.
1428
1429 {
1430 const tcu::TextureLevel rendered = getPixels(renderCtx, RENDER_SIZE, m_colorBufferFormat);
1431
1432 if (!verify(m_currentIteration, rendered.getAccess()))
1433 {
1434 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed");
1435 return STOP;
1436 }
1437 }
1438
1439 m_currentIteration++;
1440 if (m_currentIteration == (int)getNumIterations())
1441 {
1442 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1443 return STOP;
1444 }
1445 else
1446 return CONTINUE;
1447 }
1448
1449 template <typename TexViewT, typename TexCoordT>
verify(const ConstPixelBufferAccess & rendered,const TexViewT & texture,const TexCoordT (& texCoords)[4],const GatherArgs & gatherArgs) const1450 bool TextureGatherCase::verify (const ConstPixelBufferAccess& rendered,
1451 const TexViewT& texture,
1452 const TexCoordT (&texCoords)[4],
1453 const GatherArgs& gatherArgs) const
1454 {
1455 TestLog& log = m_testCtx.getLog();
1456
1457 if (m_flags & GATHERCASE_MIPMAP_INCOMPLETE)
1458 {
1459 const int componentNdx = de::max(0, gatherArgs.componentNdx);
1460 const Vec4 incompleteColor (0.0f, 0.0f, 0.0f, 1.0f);
1461 const Vec4 refColor (incompleteColor[componentNdx]);
1462 const bool isOk = verifySingleColored(log, rendered, refColor);
1463
1464 if (!isOk)
1465 log << TestLog::Message << "Note: expected color " << refColor << " for all pixels; "
1466 << incompleteColor[componentNdx] << " is component at index " << componentNdx
1467 << " in the color " << incompleteColor << ", which is used for incomplete textures" << TestLog::EndMessage;
1468
1469 return isOk;
1470 }
1471 else
1472 {
1473 DE_ASSERT(m_colorBufferFormat.order == tcu::TextureFormat::RGBA);
1474 DE_ASSERT(m_colorBufferFormat.type == tcu::TextureFormat::UNORM_INT8 ||
1475 m_colorBufferFormat.type == tcu::TextureFormat::UNSIGNED_INT8 ||
1476 m_colorBufferFormat.type == tcu::TextureFormat::SIGNED_INT8);
1477
1478 const MovePtr<PixelOffsets> pixelOffsets = makePixelOffsetsFunctor(m_gatherType, gatherArgs, getOffsetRange());
1479 const tcu::PixelFormat pixelFormat = tcu::PixelFormat(8,8,8,8);
1480 const IVec4 colorBits = tcu::max(gls::TextureTestUtil::getBitsVec(pixelFormat) - 1, tcu::IVec4(0));
1481 const IVec3 coordBits = m_textureType == TEXTURETYPE_2D ? IVec3(20,20,0)
1482 : m_textureType == TEXTURETYPE_CUBE ? IVec3(10,10,10)
1483 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(20,20,20)
1484 : IVec3(-1);
1485 const IVec3 uvwBits = m_textureType == TEXTURETYPE_2D ? IVec3(7,7,0)
1486 : m_textureType == TEXTURETYPE_CUBE ? IVec3(6,6,0)
1487 : m_textureType == TEXTURETYPE_2D_ARRAY ? IVec3(7,7,7)
1488 : IVec3(-1);
1489 tcu::Sampler sampler;
1490 sampler.wrapS = m_wrapS;
1491 sampler.wrapT = m_wrapT;
1492 sampler.compare = m_shadowCompareMode;
1493
1494 if (isDepthFormat(m_textureFormat))
1495 {
1496 tcu::TexComparePrecision comparePrec;
1497 comparePrec.coordBits = coordBits;
1498 comparePrec.uvwBits = uvwBits;
1499 comparePrec.referenceBits = 16;
1500 comparePrec.resultBits = pixelFormat.redBits-1;
1501
1502 return verifyGatherOffsetsCompare(log, rendered, texture, texCoords, sampler, comparePrec, PixelCompareRefZDefault(RENDER_SIZE), *pixelOffsets);
1503 }
1504 else
1505 {
1506 const int componentNdx = de::max(0, gatherArgs.componentNdx);
1507
1508 if (isUnormFormatType(m_textureFormat.type))
1509 {
1510 tcu::LookupPrecision lookupPrec;
1511 lookupPrec.colorThreshold = tcu::computeFixedPointThreshold(colorBits);
1512 lookupPrec.coordBits = coordBits;
1513 lookupPrec.uvwBits = uvwBits;
1514 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat);
1515 return verifyGatherOffsets<float>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
1516 }
1517 else if (isUIntFormatType(m_textureFormat.type) || isSIntFormatType(m_textureFormat.type))
1518 {
1519 tcu::IntLookupPrecision lookupPrec;
1520 lookupPrec.colorThreshold = UVec4(0);
1521 lookupPrec.coordBits = coordBits;
1522 lookupPrec.uvwBits = uvwBits;
1523 lookupPrec.colorMask = gls::TextureTestUtil::getCompareMask(pixelFormat);
1524
1525 if (isUIntFormatType(m_textureFormat.type))
1526 return verifyGatherOffsets<deUint32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
1527 else if (isSIntFormatType(m_textureFormat.type))
1528 return verifyGatherOffsets<deInt32>(log, rendered, texture, texCoords, sampler, lookupPrec, componentNdx, *pixelOffsets);
1529 else
1530 {
1531 DE_ASSERT(false);
1532 return false;
1533 }
1534 }
1535 else
1536 {
1537 DE_ASSERT(false);
1538 return false;
1539 }
1540 }
1541 }
1542 }
1543
generateBasic2DCaseIterations(GatherType gatherType,const tcu::TextureFormat & textureFormat,const IVec2 & offsetRange)1544 vector<GatherArgs> generateBasic2DCaseIterations (GatherType gatherType, const tcu::TextureFormat& textureFormat, const IVec2& offsetRange)
1545 {
1546 const int numComponentCases = isDepthFormat(textureFormat) ? 1 : 4+1; // \note For non-depth textures, test explicit components 0 to 3 and implicit component 0.
1547 vector<GatherArgs> result;
1548
1549 for (int componentCaseNdx = 0; componentCaseNdx < numComponentCases; componentCaseNdx++)
1550 {
1551 const int componentNdx = componentCaseNdx - 1;
1552
1553 switch (gatherType)
1554 {
1555 case GATHERTYPE_BASIC:
1556 result.push_back(GatherArgs(componentNdx));
1557 break;
1558
1559 case GATHERTYPE_OFFSET:
1560 {
1561 const int min = offsetRange.x();
1562 const int max = offsetRange.y();
1563 const int hmin = divRoundToZero(min, 2);
1564 const int hmax = divRoundToZero(max, 2);
1565
1566 result.push_back(GatherArgs(componentNdx, IVec2(min, max)));
1567
1568 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal).
1569 {
1570 result.push_back(GatherArgs(componentNdx, IVec2(min, min)));
1571 result.push_back(GatherArgs(componentNdx, IVec2(max, min)));
1572 result.push_back(GatherArgs(componentNdx, IVec2(max, max)));
1573
1574 result.push_back(GatherArgs(componentNdx, IVec2(0, hmax)));
1575 result.push_back(GatherArgs(componentNdx, IVec2(hmin, 0)));
1576 result.push_back(GatherArgs(componentNdx, IVec2(0, 0)));
1577 }
1578
1579 break;
1580 }
1581
1582 case GATHERTYPE_OFFSET_DYNAMIC:
1583 result.push_back(GatherArgs(componentNdx));
1584 break;
1585
1586 case GATHERTYPE_OFFSETS:
1587 {
1588 const int min = offsetRange.x();
1589 const int max = offsetRange.y();
1590 const int hmin = divRoundToZero(min, 2);
1591 const int hmax = divRoundToZero(max, 2);
1592
1593 result.push_back(GatherArgs(componentNdx,
1594 IVec2(min, min),
1595 IVec2(min, max),
1596 IVec2(max, min),
1597 IVec2(max, max)));
1598
1599 if (componentCaseNdx == 0) // Don't test all offsets variants for all color components (they should be pretty orthogonal).
1600 result.push_back(GatherArgs(componentNdx,
1601 IVec2(min, hmax),
1602 IVec2(hmin, max),
1603 IVec2(0, hmax),
1604 IVec2(hmax, 0)));
1605 break;
1606 }
1607
1608 default:
1609 DE_ASSERT(false);
1610 }
1611 }
1612
1613 return result;
1614 }
1615
1616 class TextureGather2DCase : public TextureGatherCase
1617 {
1618 public:
TextureGather2DCase(Context & context,const char * name,const char * description,GatherType gatherType,OffsetSize offsetSize,tcu::TextureFormat textureFormat,tcu::Sampler::CompareMode shadowCompareMode,tcu::Sampler::WrapMode wrapS,tcu::Sampler::WrapMode wrapT,const MaybeTextureSwizzle & texSwizzle,tcu::Sampler::FilterMode minFilter,tcu::Sampler::FilterMode magFilter,int baseLevel,deUint32 flags,const IVec2 & textureSize)1619 TextureGather2DCase (Context& context,
1620 const char* name,
1621 const char* description,
1622 GatherType gatherType,
1623 OffsetSize offsetSize,
1624 tcu::TextureFormat textureFormat,
1625 tcu::Sampler::CompareMode shadowCompareMode,
1626 tcu::Sampler::WrapMode wrapS,
1627 tcu::Sampler::WrapMode wrapT,
1628 const MaybeTextureSwizzle& texSwizzle,
1629 tcu::Sampler::FilterMode minFilter,
1630 tcu::Sampler::FilterMode magFilter,
1631 int baseLevel,
1632 deUint32 flags,
1633 const IVec2& textureSize)
1634 : TextureGatherCase (context, name, description, TEXTURETYPE_2D, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags)
1635 , m_textureSize (textureSize)
1636 , m_swizzledTexture (tcu::TextureFormat(), 1, 1)
1637 {
1638 }
1639
1640 protected:
1641 void generateIterations (void);
1642 void createAndUploadTexture (void);
getNumIterations(void) const1643 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
getGatherArgs(int iterationNdx) const1644 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx]; }
1645 vector<float> computeQuadTexCoord (int iterationNdx) const;
1646 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const;
1647
1648 private:
1649 const IVec2 m_textureSize;
1650
1651 MovePtr<glu::Texture2D> m_texture;
1652 tcu::Texture2D m_swizzledTexture;
1653 vector<GatherArgs> m_iterations;
1654 };
1655
computeQuadTexCoord(int) const1656 vector<float> TextureGather2DCase::computeQuadTexCoord (int /* iterationNdx */) const
1657 {
1658 vector<float> res;
1659 gls::TextureTestUtil::computeQuadTexCoord2D(res, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f));
1660 return res;
1661 }
1662
generateIterations(void)1663 void TextureGather2DCase::generateIterations (void)
1664 {
1665 DE_ASSERT(m_iterations.empty());
1666 m_iterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
1667 }
1668
createAndUploadTexture(void)1669 void TextureGather2DCase::createAndUploadTexture (void)
1670 {
1671 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1672 const glw::Functions& gl = renderCtx.getFunctions();
1673 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat);
1674
1675 m_texture = MovePtr<glu::Texture2D>(new glu::Texture2D(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y()));
1676
1677 {
1678 tcu::Texture2D& refTexture = m_texture->getRefTexture();
1679 const int levelBegin = m_baseLevel;
1680 const int levelEnd = isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1;
1681 DE_ASSERT(m_baseLevel < refTexture.getNumLevels());
1682
1683 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
1684 {
1685 refTexture.allocLevel(levelNdx);
1686 const PixelBufferAccess& level = refTexture.getLevel(levelNdx);
1687 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed());
1688 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx), level)
1689 << TestLog::Message << "Note: texture level's size is " << IVec2(level.getWidth(), level.getHeight()) << TestLog::EndMessage;
1690 }
1691
1692 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle);
1693 }
1694
1695 gl.activeTexture(GL_TEXTURE0);
1696 m_texture->upload();
1697 }
1698
verify(int iterationNdx,const ConstPixelBufferAccess & rendered) const1699 bool TextureGather2DCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
1700 {
1701 Vec2 texCoords[4];
1702 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
1703 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx]);
1704 }
1705
1706 class TextureGather2DArrayCase : public TextureGatherCase
1707 {
1708 public:
TextureGather2DArrayCase(Context & context,const char * name,const char * description,GatherType gatherType,OffsetSize offsetSize,tcu::TextureFormat textureFormat,tcu::Sampler::CompareMode shadowCompareMode,tcu::Sampler::WrapMode wrapS,tcu::Sampler::WrapMode wrapT,const MaybeTextureSwizzle & texSwizzle,tcu::Sampler::FilterMode minFilter,tcu::Sampler::FilterMode magFilter,int baseLevel,deUint32 flags,const IVec3 & textureSize)1709 TextureGather2DArrayCase (Context& context,
1710 const char* name,
1711 const char* description,
1712 GatherType gatherType,
1713 OffsetSize offsetSize,
1714 tcu::TextureFormat textureFormat,
1715 tcu::Sampler::CompareMode shadowCompareMode,
1716 tcu::Sampler::WrapMode wrapS,
1717 tcu::Sampler::WrapMode wrapT,
1718 const MaybeTextureSwizzle& texSwizzle,
1719 tcu::Sampler::FilterMode minFilter,
1720 tcu::Sampler::FilterMode magFilter,
1721 int baseLevel,
1722 deUint32 flags,
1723 const IVec3& textureSize)
1724 : TextureGatherCase (context, name, description, TEXTURETYPE_2D_ARRAY, gatherType, offsetSize, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags)
1725 , m_textureSize (textureSize)
1726 , m_swizzledTexture (tcu::TextureFormat(), 1, 1, 1)
1727 {
1728 }
1729
1730 protected:
1731 void generateIterations (void);
1732 void createAndUploadTexture (void);
getNumIterations(void) const1733 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
getGatherArgs(int iterationNdx) const1734 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; }
1735 vector<float> computeQuadTexCoord (int iterationNdx) const;
1736 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const;
1737
1738 private:
1739 struct Iteration
1740 {
1741 GatherArgs gatherArgs;
1742 int layerNdx;
1743 };
1744
1745 const IVec3 m_textureSize;
1746
1747 MovePtr<glu::Texture2DArray> m_texture;
1748 tcu::Texture2DArray m_swizzledTexture;
1749 vector<Iteration> m_iterations;
1750 };
1751
computeQuadTexCoord(int iterationNdx) const1752 vector<float> TextureGather2DArrayCase::computeQuadTexCoord (int iterationNdx) const
1753 {
1754 vector<float> res;
1755 gls::TextureTestUtil::computeQuadTexCoord2DArray(res, m_iterations[iterationNdx].layerNdx, Vec2(-0.3f, -0.4f), Vec2(1.5f, 1.6f));
1756 return res;
1757 }
1758
generateIterations(void)1759 void TextureGather2DArrayCase::generateIterations (void)
1760 {
1761 DE_ASSERT(m_iterations.empty());
1762
1763 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
1764
1765 // \note Out-of-bounds layer indices are tested too.
1766 for (int layerNdx = -1; layerNdx < m_textureSize.z()+1; layerNdx++)
1767 {
1768 // Don't duplicate all cases for all layers.
1769 if (layerNdx == 0)
1770 {
1771 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1772 {
1773 m_iterations.push_back(Iteration());
1774 m_iterations.back().gatherArgs = basicIterations[basicNdx];
1775 m_iterations.back().layerNdx = layerNdx;
1776 }
1777 }
1778 else
1779 {
1780 // For other layers than 0, only test one component and one set of offsets per layer.
1781 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1782 {
1783 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == (layerNdx + 2) % 4)
1784 {
1785 m_iterations.push_back(Iteration());
1786 m_iterations.back().gatherArgs = basicIterations[basicNdx];
1787 m_iterations.back().layerNdx = layerNdx;
1788 break;
1789 }
1790 }
1791 }
1792 }
1793 }
1794
createAndUploadTexture(void)1795 void TextureGather2DArrayCase::createAndUploadTexture (void)
1796 {
1797 TestLog& log = m_testCtx.getLog();
1798 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1799 const glw::Functions& gl = renderCtx.getFunctions();
1800 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat);
1801
1802 m_texture = MovePtr<glu::Texture2DArray>(new glu::Texture2DArray(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize.x(), m_textureSize.y(), m_textureSize.z()));
1803
1804 {
1805 tcu::Texture2DArray& refTexture = m_texture->getRefTexture();
1806 const int levelBegin = m_baseLevel;
1807 const int levelEnd = isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1;
1808 DE_ASSERT(m_baseLevel < refTexture.getNumLevels());
1809
1810 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
1811 {
1812 refTexture.allocLevel(levelNdx);
1813 const PixelBufferAccess& level = refTexture.getLevel(levelNdx);
1814 fillWithRandomColorTiles(level, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed());
1815
1816 log << TestLog::ImageSet("InputTextureLevel", "Input texture, level " + de::toString(levelNdx));
1817 for (int layerNdx = 0; layerNdx < m_textureSize.z(); layerNdx++)
1818 log << TestLog::Image("InputTextureLevel" + de::toString(layerNdx) + "Layer" + de::toString(layerNdx),
1819 "Layer " + de::toString(layerNdx),
1820 tcu::getSubregion(level, 0, 0, layerNdx, level.getWidth(), level.getHeight(), 1));
1821 log << TestLog::EndImageSet
1822 << TestLog::Message << "Note: texture level's size is " << IVec3(level.getWidth(), level.getHeight(), level.getDepth()) << TestLog::EndMessage;
1823 }
1824
1825 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle);
1826 }
1827
1828 gl.activeTexture(GL_TEXTURE0);
1829 m_texture->upload();
1830 }
1831
verify(int iterationNdx,const ConstPixelBufferAccess & rendered) const1832 bool TextureGather2DArrayCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
1833 {
1834 Vec3 texCoords[4];
1835 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
1836 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::Texture2DArrayView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs);
1837 }
1838
1839 // \note Cube case always uses just basic textureGather(); offset versions are not defined for cube maps.
1840 class TextureGatherCubeCase : public TextureGatherCase
1841 {
1842 public:
TextureGatherCubeCase(Context & context,const char * name,const char * description,tcu::TextureFormat textureFormat,tcu::Sampler::CompareMode shadowCompareMode,tcu::Sampler::WrapMode wrapS,tcu::Sampler::WrapMode wrapT,const MaybeTextureSwizzle & texSwizzle,tcu::Sampler::FilterMode minFilter,tcu::Sampler::FilterMode magFilter,int baseLevel,deUint32 flags,int textureSize)1843 TextureGatherCubeCase (Context& context,
1844 const char* name,
1845 const char* description,
1846 tcu::TextureFormat textureFormat,
1847 tcu::Sampler::CompareMode shadowCompareMode,
1848 tcu::Sampler::WrapMode wrapS,
1849 tcu::Sampler::WrapMode wrapT,
1850 const MaybeTextureSwizzle& texSwizzle,
1851 tcu::Sampler::FilterMode minFilter,
1852 tcu::Sampler::FilterMode magFilter,
1853 int baseLevel,
1854 deUint32 flags,
1855 int textureSize)
1856 : TextureGatherCase (context, name, description, TEXTURETYPE_CUBE, GATHERTYPE_BASIC, OFFSETSIZE_NONE, textureFormat, shadowCompareMode, wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags)
1857 , m_textureSize (textureSize)
1858 , m_swizzledTexture (tcu::TextureFormat(), 1)
1859 {
1860 }
1861
1862 protected:
1863 void generateIterations (void);
1864 void createAndUploadTexture (void);
getNumIterations(void) const1865 int getNumIterations (void) const { DE_ASSERT(!m_iterations.empty()); return (int)m_iterations.size(); }
getGatherArgs(int iterationNdx) const1866 GatherArgs getGatherArgs (int iterationNdx) const { return m_iterations[iterationNdx].gatherArgs; }
1867 vector<float> computeQuadTexCoord (int iterationNdx) const;
1868 bool verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const;
1869
1870 private:
1871 struct Iteration
1872 {
1873 GatherArgs gatherArgs;
1874 tcu::CubeFace face;
1875 };
1876
1877 const int m_textureSize;
1878
1879 MovePtr<glu::TextureCube> m_texture;
1880 tcu::TextureCube m_swizzledTexture;
1881 vector<Iteration> m_iterations;
1882 };
1883
computeQuadTexCoord(int iterationNdx) const1884 vector<float> TextureGatherCubeCase::computeQuadTexCoord (int iterationNdx) const
1885 {
1886 const bool corners = (m_flags & GATHERCASE_DONT_SAMPLE_CUBE_CORNERS) == 0;
1887 const Vec2 minC = corners ? Vec2(-1.2f) : Vec2(-0.6f, -1.2f);
1888 const Vec2 maxC = corners ? Vec2( 1.2f) : Vec2( 0.6f, 1.2f);
1889 vector<float> res;
1890 gls::TextureTestUtil::computeQuadTexCoordCube(res, m_iterations[iterationNdx].face, minC, maxC);
1891 return res;
1892 }
1893
generateIterations(void)1894 void TextureGatherCubeCase::generateIterations (void)
1895 {
1896 DE_ASSERT(m_iterations.empty());
1897
1898 const vector<GatherArgs> basicIterations = generateBasic2DCaseIterations(m_gatherType, m_textureFormat, getOffsetRange());
1899
1900 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++)
1901 {
1902 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI;
1903
1904 // Don't duplicate all cases for all faces.
1905 if (cubeFaceI == 0)
1906 {
1907 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1908 {
1909 m_iterations.push_back(Iteration());
1910 m_iterations.back().gatherArgs = basicIterations[basicNdx];
1911 m_iterations.back().face = cubeFace;
1912 }
1913 }
1914 else
1915 {
1916 // For other faces than first, only test one component per face.
1917 for (int basicNdx = 0; basicNdx < (int)basicIterations.size(); basicNdx++)
1918 {
1919 if (isDepthFormat(m_textureFormat) || basicIterations[basicNdx].componentNdx == cubeFaceI % 4)
1920 {
1921 m_iterations.push_back(Iteration());
1922 m_iterations.back().gatherArgs = basicIterations[basicNdx];
1923 m_iterations.back().face = cubeFace;
1924 break;
1925 }
1926 }
1927 }
1928 }
1929 }
1930
createAndUploadTexture(void)1931 void TextureGatherCubeCase::createAndUploadTexture (void)
1932 {
1933 TestLog& log = m_testCtx.getLog();
1934 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1935 const glw::Functions& gl = renderCtx.getFunctions();
1936 const tcu::TextureFormatInfo texFmtInfo = tcu::getTextureFormatInfo(m_textureFormat);
1937
1938 m_texture = MovePtr<glu::TextureCube>(new glu::TextureCube(renderCtx, glu::getInternalFormat(m_textureFormat), m_textureSize));
1939
1940 {
1941 tcu::TextureCube& refTexture = m_texture->getRefTexture();
1942 const int levelBegin = m_baseLevel;
1943 const int levelEnd = isMipmapFilter(m_minFilter) && !(m_flags & GATHERCASE_MIPMAP_INCOMPLETE) ? refTexture.getNumLevels() : m_baseLevel+1;
1944 DE_ASSERT(m_baseLevel < refTexture.getNumLevels());
1945
1946 for (int levelNdx = levelBegin; levelNdx < levelEnd; levelNdx++)
1947 {
1948 log << TestLog::ImageSet("InputTextureLevel" + de::toString(levelNdx), "Input texture, level " + de::toString(levelNdx));
1949
1950 for (int cubeFaceI = 0; cubeFaceI < tcu::CUBEFACE_LAST; cubeFaceI++)
1951 {
1952 const tcu::CubeFace cubeFace = (tcu::CubeFace)cubeFaceI;
1953 refTexture.allocLevel(cubeFace, levelNdx);
1954 const PixelBufferAccess& levelFace = refTexture.getLevelFace(levelNdx, cubeFace);
1955 fillWithRandomColorTiles(levelFace, texFmtInfo.valueMin, texFmtInfo.valueMax, (deUint32)m_testCtx.getCommandLine().getBaseSeed() ^ (deUint32)cubeFaceI);
1956
1957 m_testCtx.getLog() << TestLog::Image("InputTextureLevel" + de::toString(levelNdx) + "Face" + de::toString((int)cubeFace),
1958 de::toString(cubeFace),
1959 levelFace);
1960 }
1961
1962 log << TestLog::EndImageSet
1963 << TestLog::Message << "Note: texture level's size is " << refTexture.getLevelFace(levelNdx, tcu::CUBEFACE_NEGATIVE_X).getWidth() << TestLog::EndMessage;
1964 }
1965
1966 swizzleTexture(m_swizzledTexture, refTexture, m_textureSwizzle);
1967 }
1968
1969 gl.activeTexture(GL_TEXTURE0);
1970 m_texture->upload();
1971 }
1972
verify(int iterationNdx,const ConstPixelBufferAccess & rendered) const1973 bool TextureGatherCubeCase::verify (int iterationNdx, const ConstPixelBufferAccess& rendered) const
1974 {
1975 Vec3 texCoords[4];
1976 computeTexCoordVecs(computeQuadTexCoord(iterationNdx), texCoords);
1977 return TextureGatherCase::verify(rendered, getOneLevelSubView(tcu::TextureCubeView(m_swizzledTexture), m_baseLevel), texCoords, m_iterations[iterationNdx].gatherArgs);
1978 }
1979
makeTextureGatherCase(TextureType textureType,Context & context,const char * name,const char * description,GatherType gatherType,OffsetSize offsetSize,tcu::TextureFormat textureFormat,tcu::Sampler::CompareMode shadowCompareMode,tcu::Sampler::WrapMode wrapS,tcu::Sampler::WrapMode wrapT,const MaybeTextureSwizzle & texSwizzle,tcu::Sampler::FilterMode minFilter,tcu::Sampler::FilterMode magFilter,int baseLevel,const IVec3 & textureSize,deUint32 flags=0)1980 static inline TextureGatherCase* makeTextureGatherCase (TextureType textureType,
1981 Context& context,
1982 const char* name,
1983 const char* description,
1984 GatherType gatherType,
1985 OffsetSize offsetSize,
1986 tcu::TextureFormat textureFormat,
1987 tcu::Sampler::CompareMode shadowCompareMode,
1988 tcu::Sampler::WrapMode wrapS,
1989 tcu::Sampler::WrapMode wrapT,
1990 const MaybeTextureSwizzle& texSwizzle,
1991 tcu::Sampler::FilterMode minFilter,
1992 tcu::Sampler::FilterMode magFilter,
1993 int baseLevel,
1994 const IVec3& textureSize,
1995 deUint32 flags = 0)
1996 {
1997 switch (textureType)
1998 {
1999 case TEXTURETYPE_2D:
2000 return new TextureGather2DCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode,
2001 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.swizzle(0, 1));
2002
2003 case TEXTURETYPE_2D_ARRAY:
2004 return new TextureGather2DArrayCase(context, name, description, gatherType, offsetSize, textureFormat, shadowCompareMode,
2005 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize);
2006
2007 case TEXTURETYPE_CUBE:
2008 DE_ASSERT(gatherType == GATHERTYPE_BASIC);
2009 DE_ASSERT(offsetSize == OFFSETSIZE_NONE);
2010 return new TextureGatherCubeCase(context, name, description, textureFormat, shadowCompareMode,
2011 wrapS, wrapT, texSwizzle, minFilter, magFilter, baseLevel, flags, textureSize.x());
2012
2013 default:
2014 DE_ASSERT(false);
2015 return DE_NULL;
2016 }
2017 }
2018
2019 } // anonymous
2020
TextureGatherTests(Context & context)2021 TextureGatherTests::TextureGatherTests (Context& context)
2022 : TestCaseGroup(context, "gather", "textureGather* tests")
2023 {
2024 }
2025
compareModeName(tcu::Sampler::CompareMode mode)2026 static inline const char* compareModeName (tcu::Sampler::CompareMode mode)
2027 {
2028 switch (mode)
2029 {
2030 case tcu::Sampler::COMPAREMODE_LESS: return "less";
2031 case tcu::Sampler::COMPAREMODE_LESS_OR_EQUAL: return "less_or_equal";
2032 case tcu::Sampler::COMPAREMODE_GREATER: return "greater";
2033 case tcu::Sampler::COMPAREMODE_GREATER_OR_EQUAL: return "greater_or_equal";
2034 case tcu::Sampler::COMPAREMODE_EQUAL: return "equal";
2035 case tcu::Sampler::COMPAREMODE_NOT_EQUAL: return "not_equal";
2036 case tcu::Sampler::COMPAREMODE_ALWAYS: return "always";
2037 case tcu::Sampler::COMPAREMODE_NEVER: return "never";
2038 default: DE_ASSERT(false); return DE_NULL;
2039 }
2040 }
2041
init(void)2042 void TextureGatherTests::init (void)
2043 {
2044 const struct
2045 {
2046 const char* name;
2047 TextureType type;
2048 } textureTypes[] =
2049 {
2050 { "2d", TEXTURETYPE_2D },
2051 { "2d_array", TEXTURETYPE_2D_ARRAY },
2052 { "cube", TEXTURETYPE_CUBE }
2053 };
2054
2055 const struct
2056 {
2057 const char* name;
2058 tcu::TextureFormat format;
2059 } formats[] =
2060 {
2061 { "rgba8", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) },
2062 { "rgba8ui", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8) },
2063 { "rgba8i", tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8) },
2064 { "depth32f", tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT) }
2065 };
2066
2067 const struct
2068 {
2069 const char* name;
2070 IVec3 size;
2071 } textureSizes[] =
2072 {
2073 { "size_pot", IVec3(64, 64, 3) },
2074 { "size_npot", IVec3(17, 23, 3) }
2075 };
2076
2077 const struct
2078 {
2079 const char* name;
2080 tcu::Sampler::WrapMode mode;
2081 } wrapModes[] =
2082 {
2083 { "clamp_to_edge", tcu::Sampler::CLAMP_TO_EDGE },
2084 { "repeat", tcu::Sampler::REPEAT_GL },
2085 { "mirrored_repeat", tcu::Sampler::MIRRORED_REPEAT_GL }
2086 };
2087
2088 for (int gatherTypeI = 0; gatherTypeI < GATHERTYPE_LAST; gatherTypeI++)
2089 {
2090 const GatherType gatherType = (GatherType)gatherTypeI;
2091 TestCaseGroup* const gatherTypeGroup = new TestCaseGroup(m_context, gatherTypeName(gatherType), gatherTypeDescription(gatherType));
2092 addChild(gatherTypeGroup);
2093
2094 for (int offsetSizeI = 0; offsetSizeI < OFFSETSIZE_LAST; offsetSizeI++)
2095 {
2096 const OffsetSize offsetSize = (OffsetSize)offsetSizeI;
2097 if ((gatherType == GATHERTYPE_BASIC) != (offsetSize == OFFSETSIZE_NONE))
2098 continue;
2099
2100 TestCaseGroup* const offsetSizeGroup = offsetSize == OFFSETSIZE_NONE ?
2101 gatherTypeGroup :
2102 new TestCaseGroup(m_context,
2103 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "min_required_offset"
2104 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "implementation_offset"
2105 : DE_NULL,
2106 offsetSize == OFFSETSIZE_MINIMUM_REQUIRED ? "Use offsets within GL minimum required range"
2107 : offsetSize == OFFSETSIZE_IMPLEMENTATION_MAXIMUM ? "Use offsets within the implementation range"
2108 : DE_NULL);
2109 if (offsetSizeGroup != gatherTypeGroup)
2110 gatherTypeGroup->addChild(offsetSizeGroup);
2111
2112 for (int textureTypeNdx = 0; textureTypeNdx < DE_LENGTH_OF_ARRAY(textureTypes); textureTypeNdx++)
2113 {
2114 const TextureType textureType = textureTypes[textureTypeNdx].type;
2115
2116 if (textureType == TEXTURETYPE_CUBE && gatherType != GATHERTYPE_BASIC)
2117 continue;
2118
2119 TestCaseGroup* const textureTypeGroup = new TestCaseGroup(m_context, textureTypes[textureTypeNdx].name, "");
2120 offsetSizeGroup->addChild(textureTypeGroup);
2121
2122 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
2123 {
2124 const tcu::TextureFormat& format = formats[formatNdx].format;
2125 TestCaseGroup* const formatGroup = new TestCaseGroup(m_context, formats[formatNdx].name, "");
2126 textureTypeGroup->addChild(formatGroup);
2127
2128 for (int noCornersI = 0; noCornersI <= ((textureType == TEXTURETYPE_CUBE)?1:0); noCornersI++)
2129 {
2130 const bool noCorners = noCornersI!= 0;
2131 TestCaseGroup* const cornersGroup = noCorners
2132 ? new TestCaseGroup(m_context, "no_corners", "Test case variants that don't sample around cube map corners")
2133 : formatGroup;
2134
2135 if (formatGroup != cornersGroup)
2136 formatGroup->addChild(cornersGroup);
2137
2138 for (int textureSizeNdx = 0; textureSizeNdx < DE_LENGTH_OF_ARRAY(textureSizes); textureSizeNdx++)
2139 {
2140 const IVec3& textureSize = textureSizes[textureSizeNdx].size;
2141 TestCaseGroup* const textureSizeGroup = new TestCaseGroup(m_context, textureSizes[textureSizeNdx].name, "");
2142 cornersGroup->addChild(textureSizeGroup);
2143
2144 for (int compareModeI = 0; compareModeI < tcu::Sampler::COMPAREMODE_LAST; compareModeI++)
2145 {
2146 const tcu::Sampler::CompareMode compareMode = (tcu::Sampler::CompareMode)compareModeI;
2147
2148 if ((compareMode != tcu::Sampler::COMPAREMODE_NONE) != isDepthFormat(format))
2149 continue;
2150
2151 if (compareMode != tcu::Sampler::COMPAREMODE_NONE &&
2152 compareMode != tcu::Sampler::COMPAREMODE_LESS &&
2153 compareMode != tcu::Sampler::COMPAREMODE_GREATER)
2154 continue;
2155
2156 TestCaseGroup* const compareModeGroup = compareMode == tcu::Sampler::COMPAREMODE_NONE ?
2157 textureSizeGroup :
2158 new TestCaseGroup(m_context,
2159 (string() + "compare_" + compareModeName(compareMode)).c_str(),
2160 "");
2161 if (compareModeGroup != textureSizeGroup)
2162 textureSizeGroup->addChild(compareModeGroup);
2163
2164 for (int wrapCaseNdx = 0; wrapCaseNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapCaseNdx++)
2165 {
2166 const int wrapSNdx = wrapCaseNdx;
2167 const int wrapTNdx = (wrapCaseNdx + 1) % DE_LENGTH_OF_ARRAY(wrapModes);
2168 const tcu::Sampler::WrapMode wrapS = wrapModes[wrapSNdx].mode;
2169 const tcu::Sampler::WrapMode wrapT = wrapModes[wrapTNdx].mode;
2170
2171 const string caseName = string() + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
2172
2173 compareModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode, wrapS, wrapT,
2174 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, textureSize,
2175 noCorners ? GATHERCASE_DONT_SAMPLE_CUBE_CORNERS : 0));
2176 }
2177 }
2178 }
2179 }
2180
2181 if (offsetSize != OFFSETSIZE_MINIMUM_REQUIRED) // Don't test all features for both offset size types, as they should be rather orthogonal.
2182 {
2183 if (!isDepthFormat(format))
2184 {
2185 TestCaseGroup* const swizzleGroup = new TestCaseGroup(m_context, "texture_swizzle", "");
2186 formatGroup->addChild(swizzleGroup);
2187
2188 DE_STATIC_ASSERT(TEXTURESWIZZLECOMPONENT_R == 0);
2189 for (int swizzleCaseNdx = 0; swizzleCaseNdx < TEXTURESWIZZLECOMPONENT_LAST; swizzleCaseNdx++)
2190 {
2191 MaybeTextureSwizzle swizzle = MaybeTextureSwizzle::createSomeTextureSwizzle();
2192 string caseName;
2193
2194 for (int i = 0; i < 4; i++)
2195 {
2196 swizzle.getSwizzle()[i] = (TextureSwizzleComponent)((swizzleCaseNdx + i) % (int)TEXTURESWIZZLECOMPONENT_LAST);
2197 caseName += (i > 0 ? "_" : "") + de::toLower(de::toString(swizzle.getSwizzle()[i]));
2198 }
2199
2200 swizzleGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format,
2201 tcu::Sampler::COMPAREMODE_NONE, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
2202 swizzle, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0, IVec3(64, 64, 3)));
2203 }
2204 }
2205
2206 {
2207 TestCaseGroup* const filterModeGroup = new TestCaseGroup(m_context, "filter_mode", "Test that filter modes have no effect");
2208 formatGroup->addChild(filterModeGroup);
2209
2210 const struct
2211 {
2212 const char* name;
2213 tcu::Sampler::FilterMode filter;
2214 } magFilters[] =
2215 {
2216 { "linear", tcu::Sampler::LINEAR },
2217 { "nearest", tcu::Sampler::NEAREST }
2218 };
2219
2220 const struct
2221 {
2222 const char* name;
2223 tcu::Sampler::FilterMode filter;
2224 } minFilters[] =
2225 {
2226 // \note Don't test NEAREST here, as it's covered by other cases.
2227 { "linear", tcu::Sampler::LINEAR },
2228 { "nearest_mipmap_nearest", tcu::Sampler::NEAREST_MIPMAP_NEAREST },
2229 { "nearest_mipmap_linear", tcu::Sampler::NEAREST_MIPMAP_LINEAR },
2230 { "linear_mipmap_nearest", tcu::Sampler::LINEAR_MIPMAP_NEAREST },
2231 { "linear_mipmap_linear", tcu::Sampler::LINEAR_MIPMAP_LINEAR },
2232 };
2233
2234 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilters); minFilterNdx++)
2235 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilters); magFilterNdx++)
2236 {
2237 const tcu::Sampler::FilterMode minFilter = minFilters[minFilterNdx].filter;
2238 const tcu::Sampler::FilterMode magFilter = magFilters[magFilterNdx].filter;
2239 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
2240
2241 if ((isUnormFormatType(format.type) || isDepthFormat(format)) && magFilter == tcu::Sampler::NEAREST)
2242 continue; // Covered by other cases.
2243 if ((isUIntFormatType(format.type) || isSIntFormatType(format.type)) &&
2244 (magFilter != tcu::Sampler::NEAREST || minFilter != tcu::Sampler::NEAREST_MIPMAP_NEAREST))
2245 continue;
2246
2247 const string caseName = string() + "min_" + minFilters[minFilterNdx].name + "_mag_" + magFilters[magFilterNdx].name;
2248
2249 filterModeGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format, compareMode,
2250 tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, MaybeTextureSwizzle::createNoneTextureSwizzle(),
2251 minFilter, magFilter, 0, IVec3(64, 64, 3)));
2252 }
2253 }
2254
2255 {
2256 TestCaseGroup* const baseLevelGroup = new TestCaseGroup(m_context, "base_level", "");
2257 formatGroup->addChild(baseLevelGroup);
2258
2259 for (int baseLevel = 1; baseLevel <= 2; baseLevel++)
2260 {
2261 const string caseName = "level_" + de::toString(baseLevel);
2262 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
2263 baseLevelGroup->addChild(makeTextureGatherCase(textureType, m_context, caseName.c_str(), "", gatherType, offsetSize, format,
2264 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
2265 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST, tcu::Sampler::NEAREST,
2266 baseLevel, IVec3(64, 64, 3)));
2267 }
2268 }
2269
2270 // What shadow textures should return for incomplete textures is unclear.
2271 // Integer and unsigned integer lookups from incomplete textures return undefined values.
2272 if (!isDepthFormat(format) && !isSIntFormatType(format.type) && !isUIntFormatType(format.type))
2273 {
2274 TestCaseGroup* const incompleteGroup = new TestCaseGroup(m_context, "incomplete", "Test that textureGather* takes components from (0,0,0,1) for incomplete textures");
2275 formatGroup->addChild(incompleteGroup);
2276
2277 const tcu::Sampler::CompareMode compareMode = isDepthFormat(format) ? tcu::Sampler::COMPAREMODE_LESS : tcu::Sampler::COMPAREMODE_NONE;
2278 incompleteGroup->addChild(makeTextureGatherCase(textureType, m_context, "mipmap_incomplete", "", gatherType, offsetSize, format,
2279 compareMode, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL,
2280 MaybeTextureSwizzle::createNoneTextureSwizzle(), tcu::Sampler::NEAREST_MIPMAP_NEAREST, tcu::Sampler::NEAREST,
2281 0, IVec3(64, 64, 3), GATHERCASE_MIPMAP_INCOMPLETE));
2282 }
2283 }
2284 }
2285 }
2286 }
2287 }
2288 }
2289
2290 } // Functional
2291 } // gles31
2292 } // deqp
2293