5784c375e447341cb332d7d8ea1d2f8c3db0647d
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fTextureFilteringTests.cpp
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 Texture filtering tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fTextureFilteringTests.hpp"
25
26 #include "glsTextureTestUtil.hpp"
27
28 #include "gluPixelTransfer.hpp"
29 #include "gluTexture.hpp"
30 #include "gluTextureUtil.hpp"
31
32 #include "tcuCommandLine.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "tcuTexLookupVerifier.hpp"
36 #include "tcuVectorUtil.hpp"
37
38 #include "deStringUtil.hpp"
39 #include "deString.h"
40
41 #include "glwFunctions.hpp"
42 #include "glwEnums.hpp"
43
44 namespace deqp
45 {
46 namespace gles31
47 {
48 namespace Functional
49 {
50
51 using std::vector;
52 using std::string;
53 using tcu::TestLog;
54 using namespace gls::TextureTestUtil;
55 using namespace glu::TextureTestUtil;
56
57 static const char* getFaceDesc (const tcu::CubeFace face)
58 {
59         switch (face)
60         {
61                 case tcu::CUBEFACE_NEGATIVE_X:  return "-X";
62                 case tcu::CUBEFACE_POSITIVE_X:  return "+X";
63                 case tcu::CUBEFACE_NEGATIVE_Y:  return "-Y";
64                 case tcu::CUBEFACE_POSITIVE_Y:  return "+Y";
65                 case tcu::CUBEFACE_NEGATIVE_Z:  return "-Z";
66                 case tcu::CUBEFACE_POSITIVE_Z:  return "+Z";
67                 default:
68                         DE_ASSERT(false);
69                         return DE_NULL;
70         }
71 }
72
73 static void logCubeArrayTexCoords(TestLog& log, vector<float>& texCoord)
74 {
75         const size_t numVerts = texCoord.size() / 4;
76
77         DE_ASSERT(texCoord.size() % 4 == 0);
78
79         for (size_t vertNdx = 0; vertNdx < numVerts; vertNdx++)
80         {
81                 const size_t    coordNdx        = vertNdx * 4;
82
83                 const float             u                       = texCoord[coordNdx + 0];
84                 const float             v                       = texCoord[coordNdx + 1];
85                 const float             w                       = texCoord[coordNdx + 2];
86                 const float             q                       = texCoord[coordNdx + 3];
87
88                 log << TestLog::Message
89                         << vertNdx << ": ("
90                         << u << ", "
91                         << v << ", "
92                         << w << ", "
93                         << q << ")"
94                         << TestLog::EndMessage;
95         }
96 }
97
98 // Cube map array filtering
99
100 class TextureCubeArrayFilteringCase : public TestCase
101 {
102 public:
103                                                                         TextureCubeArrayFilteringCase   (Context& context,
104                                                                                                                                          const char* name,
105                                                                                                                                          const char* desc,
106                                                                                                                                          deUint32 minFilter,
107                                                                                                                                          deUint32 magFilter,
108                                                                                                                                          deUint32 wrapS,
109                                                                                                                                          deUint32 wrapT,
110                                                                                                                                          deUint32 internalFormat,
111                                                                                                                                          int size,
112                                                                                                                                          int depth,
113                                                                                                                                          bool onlySampleFaceInterior = false);
114
115                                                                         ~TextureCubeArrayFilteringCase  (void);
116
117         void                                                    init                                                    (void);
118         void                                                    deinit                                                  (void);
119         IterateResult                                   iterate                                                 (void);
120
121 private:
122                                                                         TextureCubeArrayFilteringCase   (const TextureCubeArrayFilteringCase&);
123         TextureCubeArrayFilteringCase&  operator=                                               (const TextureCubeArrayFilteringCase&);
124
125         const deUint32                                  m_minFilter;
126         const deUint32                                  m_magFilter;
127         const deUint32                                  m_wrapS;
128         const deUint32                                  m_wrapT;
129
130         const deUint32                                  m_internalFormat;
131         const int                                               m_size;
132         const int                                               m_depth;
133
134         const bool                                              m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
135
136         struct FilterCase
137         {
138                 const glu::TextureCubeArray*    texture;
139                 tcu::Vec2                                               bottomLeft;
140                 tcu::Vec2                                               topRight;
141                 tcu::Vec2                                               layerRange;
142
143                 FilterCase (void)
144                         : texture(DE_NULL)
145                 {
146                 }
147
148                 FilterCase (const glu::TextureCubeArray* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_, const tcu::Vec2& layerRange_)
149                         : texture               (tex_)
150                         , bottomLeft    (bottomLeft_)
151                         , topRight              (topRight_)
152                         , layerRange    (layerRange_)
153                 {
154                 }
155         };
156
157         glu::TextureCubeArray*  m_gradientTex;
158         glu::TextureCubeArray*  m_gridTex;
159
160         TextureRenderer                 m_renderer;
161
162         std::vector<FilterCase> m_cases;
163         int                                             m_caseNdx;
164 };
165
166 TextureCubeArrayFilteringCase::TextureCubeArrayFilteringCase (Context& context,
167                                                                                                                           const char* name,
168                                                                                                                           const char* desc,
169                                                                                                                           deUint32 minFilter,
170                                                                                                                           deUint32 magFilter,
171                                                                                                                           deUint32 wrapS,
172                                                                                                                           deUint32 wrapT,
173                                                                                                                           deUint32 internalFormat,
174                                                                                                                           int size,
175                                                                                                                           int depth,
176                                                                                                                           bool onlySampleFaceInterior)
177         : TestCase                                      (context, name, desc)
178         , m_minFilter                           (minFilter)
179         , m_magFilter                           (magFilter)
180         , m_wrapS                                       (wrapS)
181         , m_wrapT                                       (wrapT)
182         , m_internalFormat                      (internalFormat)
183         , m_size                                        (size)
184         , m_depth                                       (depth)
185         , m_onlySampleFaceInterior      (onlySampleFaceInterior)
186         , m_gradientTex                         (DE_NULL)
187         , m_gridTex                                     (DE_NULL)
188         , m_renderer                            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_310_ES, glu::PRECISION_HIGHP)
189         , m_caseNdx                                     (0)
190 {
191 }
192
193 TextureCubeArrayFilteringCase::~TextureCubeArrayFilteringCase (void)
194 {
195         TextureCubeArrayFilteringCase::deinit();
196 }
197
198 void TextureCubeArrayFilteringCase::init (void)
199 {
200         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
201                 throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported");
202
203         try
204         {
205                 const tcu::TextureFormat                texFmt          = glu::mapGLInternalFormat(m_internalFormat);
206                 const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
207                 const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
208                 const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
209                 const int                                               numLevels       = deLog2Floor32(m_size) + 1;
210                 const int                                               numLayers       = m_depth / 6;
211
212                 // Create textures.
213                 m_gradientTex   = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
214                 m_gridTex               = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
215
216                 const tcu::IVec4 levelSwz[] =
217                 {
218                         tcu::IVec4(0,1,2,3),
219                         tcu::IVec4(2,1,3,0),
220                         tcu::IVec4(3,0,1,2),
221                         tcu::IVec4(1,3,2,0),
222                 };
223
224                 // Fill first gradient texture (gradient direction varies between layers).
225                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
226                 {
227                         m_gradientTex->getRefTexture().allocLevel(levelNdx);
228
229                         const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
230
231                         for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
232                         {
233                                 const tcu::IVec4        swz             = levelSwz[layerFaceNdx % DE_LENGTH_OF_ARRAY(levelSwz)];
234                                 const tcu::Vec4         gMin    = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
235                                 const tcu::Vec4         gMax    = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
236
237                                 tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax);
238                         }
239                 }
240
241                 // Fill second with grid texture (each layer has unique colors).
242                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
243                 {
244                         m_gridTex->getRefTexture().allocLevel(levelNdx);
245
246                         const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
247
248                         for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
249                         {
250                                 const deUint32  step    = 0x00ffffff / (numLevels*m_depth - 1);
251                                 const deUint32  rgb             = step * (levelNdx + layerFaceNdx*numLevels);
252                                 const deUint32  colorA  = 0xff000000 | rgb;
253                                 const deUint32  colorB  = 0xff000000 | ~rgb;
254
255                                 tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1),
256                                                                   4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
257                         }
258                 }
259
260                 // Upload.
261                 m_gradientTex->upload();
262                 m_gridTex->upload();
263
264                 // Test cases
265                 {
266                         const glu::TextureCubeArray* const      tex0    = m_gradientTex;
267                         const glu::TextureCubeArray* const      tex1    = m_gridTex;
268
269                         if (m_onlySampleFaceInterior)
270                         {
271                                 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f),     tcu::Vec2(0.8f,  0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));      // minification
272                                 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f),      tcu::Vec2(0.8f,  0.8f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));      // magnification
273                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f),     tcu::Vec2(0.8f,  0.8f), tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // minification
274                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f),       tcu::Vec2(0.6f,  0.5f), tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // magnification
275                         }
276                         else
277                         {
278                                 const bool isSingleSample = (m_context.getRenderTarget().getNumSamples() == 0);
279
280                                 // minification - w/ tweak to avoid hitting triangle edges with a face switchpoint in multisample configs
281                                 if (isSingleSample)
282                                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
283                                 else
284                                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f), tcu::Vec2(-0.5f, float(numLayers)+0.5f)));
285
286                                 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f),               tcu::Vec2(1.25f, 1.20f),        tcu::Vec2(-0.5f, float(numLayers)+0.5f)));      // magnification
287                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f),    tcu::Vec2(1.1f, 1.35f),         tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // minification
288                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f),             tcu::Vec2(-0.8f, -0.8f),        tcu::Vec2(float(numLayers)+0.5f, -0.5f)));      // magnification
289
290                                 // Layer rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
291                                 if (isSingleSample && (numLayers > 1))
292                                         m_cases.push_back(FilterCase(tex0,      tcu::Vec2(-2.0f, -1.5f  ),      tcu::Vec2(-0.1f,  0.9f), tcu::Vec2(1.50001f, 1.49999f)));
293                         }
294                 }
295
296                 m_caseNdx = 0;
297                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
298         }
299         catch (...)
300         {
301                 // Clean up to save memory.
302                 TextureCubeArrayFilteringCase::deinit();
303                 throw;
304         }
305 }
306
307 void TextureCubeArrayFilteringCase::deinit (void)
308 {
309         delete m_gradientTex;
310         delete m_gridTex;
311
312         m_gradientTex   = DE_NULL;
313         m_gridTex               = DE_NULL;
314
315         m_renderer.clear();
316         m_cases.clear();
317 }
318
319 TextureCubeArrayFilteringCase::IterateResult TextureCubeArrayFilteringCase::iterate (void)
320 {
321         TestLog&                                                log                             = m_testCtx.getLog();
322         const glu::RenderContext&               renderCtx               = m_context.getRenderContext();
323         const glw::Functions&                   gl                              = renderCtx.getFunctions();
324         const int                                               viewportSize    = 28;
325         const deUint32                                  randomSeed              = deStringHash(getName()) ^ deInt32Hash(m_caseNdx) ^ m_testCtx.getCommandLine().getBaseSeed();
326         const RandomViewport                    viewport                (m_context.getRenderTarget(), viewportSize, viewportSize, randomSeed);
327         const FilterCase&                               curCase                 = m_cases[m_caseNdx];
328         const tcu::TextureFormat                texFmt                  = curCase.texture->getRefTexture().getFormat();
329         const tcu::TextureFormatInfo    fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
330         const tcu::ScopedLogSection             section                 (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
331         ReferenceParams                                 refParams               (TEXTURETYPE_CUBE_ARRAY);
332
333         if (viewport.width < viewportSize || viewport.height < viewportSize)
334                 throw tcu::NotSupportedError("Render target too small", "", __FILE__, __LINE__);
335
336         // Params for reference computation.
337         refParams.sampler                                       = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
338         refParams.sampler.seamlessCubeMap       = true;
339         refParams.samplerType                           = getSamplerType(texFmt);
340         refParams.colorBias                                     = fmtInfo.lookupBias;
341         refParams.colorScale                            = fmtInfo.lookupScale;
342         refParams.lodMode                                       = LODMODE_EXACT;
343
344         gl.bindTexture  (GL_TEXTURE_CUBE_MAP_ARRAY, curCase.texture->getGLTexture());
345         gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER,      m_minFilter);
346         gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER,      m_magFilter);
347         gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S,          m_wrapS);
348         gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T,          m_wrapT);
349
350         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
351
352         m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
353
354         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
355         {
356                 const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
357                 tcu::Surface                    result          (viewport.width, viewport.height);
358                 vector<float>                   texCoord;
359
360                 computeQuadTexCoordCubeArray(texCoord, face, curCase.bottomLeft, curCase.topRight, curCase.layerRange);
361
362                 log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
363
364                 log << TestLog::Message << "Texture coordinates:" << TestLog::EndMessage;
365
366                 logCubeArrayTexCoords(log, texCoord);
367
368                 m_renderer.renderQuad(0, &texCoord[0], refParams);
369                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
370
371                 glu::readPixels(renderCtx, viewport.x, viewport.y, result.getAccess());
372                 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
373
374                 {
375                         const bool                              isNearestOnly   = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
376                         const tcu::PixelFormat  pixelFormat             = renderCtx.getRenderTarget().getPixelFormat();
377                         const tcu::IVec4                coordBits               = tcu::IVec4(10);
378                         const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
379                         tcu::LodPrecision               lodPrecision    (tcu::LodPrecision::RULE_OPENGL);
380                         tcu::LookupPrecision    lookupPrecision;
381
382                         lodPrecision.derivateBits               = 10;
383                         lodPrecision.lodBits                    = 5;
384                         lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
385                         lookupPrecision.coordBits               = coordBits.toWidth<3>();
386                         lookupPrecision.uvwBits                 = tcu::IVec3(6);
387                         lookupPrecision.colorMask               = getCompareMask(pixelFormat);
388
389                         const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
390                                                                                                                    &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
391
392                         if (!isHighQuality)
393                         {
394                                 // Evaluate against lower precision requirements.
395                                 lodPrecision.lodBits    = 4;
396                                 lookupPrecision.uvwBits = tcu::IVec3(4);
397
398                                 m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
399
400                                 const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
401                                                                                                           &texCoord[0], refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
402
403                                 if (!isOk)
404                                 {
405                                         m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
406                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
407                                 }
408                                 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
409                                         m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
410                         }
411                 }
412         }
413
414         m_caseNdx += 1;
415         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
416 }
417
418 TextureFilteringTests::TextureFilteringTests (Context& context)
419         : TestCaseGroup(context, "filtering", "Texture Filtering Tests")
420 {
421 }
422
423 TextureFilteringTests::~TextureFilteringTests (void)
424 {
425 }
426
427 void TextureFilteringTests::init (void)
428 {
429         static const struct
430         {
431                 const char*             name;
432                 deUint32                mode;
433         } wrapModes[] =
434         {
435                 { "clamp",              GL_CLAMP_TO_EDGE },
436                 { "repeat",             GL_REPEAT },
437                 { "mirror",             GL_MIRRORED_REPEAT }
438         };
439
440         static const struct
441         {
442                 const char*             name;
443                 deUint32                mode;
444         } minFilterModes[] =
445         {
446                 { "nearest",                            GL_NEAREST                                      },
447                 { "linear",                                     GL_LINEAR                                       },
448                 { "nearest_mipmap_nearest",     GL_NEAREST_MIPMAP_NEAREST       },
449                 { "linear_mipmap_nearest",      GL_LINEAR_MIPMAP_NEAREST        },
450                 { "nearest_mipmap_linear",      GL_NEAREST_MIPMAP_LINEAR        },
451                 { "linear_mipmap_linear",       GL_LINEAR_MIPMAP_LINEAR         }
452         };
453
454         static const struct
455         {
456                 const char*             name;
457                 deUint32                mode;
458         } magFilterModes[] =
459         {
460                 { "nearest",    GL_NEAREST },
461                 { "linear",             GL_LINEAR }
462         };
463
464         static const struct
465         {
466                 int size;
467                 int depth;
468         } sizesCubeArray[] =
469         {
470                 {   8,   6 },
471                 {  64,  12 },
472                 { 128,  12 },
473                 {   7,  12 },
474                 {  63,  18 }
475         };
476
477         static const struct
478         {
479                 const char*             name;
480                 deUint32                format;
481         } filterableFormatsByType[] =
482         {
483                 { "rgba16f",            GL_RGBA16F                      },
484                 { "r11f_g11f_b10f",     GL_R11F_G11F_B10F       },
485                 { "rgb9_e5",            GL_RGB9_E5                      },
486                 { "rgba8",                      GL_RGBA8                        },
487                 { "rgba8_snorm",        GL_RGBA8_SNORM          },
488                 { "rgb565",                     GL_RGB565                       },
489                 { "rgba4",                      GL_RGBA4                        },
490                 { "rgb5_a1",            GL_RGB5_A1                      },
491                 { "srgb8_alpha8",       GL_SRGB8_ALPHA8         },
492                 { "rgb10_a2",           GL_RGB10_A2                     }
493         };
494
495         // Cube map array texture filtering.
496         {
497                 tcu::TestCaseGroup* const groupCubeArray = new tcu::TestCaseGroup(m_testCtx, "cube_array", "Cube Map Array Texture Filtering");
498                 addChild(groupCubeArray);
499
500                 // Formats.
501                 {
502                         tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "Cube Map Array Texture Formats");
503                         groupCubeArray->addChild(formatsGroup);
504
505                         for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
506                         {
507                                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
508                                 {
509                                         const deUint32  minFilter       = minFilterModes[filterNdx].mode;
510                                         const char*             filterName      = minFilterModes[filterNdx].name;
511                                         const deUint32  format          = filterableFormatsByType[fmtNdx].format;
512                                         const char*             formatName      = filterableFormatsByType[fmtNdx].name;
513                                         const bool              isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
514                                         const deUint32  magFilter       = isMipmap ? GL_LINEAR : minFilter;
515                                         const string    name            = string(formatName) + "_" + filterName;
516                                         const deUint32  wrapS           = GL_REPEAT;
517                                         const deUint32  wrapT           = GL_REPEAT;
518                                         const int               size            = 64;
519                                         const int               depth           = 12;
520
521                                         formatsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
522                                                                                                                                                          name.c_str(), "",
523                                                                                                                                                          minFilter, magFilter,
524                                                                                                                                                          wrapS, wrapT,
525                                                                                                                                                          format,
526                                                                                                                                                          size, depth));
527                                 }
528                         }
529                 }
530
531                 // Sizes.
532                 {
533                         tcu::TestCaseGroup* const sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
534                         groupCubeArray->addChild(sizesGroup);
535
536                         for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCubeArray); sizeNdx++)
537                         {
538                                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
539                                 {
540                                         const deUint32  minFilter       = minFilterModes[filterNdx].mode;
541                                         const char*             filterName      = minFilterModes[filterNdx].name;
542                                         const deUint32  format          = GL_RGBA8;
543                                         const bool              isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
544                                         const deUint32  magFilter       = isMipmap ? GL_LINEAR : minFilter;
545                                         const deUint32  wrapS           = GL_REPEAT;
546                                         const deUint32  wrapT           = GL_REPEAT;
547                                         const int               size            = sizesCubeArray[sizeNdx].size;
548                                         const int               depth           = sizesCubeArray[sizeNdx].depth;
549                                         const string    name            = de::toString(size) + "x" + de::toString(size) + "x" + de::toString(depth) + "_" + filterName;
550
551                                         sizesGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
552                                                                                                                                                    name.c_str(), "",
553                                                                                                                                                    minFilter, magFilter,
554                                                                                                                                                    wrapS, wrapT,
555                                                                                                                                                    format,
556                                                                                                                                                    size, depth));
557                                 }
558                         }
559                 }
560
561                 // Wrap modes.
562                 {
563                         tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
564                         groupCubeArray->addChild(combinationsGroup);
565
566                         for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
567                         {
568                                 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
569                                 {
570                                         for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
571                                         {
572                                                 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
573                                                 {
574                                                         const deUint32  minFilter       = minFilterModes[minFilterNdx].mode;
575                                                         const deUint32  magFilter       = magFilterModes[magFilterNdx].mode;
576                                                         const deUint32  format          = GL_RGBA8;
577                                                         const deUint32  wrapS           = wrapModes[wrapSNdx].mode;
578                                                         const deUint32  wrapT           = wrapModes[wrapTNdx].mode;
579                                                         const int               size            = 63;
580                                                         const int               depth           = 12;
581                                                         const string    name            = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
582
583                                                         combinationsGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
584                                                                                                                                                                                   name.c_str(), "",
585                                                                                                                                                                                   minFilter, magFilter,
586                                                                                                                                                                                   wrapS, wrapT,
587                                                                                                                                                                                   format,
588                                                                                                                                                                                   size, depth));
589                                                 }
590                                         }
591                                 }
592                         }
593                 }
594
595                 // Cases with no visible cube edges.
596                 {
597                         tcu::TestCaseGroup* const onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
598                         groupCubeArray->addChild(onlyFaceInteriorGroup);
599
600                         for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
601                         {
602                                 const bool              isLinear        = isLinearI != 0;
603                                 const deUint32  filter          = isLinear ? GL_LINEAR : GL_NEAREST;
604
605                                 onlyFaceInteriorGroup->addChild(new TextureCubeArrayFilteringCase(m_context,
606                                                                                                                                                                   isLinear ? "linear" : "nearest", "",
607                                                                                                                                                                   filter, filter,
608                                                                                                                                                                   GL_REPEAT, GL_REPEAT,
609                                                                                                                                                                   GL_RGBA8,
610                                                                                                                                                                   63, 12,
611                                                                                                                                                                   true));
612                         }
613                 }
614         }
615 }
616
617 } // Functional
618 } // gles31
619 } // deqp