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