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