Relax LOD computation bounds; add mipmap.2d.projected to mustpass
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / texture / vktTextureFilteringTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Texture filtering tests.
24  *//*--------------------------------------------------------------------*/
25
26 #include "tcuVectorUtil.hpp"
27 #include "tcuTexVerifierUtil.hpp"
28 #include "vkImageUtil.hpp"
29 #include "vkMemUtil.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestCaseUtil.hpp"
35 #include "vktTestGroupUtil.hpp"
36 #include "vktTextureFilteringTests.hpp"
37 #include "vktTextureTestUtil.hpp"
38 #include <string>
39 #include <vector>
40
41 using namespace vk;
42
43 namespace vkt
44 {
45 namespace texture
46 {
47
48 namespace
49 {
50
51 using std::vector;
52 using std::string;
53 using tcu::TestLog;
54 using tcu::Sampler;
55
56 using namespace texture::util;
57 using namespace glu::TextureTestUtil;
58
59 enum
60 {
61         TEXCUBE_VIEWPORT_SIZE           = 28,
62
63         TEX2D_VIEWPORT_WIDTH            = 64,
64         TEX2D_VIEWPORT_HEIGHT           = 64,
65
66         TEX3D_VIEWPORT_WIDTH            = 64,
67         TEX3D_VIEWPORT_HEIGHT           = 64,
68 };
69
70 class Texture2DFilteringTestInstance : public TestInstance
71 {
72 public:
73         typedef Texture2DTestCaseParameters     ParameterType;
74
75                                                                                 Texture2DFilteringTestInstance          (Context& context, const ParameterType& testParameters);
76                                                                                 ~Texture2DFilteringTestInstance         (void);
77
78         virtual tcu::TestStatus                         iterate                                                         (void);
79 private:
80                                                                                 Texture2DFilteringTestInstance          (const Texture2DFilteringTestInstance& other);
81         Texture2DFilteringTestInstance&         operator=                                                       (const Texture2DFilteringTestInstance& other);
82
83         struct FilterCase
84         {
85                 int                                             textureIndex;
86
87                 tcu::Vec2                               minCoord;
88                 tcu::Vec2                               maxCoord;
89
90                 FilterCase (void)
91                         : textureIndex(-1)
92                 {
93                 }
94
95                 FilterCase (int tex_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
96                         : textureIndex  (tex_)
97                         , minCoord              (minCoord_)
98                         , maxCoord              (maxCoord_)
99                 {
100                 }
101         };
102
103         const ParameterType                     m_testParameters;
104         vector<TestTexture2DSp>         m_textures;
105         vector<FilterCase>                      m_cases;
106         TextureRenderer                         m_renderer;
107         int                                                     m_caseNdx;
108 };
109
110 Texture2DFilteringTestInstance::Texture2DFilteringTestInstance (Context& context, const ParameterType& testParameters)
111         : TestInstance                  (context)
112         , m_testParameters              (testParameters)
113         , m_renderer                    (context, testParameters.sampleCount, TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT)
114         , m_caseNdx                             (0)
115 {
116         const bool                                              mipmaps         = true;
117         const int                                               numLevels       = mipmaps ? deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height))+1 : 1;
118         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
119         const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
120         const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
121
122         // Create 2 textures.
123         m_textures.reserve(2);
124         for (int ndx = 0; ndx < 2; ndx++)
125                 m_textures.push_back(TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height)));
126
127         // Fill first gradient texture.
128         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
129         {
130                 const tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
131                 const tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
132
133                 tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, 0), gMin, gMax);
134         }
135
136         // Fill second with grid texture.
137         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
138         {
139                 const deUint32  step    = 0x00ffffff / numLevels;
140                 const deUint32  rgb             = step*levelNdx;
141                 const deUint32  colorA  = 0xff000000 | rgb;
142                 const deUint32  colorB  = 0xff000000 | ~rgb;
143
144                 tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, 0), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
145         }
146
147         // Upload.
148         for (vector<TestTexture2DSp>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
149         {
150                 m_renderer.add2DTexture(*i);
151         }
152
153         // Compute cases.
154         {
155                 const struct
156                 {
157                         const int               texNdx;
158                         const float             lodX;
159                         const float             lodY;
160                         const float             oX;
161                         const float             oY;
162                 } cases[] =
163                 {
164                         { 0,    1.6f,   2.9f,   -1.0f,  -2.7f   },
165                         { 0,    -2.0f,  -1.35f, -0.2f,  0.7f    },
166                         { 1,    0.14f,  0.275f, -1.5f,  -1.1f   },
167                         { 1,    -0.92f, -2.64f, 0.4f,   -0.1f   },
168                 };
169
170                 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
171                 {
172                         const int       texNdx  = de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
173                         const float     lodX    = cases[caseNdx].lodX;
174                         const float     lodY    = cases[caseNdx].lodY;
175                         const float     oX              = cases[caseNdx].oX;
176                         const float     oY              = cases[caseNdx].oY;
177                         const float     sX              = deFloatExp2(lodX) * float(m_renderer.getRenderWidth()) / float(m_textures[texNdx]->getTexture().getWidth());
178                         const float     sY              = deFloatExp2(lodY) * float(m_renderer.getRenderHeight()) / float(m_textures[texNdx]->getTexture().getHeight());
179
180                         m_cases.push_back(FilterCase(texNdx, tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
181                 }
182         }
183 }
184
185 Texture2DFilteringTestInstance::~Texture2DFilteringTestInstance (void)
186 {
187 }
188
189 tcu::TestStatus Texture2DFilteringTestInstance::iterate (void)
190 {
191         tcu::TestLog&                                   log                     = m_context.getTestContext().getLog();
192
193         const pipeline::TestTexture2D&  texture         = m_renderer.get2DTexture(m_cases[m_caseNdx].textureIndex);
194         const tcu::TextureFormat                texFmt          = texture.getTextureFormat();
195         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
196         const FilterCase&                               curCase         = m_cases[m_caseNdx];
197         ReferenceParams                                 refParams       (TEXTURETYPE_2D);
198         tcu::Surface                                    rendered        (m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
199         vector<float>                                   texCoord;
200
201         // Setup params for reference.
202
203         refParams.sampler               = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
204         refParams.samplerType   = getSamplerType(texFmt);
205         refParams.lodMode               = LODMODE_EXACT;
206         refParams.colorBias             = fmtInfo.lookupBias;
207         refParams.colorScale    = fmtInfo.lookupScale;
208
209         // Compute texture coordinates.
210         log << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
211         computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
212
213         m_renderer.renderQuad(rendered, curCase.textureIndex, &texCoord[0], refParams);
214
215         {
216                 const bool                              isNearestOnly   = m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
217                 const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
218                 const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
219                 const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
220                 tcu::LodPrecision               lodPrecision    (tcu::LodPrecision::RULE_VULKAN);
221                 tcu::LookupPrecision    lookupPrecision;
222
223                 lodPrecision.derivateBits               = 18;
224                 lodPrecision.lodBits                    = 6;
225                 lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
226                 lookupPrecision.coordBits               = tcu::IVec3(20,20,0);
227                 lookupPrecision.uvwBits                 = tcu::IVec3(7,7,0);
228                 lookupPrecision.colorMask               = getCompareMask(pixelFormat);
229
230                 const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DView)texture.getTexture(),
231                                                                                                            &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
232
233                 if (!isHighQuality)
234                 {
235                         // Evaluate against lower precision requirements.
236                         lodPrecision.lodBits    = 4;
237                         lookupPrecision.uvwBits = tcu::IVec3(4,4,0);
238
239                         log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
240
241                         const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DView)texture.getTexture(),
242                                                                                                   &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
243
244                         if (!isOk)
245                         {
246                                 log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
247                                 return tcu::TestStatus::fail("Image verification failed");
248                         }
249                 }
250         }
251
252         m_caseNdx += 1;
253         return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
254 }
255
256 struct TextureCubeFilteringTestCaseParameters : public TextureCubeTestCaseParameters
257 {
258         bool    onlySampleFaceInterior;
259 };
260
261 class TextureCubeFilteringTestInstance : public TestInstance
262 {
263 public:
264         typedef TextureCubeFilteringTestCaseParameters  ParameterType;
265
266                                                                                                         TextureCubeFilteringTestInstance        (Context& context, const ParameterType& testParameters);
267                                                                                                         ~TextureCubeFilteringTestInstance       (void);
268
269         virtual tcu::TestStatus                                                 iterate                                                         (void);
270
271 private:
272                                                                                                         TextureCubeFilteringTestInstance        (const TextureCubeFilteringTestInstance& other);
273         TextureCubeFilteringTestInstance&                               operator=                                                       (const TextureCubeFilteringTestInstance& other);
274
275         struct FilterCase
276         {
277                 int                                             textureIndex;
278                 tcu::Vec2                               bottomLeft;
279                 tcu::Vec2                               topRight;
280
281                 FilterCase (void)
282                         : textureIndex(-1)
283                 {
284                 }
285
286                 FilterCase (int tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
287                         : textureIndex  (tex_)
288                         , bottomLeft    (bottomLeft_)
289                         , topRight              (topRight_)
290                 {
291                 }
292         };
293
294         const ParameterType                     m_testParameters;
295         vector<TestTextureCubeSp>       m_textures;
296         vector<FilterCase>                      m_cases;
297         TextureRenderer                         m_renderer;
298         int                                                     m_caseNdx;
299 };
300
301 TextureCubeFilteringTestInstance::TextureCubeFilteringTestInstance (Context& context, const ParameterType& testParameters)
302         : TestInstance                  (context)
303         , m_testParameters              (testParameters)
304         , m_renderer                    (context, testParameters.sampleCount, TEXCUBE_VIEWPORT_SIZE, TEXCUBE_VIEWPORT_SIZE)
305         , m_caseNdx                             (0)
306 {
307         const int                                               numLevels       = deLog2Floor32(m_testParameters.size)+1;
308         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
309         const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
310         const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
311
312         m_textures.reserve(2);
313         for (int ndx = 0; ndx < 2; ndx++)
314                 m_textures.push_back(TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(m_testParameters.format), m_testParameters.size)));
315
316         // Fill first with gradient texture.
317         static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
318         {
319                 { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
320                 { tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
321                 { tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
322                 { tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
323                 { tcu::Vec4(0.0f, 0.0f, 0.0f, 0.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
324                 { tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
325         };
326
327         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
328         {
329                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
330                 {
331                         tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
332                 }
333         }
334
335         // Fill second with grid texture.
336         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
337         {
338                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
339                 {
340                         const deUint32  step    = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
341                         const deUint32  rgb             = step*levelNdx*face;
342                         const deUint32  colorA  = 0xff000000 | rgb;
343                         const deUint32  colorB  = 0xff000000 | ~rgb;
344
345                         tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
346                 }
347         }
348
349         // Upload.
350         for (vector<TestTextureCubeSp>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
351         {
352                 m_renderer.addCubeTexture(*i);
353         }
354
355         // Compute cases
356         {
357                 const int tex0  = 0;
358                 const int tex1  = m_textures.size() > 1 ? 1 : 0;
359
360                 if (m_testParameters.onlySampleFaceInterior)
361                 {
362                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));   // minification
363                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f,  0.8f)));    // magnification
364                         m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));   // minification
365                         m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f,  0.5f)));             // magnification
366                 }
367                 else
368                 {
369                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f)));  // minification
370
371                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f)));    // magnification
372                         m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));  // minification
373                         m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f)));  // magnification
374                 }
375         }
376 }
377
378 TextureCubeFilteringTestInstance::~TextureCubeFilteringTestInstance (void)
379 {
380 }
381
382 const char* getFaceDesc (const tcu::CubeFace face)
383 {
384         switch (face)
385         {
386                 case tcu::CUBEFACE_NEGATIVE_X:  return "-X";
387                 case tcu::CUBEFACE_POSITIVE_X:  return "+X";
388                 case tcu::CUBEFACE_NEGATIVE_Y:  return "-Y";
389                 case tcu::CUBEFACE_POSITIVE_Y:  return "+Y";
390                 case tcu::CUBEFACE_NEGATIVE_Z:  return "-Z";
391                 case tcu::CUBEFACE_POSITIVE_Z:  return "+Z";
392                 default:
393                         DE_ASSERT(false);
394                         return DE_NULL;
395         }
396 }
397
398 tcu::TestStatus TextureCubeFilteringTestInstance::iterate (void)
399 {
400         tcu::TestLog&                                           log                     = m_context.getTestContext().getLog();
401
402         const pipeline::TestTextureCube&        texture         = m_renderer.getCubeTexture(m_cases[m_caseNdx].textureIndex);
403         const tcu::TextureFormat                        texFmt          = texture.getTextureFormat();
404         const tcu::TextureFormatInfo            fmtInfo         = tcu::getTextureFormatInfo(texFmt);
405         const FilterCase&                                       curCase         = m_cases[m_caseNdx];
406         ReferenceParams                                         refParams       (TEXTURETYPE_CUBE);
407
408         // Params for reference computation.
409         refParams.sampler                                       = util::createSampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, m_testParameters.minFilter, m_testParameters.magFilter);
410         refParams.sampler.seamlessCubeMap       = true;
411         refParams.samplerType                           = getSamplerType(texFmt);
412         refParams.lodMode                                       = LODMODE_EXACT;
413         refParams.colorBias                                     = fmtInfo.lookupBias;
414         refParams.colorScale                            = fmtInfo.lookupScale;
415
416         log << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
417
418         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
419         {
420                 const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
421                 tcu::Surface                    rendered        (m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
422                 vector<float>                   texCoord;
423
424                 computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
425
426                 log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
427
428                 // \todo Log texture coordinates.
429
430                 m_renderer.renderQuad(rendered, curCase.textureIndex, &texCoord[0], refParams);
431
432                 {
433                         const bool                              isNearestOnly   = m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
434                         const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
435                         const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
436                         const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
437                         tcu::LodPrecision               lodPrecision    (tcu::LodPrecision::RULE_VULKAN);
438                         tcu::LookupPrecision    lookupPrecision;
439
440                         lodPrecision.derivateBits               = 10;
441                         lodPrecision.lodBits                    = 5;
442                         lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
443                         lookupPrecision.coordBits               = tcu::IVec3(10,10,10);
444                         lookupPrecision.uvwBits                 = tcu::IVec3(6,6,0);
445                         lookupPrecision.colorMask               = getCompareMask(pixelFormat);
446
447                         const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::TextureCubeView)texture.getTexture(),
448                                                                                                                    &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
449
450                         if (!isHighQuality)
451                         {
452                                 // Evaluate against lower precision requirements.
453                                 lodPrecision.lodBits    = 4;
454                                 lookupPrecision.uvwBits = tcu::IVec3(4,4,0);
455
456                                 log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
457
458                                 const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::TextureCubeView)texture.getTexture(),
459                                                                                                           &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
460
461                                 if (!isOk)
462                                 {
463                                         log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
464                                         return tcu::TestStatus::fail("Image verification failed");
465                                 }
466                         }
467                 }
468         }
469
470         m_caseNdx += 1;
471         return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
472 }
473
474 // 2D array filtering
475
476 class Texture2DArrayFilteringTestInstance : public TestInstance
477 {
478 public:
479         typedef Texture2DArrayTestCaseParameters        ParameterType;
480
481                                                                                                 Texture2DArrayFilteringTestInstance             (Context& context, const ParameterType& testParameters);
482                                                                                                 ~Texture2DArrayFilteringTestInstance    (void);
483
484         virtual tcu::TestStatus                                         iterate                                                                 (void);
485
486 private:
487                                                                                                 Texture2DArrayFilteringTestInstance             (const Texture2DArrayFilteringTestInstance&);
488         Texture2DArrayFilteringTestInstance&            operator=                                                               (const Texture2DArrayFilteringTestInstance&);
489
490         struct FilterCase
491         {
492                 int                                                     textureIndex;
493                 tcu::Vec2                                       lod;
494                 tcu::Vec2                                       offset;
495                 tcu::Vec2                                       layerRange;
496
497                 FilterCase (void)
498                         : textureIndex(-1)
499                 {
500                 }
501
502                 FilterCase (const int tex_, const tcu::Vec2& lod_, const tcu::Vec2& offset_, const tcu::Vec2& layerRange_)
503                         : textureIndex  (tex_)
504                         , lod                   (lod_)
505                         , offset                (offset_)
506                         , layerRange    (layerRange_)
507                 {
508                 }
509         };
510
511         const ParameterType                             m_testParameters;
512         vector<TestTexture2DArraySp>    m_textures;
513         vector<FilterCase>                              m_cases;
514         TextureRenderer                                 m_renderer;
515         int                                                             m_caseNdx;
516 };
517
518 Texture2DArrayFilteringTestInstance::Texture2DArrayFilteringTestInstance (Context& context, const ParameterType& testParameters)
519         : TestInstance                  (context)
520         , m_testParameters              (testParameters)
521         , m_renderer                    (context, testParameters.sampleCount, TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT)
522         , m_caseNdx                             (0)
523 {
524         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
525         const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
526         const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
527         const int                                               numLevels       = deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height)) + 1;
528
529         // Create textures.
530         m_textures.reserve(2);
531         for (int ndx = 0; ndx < 2; ndx++)
532                 m_textures.push_back(TestTexture2DArraySp(new pipeline::TestTexture2DArray(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.numLayers)));
533
534         const tcu::IVec4 levelSwz[] =
535         {
536                 tcu::IVec4(0,1,2,3),
537                 tcu::IVec4(2,1,3,0),
538                 tcu::IVec4(3,0,1,2),
539                 tcu::IVec4(1,3,2,0),
540         };
541
542         // Fill first gradient texture (gradient direction varies between layers).
543         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
544         {
545                 for (int layerNdx = 0; layerNdx < m_testParameters.numLayers; layerNdx++)
546                 {
547                         const tcu::PixelBufferAccess levelBuf = m_textures[0]->getLevel(levelNdx, layerNdx);
548
549                         const tcu::IVec4        swz             = levelSwz[layerNdx%DE_LENGTH_OF_ARRAY(levelSwz)];
550                         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;
551                         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;
552
553                         tcu::fillWithComponentGradients(levelBuf, gMin, gMax);
554                 }
555         }
556
557         // Fill second with grid texture (each layer has unique colors).
558         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
559         {
560                 for (int layerNdx = 0; layerNdx < m_testParameters.numLayers; layerNdx++)
561                 {
562                         const tcu::PixelBufferAccess levelBuf = m_textures[1]->getLevel(levelNdx, layerNdx);
563
564                         const deUint32  step    = 0x00ffffff / (numLevels*m_testParameters.numLayers - 1);
565                         const deUint32  rgb             = step * (levelNdx + layerNdx*numLevels);
566                         const deUint32  colorA  = 0xff000000 | rgb;
567                         const deUint32  colorB  = 0xff000000 | ~rgb;
568
569                         tcu::fillWithGrid(levelBuf, 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
570                 }
571         }
572
573         // Upload.
574         for (vector<TestTexture2DArraySp>::const_iterator i = m_textures.begin(); i != m_textures.end(); i++)
575         {
576                 m_renderer.add2DArrayTexture(*i);
577         }
578
579         // Test cases
580         m_cases.push_back(FilterCase(0, tcu::Vec2( 1.5f,  2.8f  ),      tcu::Vec2(-1.0f, -2.7f), tcu::Vec2(-0.5f, float(m_testParameters.numLayers)+0.5f)));
581         m_cases.push_back(FilterCase(1, tcu::Vec2( 0.2f,  0.175f),      tcu::Vec2(-2.0f, -3.7f), tcu::Vec2(-0.5f, float(m_testParameters.numLayers)+0.5f)));
582         m_cases.push_back(FilterCase(1, tcu::Vec2(-0.8f, -2.3f  ),      tcu::Vec2( 0.2f, -0.1f), tcu::Vec2(float(m_testParameters.numLayers)+0.5f, -0.5f)));
583         m_cases.push_back(FilterCase(0, tcu::Vec2(-2.0f, -1.5f  ),      tcu::Vec2(-0.1f,  0.9f), tcu::Vec2(1.50001f, 1.49999f)));
584 }
585
586 Texture2DArrayFilteringTestInstance::~Texture2DArrayFilteringTestInstance (void)
587 {
588 }
589
590 tcu::TestStatus Texture2DArrayFilteringTestInstance::iterate (void)
591 {
592         tcu::TestLog&                                           log                     = m_context.getTestContext().getLog();
593
594         const FilterCase&                                       curCase         = m_cases[m_caseNdx];
595         const pipeline::TestTexture2DArray&     texture         = m_renderer.get2DArrayTexture(curCase.textureIndex);
596         const tcu::TextureFormat                        texFmt          = texture.getTextureFormat();
597         const tcu::TextureFormatInfo            fmtInfo         = tcu::getTextureFormatInfo(texFmt);
598         ReferenceParams                                         refParams       (TEXTURETYPE_2D_ARRAY);
599         tcu::Surface                                            rendered        (m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
600         tcu::Vec3                                                       texCoord[4];
601         const float* const                                      texCoordPtr     = (const float*)&texCoord[0];
602
603         // Params for reference computation.
604
605         refParams.sampler               = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
606         refParams.samplerType   = getSamplerType(texFmt);
607         refParams.lodMode               = LODMODE_EXACT;
608         refParams.colorBias             = fmtInfo.lookupBias;
609         refParams.colorScale    = fmtInfo.lookupScale;
610
611         // Compute texture coordinates.
612         log << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
613
614         {
615                 const float     lodX    = curCase.lod.x();
616                 const float     lodY    = curCase.lod.y();
617                 const float     oX              = curCase.offset.x();
618                 const float     oY              = curCase.offset.y();
619                 const float     sX              = deFloatExp2(lodX) * float(m_renderer.getRenderWidth()) / float(m_textures[0]->getTexture().getWidth());
620                 const float     sY              = deFloatExp2(lodY) * float(m_renderer.getRenderHeight()) / float(m_textures[0]->getTexture().getHeight());
621                 const float     l0              = curCase.layerRange.x();
622                 const float     l1              = curCase.layerRange.y();
623
624                 texCoord[0] = tcu::Vec3(oX,             oY,             l0);
625                 texCoord[1] = tcu::Vec3(oX,             oY+sY,  l0*0.5f + l1*0.5f);
626                 texCoord[2] = tcu::Vec3(oX+sX,  oY,             l0*0.5f + l1*0.5f);
627                 texCoord[3] = tcu::Vec3(oX+sX,  oY+sY,  l1);
628         }
629
630         m_renderer.renderQuad(rendered, curCase.textureIndex, texCoordPtr, refParams);
631
632         {
633
634                 const bool                              isNearestOnly   = m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
635                 const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
636                 const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
637                 const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
638                 tcu::LodPrecision               lodPrecision    (tcu::LodPrecision::RULE_VULKAN);
639                 tcu::LookupPrecision    lookupPrecision;
640
641                 lodPrecision.derivateBits               = 18;
642                 lodPrecision.lodBits                    = 6;
643                 lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
644                 lookupPrecision.coordBits               = tcu::IVec3(20,20,20);
645                 lookupPrecision.uvwBits                 = tcu::IVec3(7,7,0);
646                 lookupPrecision.colorMask               = getCompareMask(pixelFormat);
647
648                 const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DArrayView)texture.getTexture(),
649                                                                                                            texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
650
651                 if (!isHighQuality)
652                 {
653                         // Evaluate against lower precision requirements.
654                         lodPrecision.lodBits    = 4;
655                         lookupPrecision.uvwBits = tcu::IVec3(4,4,0);
656
657                         log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
658
659                         const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture2DArrayView)texture.getTexture(),
660                                                                                                   texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
661
662                         if (!isOk)
663                         {
664                                 log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
665                                 return tcu::TestStatus::fail("Image verification failed");
666                         }
667                 }
668         }
669
670         m_caseNdx += 1;
671         return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
672 }
673
674 // 3D filtering
675
676 class Texture3DFilteringTestInstance : public TestInstance
677 {
678 public:
679         typedef Texture3DTestCaseParameters     ParameterType;
680
681                                                                                 Texture3DFilteringTestInstance          (Context& context, const ParameterType& testParameters);
682                                                                                 ~Texture3DFilteringTestInstance         (void);
683
684         virtual tcu::TestStatus                         iterate                                                         (void);
685
686 private:
687                                                                                 Texture3DFilteringTestInstance          (const Texture3DFilteringTestInstance& other);
688         Texture3DFilteringTestInstance&         operator=                                                       (const Texture3DFilteringTestInstance& other);
689
690         struct FilterCase
691         {
692                 int                                             textureIndex;
693                 tcu::Vec3                               lod;
694                 tcu::Vec3                               offset;
695
696                 FilterCase (void)
697                         : textureIndex(-1)
698                 {
699                 }
700
701                 FilterCase (const int tex_, const tcu::Vec3& lod_, const tcu::Vec3& offset_)
702                         : textureIndex  (tex_)
703                         , lod                   (lod_)
704                         , offset                (offset_)
705                 {
706                 }
707         };
708
709         const ParameterType                     m_testParameters;
710         vector<TestTexture3DSp>         m_textures;
711         vector<FilterCase>                      m_cases;
712         TextureRenderer                         m_renderer;
713         int                                                     m_caseNdx;
714 };
715
716 Texture3DFilteringTestInstance::Texture3DFilteringTestInstance (Context& context, const ParameterType& testParameters)
717         : TestInstance                  (context)
718         , m_testParameters              (testParameters)
719         , m_renderer                    (context, testParameters.sampleCount, TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT)
720         , m_caseNdx                             (0)
721 {
722         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
723         const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
724         const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
725         const int                                               numLevels       = deLog2Floor32(de::max(de::max(m_testParameters.width, m_testParameters.height), m_testParameters.depth)) + 1;
726
727         // Create textures.
728         m_textures.reserve(2);
729         for (int ndx = 0; ndx < 2; ndx++)
730                 m_textures.push_back(TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.depth)));
731
732         // Fill first gradient texture.
733         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
734         {
735                 const tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
736                 const tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
737
738                 tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, 0), gMin, gMax);
739         }
740
741         // Fill second with grid texture.
742         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
743         {
744                 const deUint32  step    = 0x00ffffff / numLevels;
745                 const deUint32  rgb             = step*levelNdx;
746                 const deUint32  colorA  = 0xff000000 | rgb;
747                 const deUint32  colorB  = 0xff000000 | ~rgb;
748
749                 tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, 0), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
750         }
751
752         // Upload.
753         for (vector<TestTexture3DSp>::const_iterator i = m_textures.begin(); i != m_textures.end(); i++)
754         {
755                 m_renderer.add3DTexture(*i);
756         }
757
758         // Test cases
759         m_cases.push_back(FilterCase(0, tcu::Vec3(1.5f, 2.8f, 1.0f),    tcu::Vec3(-1.0f, -2.7f, -2.275f)));
760         m_cases.push_back(FilterCase(0, tcu::Vec3(-2.0f, -1.5f, -1.8f), tcu::Vec3(-0.1f, 0.9f, -0.25f)));
761         m_cases.push_back(FilterCase(1, tcu::Vec3(0.2f, 0.175f, 0.3f),  tcu::Vec3(-2.0f, -3.7f, -1.825f)));
762         m_cases.push_back(FilterCase(1, tcu::Vec3(-0.8f, -2.3f, -2.5f), tcu::Vec3(0.2f, -0.1f, 1.325f)));
763 }
764
765 Texture3DFilteringTestInstance::~Texture3DFilteringTestInstance (void)
766 {
767 }
768
769 tcu::TestStatus Texture3DFilteringTestInstance::iterate (void)
770 {
771         tcu::TestLog&                                           log                     = m_context.getTestContext().getLog();
772
773         const pipeline::TestTexture3D&  texture         = m_renderer.get3DTexture(m_cases[m_caseNdx].textureIndex);
774         const tcu::TextureFormat                texFmt          = texture.getTextureFormat();
775         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
776         const FilterCase&                               curCase         = m_cases[m_caseNdx];
777         ReferenceParams                                 refParams       (TEXTURETYPE_3D);
778         tcu::Surface                                    rendered        (m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
779         tcu::Vec3                                               texCoord[4];
780         const float* const                              texCoordPtr     = (const float*)&texCoord[0];
781
782         // Params for reference computation.
783         refParams.sampler               = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.wrapR, m_testParameters.minFilter, m_testParameters.magFilter);
784         refParams.samplerType   = getSamplerType(texFmt);
785         refParams.lodMode               = LODMODE_EXACT;
786         refParams.colorBias             = fmtInfo.lookupBias;
787         refParams.colorScale    = fmtInfo.lookupScale;
788
789         // Compute texture coordinates.
790         log << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
791
792         {
793                 const float     lodX    = curCase.lod.x();
794                 const float     lodY    = curCase.lod.y();
795                 const float     lodZ    = curCase.lod.z();
796                 const float     oX              = curCase.offset.x();
797                 const float     oY              = curCase.offset.y();
798                 const float oZ          = curCase.offset.z();
799                 const float     sX              = deFloatExp2(lodX) * float(m_renderer.getRenderWidth())                                                                                / float(m_textures[0]->getTexture().getWidth());
800                 const float     sY              = deFloatExp2(lodY) * float(m_renderer.getRenderHeight())                                                                               / float(m_textures[0]->getTexture().getHeight());
801                 const float     sZ              = deFloatExp2(lodZ) * float(de::max(m_renderer.getRenderWidth(), m_renderer.getRenderHeight())) / float(m_textures[0]->getTexture().getDepth());
802
803                 texCoord[0] = tcu::Vec3(oX,             oY,             oZ);
804                 texCoord[1] = tcu::Vec3(oX,             oY+sY,  oZ + sZ*0.5f);
805                 texCoord[2] = tcu::Vec3(oX+sX,  oY,             oZ + sZ*0.5f);
806                 texCoord[3] = tcu::Vec3(oX+sX,  oY+sY,  oZ + sZ);
807         }
808
809         m_renderer.renderQuad(rendered, curCase.textureIndex, texCoordPtr, refParams);
810
811         {
812                 const bool                              isNearestOnly   = m_testParameters.minFilter == Sampler::NEAREST && m_testParameters.magFilter == Sampler::NEAREST;
813                 const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
814                 const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
815                 const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
816                 tcu::LodPrecision               lodPrecision    (tcu::LodPrecision::RULE_VULKAN);
817                 tcu::LookupPrecision    lookupPrecision;
818
819                 lodPrecision.derivateBits               = 18;
820                 lodPrecision.lodBits                    = 6;
821                 lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
822                 lookupPrecision.coordBits               = tcu::IVec3(20,20,20);
823                 lookupPrecision.uvwBits                 = tcu::IVec3(7,7,7);
824                 lookupPrecision.colorMask               = getCompareMask(pixelFormat);
825
826                 const bool isHighQuality = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture3DView)texture.getTexture(),
827                                                                                                            texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
828
829                 if (!isHighQuality)
830                 {
831                         // Evaluate against lower precision requirements.
832                         lodPrecision.lodBits    = 4;
833                         lookupPrecision.uvwBits = tcu::IVec3(4,4,4);
834
835                         log << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
836
837                         const bool isOk = verifyTextureResult(m_context.getTestContext(), rendered.getAccess(), (tcu::Texture3DView)texture.getTexture(),
838                                                                                                   texCoordPtr, refParams, lookupPrecision, lodPrecision, pixelFormat);
839
840                         if (!isOk)
841                         {
842                                 log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
843                                 return tcu::TestStatus::fail("Image verification failed");
844                         }
845                 }
846         }
847
848         m_caseNdx += 1;
849         return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
850 }
851
852 bool verifierCanBeUsed(const VkFormat format, const Sampler::FilterMode minFilter, const Sampler::FilterMode magFilter)
853 {
854         const tcu::TextureFormat                                textureFormat           = mapVkFormat(format);
855         const tcu::TextureChannelClass                  textureChannelClass     = tcu::getTextureChannelClass(textureFormat.type);
856
857         return !(!(textureChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
858                            textureChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT   ||
859                            textureChannelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) &&
860                           (tcu::TexVerifierUtil::isLinearFilter(minFilter) || tcu::TexVerifierUtil::isLinearFilter(magFilter)));
861 }
862
863 void populateTextureFilteringTests (tcu::TestCaseGroup* textureFilteringTests)
864 {
865         tcu::TestContext&       testCtx         = textureFilteringTests->getTestContext();
866
867         static const struct
868         {
869                 const char* const                       name;
870                 const Sampler::WrapMode         mode;
871         } wrapModes[] =
872         {
873                 { "repeat",                                     Sampler::REPEAT_GL                      },
874                 { "mirrored_repeat",            Sampler::MIRRORED_REPEAT_GL     },
875                 { "clamp_to_edge",                      Sampler::CLAMP_TO_EDGE          },
876                 { "clamp_to_border",            Sampler::CLAMP_TO_BORDER        },
877                 { "mirror_clamp_to_edge",       Sampler::MIRRORED_ONCE          }
878         };
879
880         static const struct
881         {
882                 const char* const                       name;
883                 const Sampler::FilterMode       mode;
884         } minFilterModes[] =
885         {
886                 { "nearest",                            Sampler::NEAREST                                        },
887                 { "linear",                                     Sampler::LINEAR                                         },
888                 { "nearest_mipmap_nearest",     Sampler::NEAREST_MIPMAP_NEAREST         },
889                 { "linear_mipmap_nearest",      Sampler::LINEAR_MIPMAP_NEAREST          },
890                 { "nearest_mipmap_linear",      Sampler::NEAREST_MIPMAP_LINEAR          },
891                 { "linear_mipmap_linear",       Sampler::LINEAR_MIPMAP_LINEAR           }
892         };
893
894         static const struct
895         {
896                 const char* const                       name;
897                 const Sampler::FilterMode       mode;
898         } magFilterModes[] =
899         {
900                 { "nearest",                            Sampler::NEAREST },
901                 { "linear",                                     Sampler::LINEAR  }
902         };
903
904         static const struct
905         {
906                 const int       width;
907                 const int       height;
908         } sizes2D[] =
909         {
910                 {   4,    8 },
911                 {  32,   64 },
912                 { 128,  128     },
913                 {   3,    7 },
914                 {  31,   55 },
915                 { 127,   99 }
916         };
917
918         static const struct
919         {
920                 const int       size;
921         } sizesCube[] =
922         {
923                 {   8 },
924                 {  64 },
925                 { 128 },
926                 {   7 },
927                 {  63 }
928         };
929
930         static const struct
931         {
932                 const int       width;
933                 const int       height;
934                 const int       numLayers;
935         } sizes2DArray[] =
936         {
937                 {   4,   8,   8 },
938                 {  32,  64,  16 },
939                 { 128,  32,  64 },
940                 {   3,   7,   5 },
941                 {  63,  63,  63 }
942         };
943
944         static const struct
945         {
946                 const int       width;
947                 const int       height;
948                 const int       depth;
949         } sizes3D[] =
950         {
951                 {   4,   8,   8 },
952                 {  32,  64,  16 },
953                 { 128,  32,  64 },
954                 {   3,   7,   5 },
955                 {  63,  63,  63 }
956         };
957
958         static const struct
959         {
960                 const char* const       name;
961                 const VkFormat          format;
962         } filterableFormatsByType[] =
963         {
964                 { "r16g16b16a16_sfloat",        VK_FORMAT_R16G16B16A16_SFLOAT           },
965                 { "b10g11r11_ufloat",           VK_FORMAT_B10G11R11_UFLOAT_PACK32       },
966                 { "e5b9g9r9_ufloat",            VK_FORMAT_E5B9G9R9_UFLOAT_PACK32        },
967                 { "r8g8b8a8_unorm",                     VK_FORMAT_R8G8B8A8_UNORM                        },
968                 { "r8g8b8a8_snorm",                     VK_FORMAT_R8G8B8A8_SNORM                        },
969                 { "r5g6b5_unorm",                       VK_FORMAT_R5G6B5_UNORM_PACK16           },
970                 { "r4g4b4a4_unorm",                     VK_FORMAT_R4G4B4A4_UNORM_PACK16         },
971                 { "r5g5b5a1_unorm",                     VK_FORMAT_R5G5B5A1_UNORM_PACK16         },
972                 { "a8b8g8r8_srgb",                      VK_FORMAT_A8B8G8R8_SRGB_PACK32          },
973                 { "a1r5g5b5_unorm",                     VK_FORMAT_A1R5G5B5_UNORM_PACK16         }
974         };
975
976         // 2D texture filtering.
977         {
978                 de::MovePtr<tcu::TestCaseGroup> group2D                         (new tcu::TestCaseGroup(testCtx, "2d", "2D Texture Filtering"));
979
980                 de::MovePtr<tcu::TestCaseGroup> formatsGroup            (new tcu::TestCaseGroup(testCtx, "formats", "2D Texture Formats"));
981                 de::MovePtr<tcu::TestCaseGroup> sizesGroup                      (new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
982                 de::MovePtr<tcu::TestCaseGroup> combinationsGroup       (new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
983
984                 // Formats.
985                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
986                 {
987                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
988                         {
989                                 const Sampler::FilterMode       minFilter               = minFilterModes[filterNdx].mode;
990                                 const char* const                       filterName              = minFilterModes[filterNdx].name;
991                                 const bool                                      isMipmap                = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
992                                 const char* const                       formatName              = filterableFormatsByType[fmtNdx].name;
993                                 const string                            name                    = string(formatName) + "_" + filterName;
994                                 Texture2DTestCaseParameters     testParameters;
995
996                                 testParameters.format           = filterableFormatsByType[fmtNdx].format;
997                                 testParameters.minFilter        = minFilter;
998                                 testParameters.magFilter        = isMipmap ? Sampler::LINEAR : minFilter;
999
1000                                 testParameters.wrapS            = Sampler::REPEAT_GL;
1001                                 testParameters.wrapT            = Sampler::REPEAT_GL;
1002                                 testParameters.width            = 64;
1003                                 testParameters.height           = 64;
1004
1005                                 testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1006                                 testParameters.programs.push_back(PROGRAM_2D_UINT);
1007
1008                                 // Some combinations of the tests have to be skipped due to the restrictions of the verifiers.
1009                                 if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1010                                 {
1011                                         formatsGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1012                                 }
1013                         }
1014                 }
1015
1016                 // Sizes.
1017                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
1018                 {
1019                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1020                         {
1021                                 const Sampler::FilterMode       minFilter               = minFilterModes[filterNdx].mode;
1022                                 const char* const                       filterName              = minFilterModes[filterNdx].name;
1023                                 const bool                                      isMipmap                = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1024                                 const string                            name                    = de::toString(sizes2D[sizeNdx].width) + "x" + de::toString(sizes2D[sizeNdx].height) + "_" + filterName;
1025                                 Texture2DTestCaseParameters     testParameters;
1026
1027                                 testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM;
1028                                 testParameters.minFilter        = minFilter;
1029                                 testParameters.magFilter        = isMipmap ? Sampler::LINEAR : minFilter;
1030                                 testParameters.wrapS            = Sampler::REPEAT_GL;
1031                                 testParameters.wrapT            = Sampler::REPEAT_GL;
1032                                 testParameters.width            = sizes2D[sizeNdx].width;
1033                                 testParameters.height           = sizes2D[sizeNdx].height;
1034
1035                                 testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1036
1037                                 sizesGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1038                         }
1039                 }
1040
1041                 // Wrap modes.
1042                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1043                 {
1044                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1045                         {
1046                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1047                                 {
1048                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1049                                         {
1050                                                 const string    name            = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1051                                                 Texture2DTestCaseParameters     testParameters;
1052
1053                                                 testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM;
1054                                                 testParameters.minFilter        = minFilterModes[minFilterNdx].mode;
1055                                                 testParameters.magFilter        = magFilterModes[magFilterNdx].mode;
1056                                                 testParameters.wrapS            = wrapModes[wrapSNdx].mode;
1057                                                 testParameters.wrapT            = wrapModes[wrapTNdx].mode;
1058                                                 testParameters.width            = 63;
1059                                                 testParameters.height           = 57;
1060
1061                                                 testParameters.programs.push_back(PROGRAM_2D_FLOAT);
1062
1063                                                 combinationsGroup->addChild(new TextureTestCase<Texture2DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1064                                         }
1065                                 }
1066                         }
1067                 }
1068
1069                 group2D->addChild(formatsGroup.release());
1070                 group2D->addChild(sizesGroup.release());
1071                 group2D->addChild(combinationsGroup.release());
1072
1073                 textureFilteringTests->addChild(group2D.release());
1074         }
1075
1076         // Cube map texture filtering.
1077         {
1078                 de::MovePtr<tcu::TestCaseGroup> groupCube                               (new tcu::TestCaseGroup(testCtx, "cube", "Cube Map Texture Filtering"));
1079
1080                 de::MovePtr<tcu::TestCaseGroup> formatsGroup                    (new tcu::TestCaseGroup(testCtx, "formats", "2D Texture Formats"));
1081                 de::MovePtr<tcu::TestCaseGroup> sizesGroup                              (new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1082                 de::MovePtr<tcu::TestCaseGroup> combinationsGroup               (new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
1083                 de::MovePtr<tcu::TestCaseGroup> onlyFaceInteriorGroup   (new tcu::TestCaseGroup(testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges"));
1084
1085                 // Formats.
1086                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1087                 {
1088                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1089                         {
1090                                 const Sampler::FilterMode                               minFilter       = minFilterModes[filterNdx].mode;
1091                                 const char* const                                               filterName      = minFilterModes[filterNdx].name;
1092                                 const bool                                                              isMipmap        = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1093                                 const char* const                                               formatName      = filterableFormatsByType[fmtNdx].name;
1094                                 const string                                                    name            = string(formatName) + "_" + filterName;
1095                                 TextureCubeFilteringTestCaseParameters  testParameters;
1096
1097                                 testParameters.format                                   = filterableFormatsByType[fmtNdx].format;
1098                                 testParameters.minFilter                                = minFilter;
1099                                 testParameters.magFilter                                = isMipmap ? Sampler::LINEAR : minFilter;
1100
1101                                 testParameters.wrapS                                    = Sampler::REPEAT_GL;
1102                                 testParameters.wrapT                                    = Sampler::REPEAT_GL;
1103                                 testParameters.onlySampleFaceInterior   = false;
1104                                 testParameters.size                                             = 64;
1105
1106                                 testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1107                                 testParameters.programs.push_back(PROGRAM_CUBE_UINT);
1108
1109                                 // Some tests have to be skipped due to the restrictions of the verifiers.
1110                                 if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1111                                 {
1112                                         formatsGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1113                                 }
1114                         }
1115                 }
1116
1117                 // Sizes.
1118                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++)
1119                 {
1120                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1121                         {
1122                                 const Sampler::FilterMode                               minFilter               = minFilterModes[filterNdx].mode;
1123                                 const char* const                                               filterName              = minFilterModes[filterNdx].name;
1124                                 const bool                                                              isMipmap                = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1125                                 const string                                                    name                    = de::toString(sizesCube[sizeNdx].size) + "x" + de::toString(sizesCube[sizeNdx].size) + "_" + filterName;
1126                                 TextureCubeFilteringTestCaseParameters  testParameters;
1127
1128                                 testParameters.format                                   = VK_FORMAT_R8G8B8A8_UNORM;
1129                                 testParameters.minFilter                                = minFilter;
1130                                 testParameters.magFilter                                = isMipmap ? Sampler::LINEAR : minFilter;
1131                                 testParameters.wrapS                                    = Sampler::REPEAT_GL;
1132                                 testParameters.wrapT                                    = Sampler::REPEAT_GL;
1133                                 testParameters.onlySampleFaceInterior   = false;
1134                                 testParameters.size                                             = sizesCube[sizeNdx].size;
1135
1136                                 testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1137
1138                                 sizesGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1139
1140                         }
1141                 }
1142
1143                 // Filter/wrap mode combinations.
1144                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1145                 {
1146                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1147                         {
1148                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1149                                 {
1150                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1151                                         {
1152                                                 const string                                                    name                    = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1153                                                 TextureCubeFilteringTestCaseParameters  testParameters;
1154
1155                                                 testParameters.format                                   = VK_FORMAT_R8G8B8A8_UNORM;
1156                                                 testParameters.minFilter                                = minFilterModes[minFilterNdx].mode;
1157                                                 testParameters.magFilter                                = magFilterModes[magFilterNdx].mode;
1158                                                 testParameters.wrapS                                    = wrapModes[wrapSNdx].mode;
1159                                                 testParameters.wrapT                                    = wrapModes[wrapTNdx].mode;
1160                                                 testParameters.onlySampleFaceInterior   = false;
1161                                                 testParameters.size                                             = 63;
1162
1163                                                 testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1164
1165                                                 combinationsGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1166                                         }
1167                                 }
1168                         }
1169                 }
1170
1171                 // Cases with no visible cube edges.
1172                 for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
1173                 {
1174                         const bool                                                              isLinear                = isLinearI != 0;
1175                         const string                                                    name                    = isLinear ? "linear" : "nearest";
1176                         TextureCubeFilteringTestCaseParameters  testParameters;
1177
1178                         testParameters.format                                   = VK_FORMAT_R8G8B8A8_UNORM;
1179                         testParameters.minFilter                                = isLinear ? Sampler::LINEAR : Sampler::NEAREST;
1180                         testParameters.magFilter                                = isLinear ? Sampler::LINEAR : Sampler::NEAREST;
1181                         testParameters.wrapS                                    = Sampler::REPEAT_GL;
1182                         testParameters.wrapT                                    = Sampler::REPEAT_GL;
1183                         testParameters.onlySampleFaceInterior   = true;
1184                         testParameters.size                                             = 63;
1185
1186                         testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
1187
1188                         onlyFaceInteriorGroup->addChild(new TextureTestCase<TextureCubeFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1189                 }
1190
1191                 groupCube->addChild(formatsGroup.release());
1192                 groupCube->addChild(sizesGroup.release());
1193                 groupCube->addChild(combinationsGroup.release());
1194                 groupCube->addChild(onlyFaceInteriorGroup.release());
1195
1196                 textureFilteringTests->addChild(groupCube.release());
1197         }
1198
1199         // 2D array texture filtering.
1200         {
1201                 de::MovePtr<tcu::TestCaseGroup> group2DArray            (new tcu::TestCaseGroup(testCtx, "2d_array", "2D Array Texture Filtering"));
1202
1203                 de::MovePtr<tcu::TestCaseGroup> formatsGroup            (new tcu::TestCaseGroup(testCtx, "formats", "2D Array Texture Formats"));
1204                 de::MovePtr<tcu::TestCaseGroup> sizesGroup                      (new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1205                 de::MovePtr<tcu::TestCaseGroup> combinationsGroup       (new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
1206
1207                 // Formats.
1208                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1209                 {
1210                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1211                         {
1212                                 const Sampler::FilterMode                       minFilter               = minFilterModes[filterNdx].mode;
1213                                 const char* const                                       filterName              = minFilterModes[filterNdx].name;
1214                                 const bool                                                      isMipmap                = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1215                                 const char* const                                       formatName              = filterableFormatsByType[fmtNdx].name;
1216                                 const string                                            name                    = string(formatName) + "_" + filterName;
1217                                 Texture2DArrayTestCaseParameters        testParameters;
1218
1219                                 testParameters.format           = filterableFormatsByType[fmtNdx].format;
1220                                 testParameters.minFilter        = minFilter;
1221                                 testParameters.magFilter        = isMipmap ? Sampler::LINEAR : minFilter;
1222
1223                                 testParameters.wrapS            = Sampler::REPEAT_GL;
1224                                 testParameters.wrapT            = Sampler::REPEAT_GL;
1225                                 testParameters.width            = 128;
1226                                 testParameters.height           = 128;
1227                                 testParameters.numLayers        = 8;
1228
1229                                 testParameters.programs.push_back(PROGRAM_2D_ARRAY_FLOAT);
1230                                 testParameters.programs.push_back(PROGRAM_2D_ARRAY_UINT);
1231
1232                                 // Some tests have to be skipped due to the restrictions of the verifiers.
1233                                 if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1234                                 {
1235                                         formatsGroup->addChild(new TextureTestCase<Texture2DArrayFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1236                                 }
1237                         }
1238                 }
1239
1240                 // Sizes.
1241                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2DArray); sizeNdx++)
1242                 {
1243                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1244                         {
1245                                 const Sampler::FilterMode                       minFilter               = minFilterModes[filterNdx].mode;
1246                                 const char* const                                       filterName              = minFilterModes[filterNdx].name;
1247                                 const bool                                                      isMipmap                = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1248                                 const string                                            name                    = de::toString(sizes2DArray[sizeNdx].width) + "x" + de::toString(sizes2DArray[sizeNdx].height) + "x" + de::toString(sizes2DArray[sizeNdx].numLayers) + "_" + filterName;
1249                                 Texture2DArrayTestCaseParameters        testParameters;
1250
1251                                 testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM;
1252                                 testParameters.minFilter        = minFilter;
1253                                 testParameters.magFilter        = isMipmap ? Sampler::LINEAR : minFilter;
1254                                 testParameters.wrapS            = Sampler::REPEAT_GL;
1255                                 testParameters.wrapT            = Sampler::REPEAT_GL;
1256                                 testParameters.width            = sizes2DArray[sizeNdx].width;
1257                                 testParameters.height           = sizes2DArray[sizeNdx].height;
1258                                 testParameters.numLayers        = sizes2DArray[sizeNdx].numLayers;
1259
1260                                 testParameters.programs.push_back(PROGRAM_2D_ARRAY_FLOAT);
1261
1262                                 sizesGroup->addChild(new TextureTestCase<Texture2DArrayFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1263                         }
1264                 }
1265
1266                 // Wrap modes.
1267                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1268                 {
1269                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1270                         {
1271                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1272                                 {
1273                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1274                                         {
1275                                                 const string                                            name                    = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1276                                                 Texture2DArrayTestCaseParameters        testParameters;
1277
1278                                                 testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM;
1279                                                 testParameters.minFilter        = minFilterModes[minFilterNdx].mode;
1280                                                 testParameters.magFilter        = magFilterModes[magFilterNdx].mode;
1281                                                 testParameters.wrapS            = wrapModes[wrapSNdx].mode;
1282                                                 testParameters.wrapT            = wrapModes[wrapTNdx].mode;
1283                                                 testParameters.width            = 123;
1284                                                 testParameters.height           = 107;
1285                                                 testParameters.numLayers        = 7;
1286
1287                                                 testParameters.programs.push_back(PROGRAM_2D_ARRAY_FLOAT);
1288
1289                                                 combinationsGroup->addChild(new TextureTestCase<Texture2DArrayFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1290                                         }
1291                                 }
1292                         }
1293                 }
1294
1295                 group2DArray->addChild(formatsGroup.release());
1296                 group2DArray->addChild(sizesGroup.release());
1297                 group2DArray->addChild(combinationsGroup.release());
1298
1299                 textureFilteringTests->addChild(group2DArray.release());
1300         }
1301
1302         // 3D texture filtering.
1303         {
1304                 de::MovePtr<tcu::TestCaseGroup> group3D                         (new tcu::TestCaseGroup(testCtx, "3d", "3D Texture Filtering"));
1305
1306                 de::MovePtr<tcu::TestCaseGroup> formatsGroup            (new tcu::TestCaseGroup(testCtx, "formats", "3D Texture Formats"));
1307                 de::MovePtr<tcu::TestCaseGroup> sizesGroup                      (new tcu::TestCaseGroup(testCtx, "sizes", "Texture Sizes"));
1308                 de::MovePtr<tcu::TestCaseGroup> combinationsGroup       (new tcu::TestCaseGroup(testCtx, "combinations", "Filter and wrap mode combinations"));
1309
1310                 // Formats.
1311                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1312                 {
1313                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1314                         {
1315                                 const Sampler::FilterMode       minFilter               = minFilterModes[filterNdx].mode;
1316                                 const char* const                       filterName              = minFilterModes[filterNdx].name;
1317                                 const bool                                      isMipmap                = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1318                                 const char* const                       formatName              = filterableFormatsByType[fmtNdx].name;
1319                                 const string                            name                    = string(formatName) + "_" + filterName;
1320                                 Texture3DTestCaseParameters     testParameters;
1321
1322                                 testParameters.format           = filterableFormatsByType[fmtNdx].format;
1323                                 testParameters.minFilter        = minFilter;
1324                                 testParameters.magFilter        = isMipmap ? Sampler::LINEAR : minFilter;
1325
1326                                 testParameters.wrapS            = Sampler::REPEAT_GL;
1327                                 testParameters.wrapT            = Sampler::REPEAT_GL;
1328                                 testParameters.wrapR            = Sampler::REPEAT_GL;
1329                                 testParameters.width            = 64;
1330                                 testParameters.height           = 64;
1331                                 testParameters.depth            = 64;
1332
1333                                 testParameters.programs.push_back(PROGRAM_3D_FLOAT);
1334                                 testParameters.programs.push_back(PROGRAM_3D_UINT);
1335
1336                                 // Some tests have to be skipped due to the restrictions of the verifiers.
1337                                 if (verifierCanBeUsed(testParameters.format, testParameters.minFilter, testParameters.magFilter))
1338                                 {
1339                                         formatsGroup->addChild(new TextureTestCase<Texture3DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1340                                 }
1341                         }
1342                 }
1343
1344                 // Sizes.
1345                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes3D); sizeNdx++)
1346                 {
1347                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1348                         {
1349                                 const Sampler::FilterMode               minFilter               = minFilterModes[filterNdx].mode;
1350                                 const char* const                               filterName              = minFilterModes[filterNdx].name;
1351                                 const bool                                              isMipmap                = minFilter != Sampler::NEAREST && minFilter != Sampler::LINEAR;
1352                                 const string                                    name                    = de::toString(sizes3D[sizeNdx].width) + "x" + de::toString(sizes3D[sizeNdx].height) + "x" + de::toString(sizes3D[sizeNdx].depth) + "_" + filterName;
1353                                 Texture3DTestCaseParameters             testParameters;
1354
1355                                 testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM;
1356                                 testParameters.minFilter        = minFilter;
1357                                 testParameters.magFilter        = isMipmap ? Sampler::LINEAR : minFilter;
1358                                 testParameters.wrapS            = Sampler::REPEAT_GL;
1359                                 testParameters.wrapT            = Sampler::REPEAT_GL;
1360                                 testParameters.wrapR            = Sampler::REPEAT_GL;
1361                                 testParameters.width            = sizes3D[sizeNdx].width;
1362                                 testParameters.height           = sizes3D[sizeNdx].height;
1363                                 testParameters.depth            = sizes3D[sizeNdx].depth;
1364
1365                                 testParameters.programs.push_back(PROGRAM_3D_FLOAT);
1366
1367                                 sizesGroup->addChild(new TextureTestCase<Texture3DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1368                         }
1369                 }
1370
1371                 // Wrap modes.
1372                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1373                 {
1374                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1375                         {
1376                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1377                                 {
1378                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1379                                         {
1380                                                 for (int wrapRNdx = 0; wrapRNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapRNdx++)
1381                                                 {
1382                                                         const string                            name                    = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name + "_" + wrapModes[wrapRNdx].name;
1383                                                         Texture3DTestCaseParameters     testParameters;
1384
1385                                                         testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM;
1386                                                         testParameters.minFilter        = minFilterModes[minFilterNdx].mode;
1387                                                         testParameters.magFilter        = magFilterModes[magFilterNdx].mode;
1388                                                         testParameters.wrapS            = wrapModes[wrapSNdx].mode;
1389                                                         testParameters.wrapT            = wrapModes[wrapTNdx].mode;
1390                                                         testParameters.wrapR            = wrapModes[wrapRNdx].mode;
1391                                                         testParameters.width            = 63;
1392                                                         testParameters.height           = 57;
1393                                                         testParameters.depth            = 67;
1394
1395                                                         testParameters.programs.push_back(PROGRAM_3D_FLOAT);
1396
1397                                                         combinationsGroup->addChild(new TextureTestCase<Texture3DFilteringTestInstance>(testCtx, name.c_str(), "", testParameters));
1398                                                 }
1399                                         }
1400                                 }
1401                         }
1402                 }
1403
1404                 group3D->addChild(formatsGroup.release());
1405                 group3D->addChild(sizesGroup.release());
1406                 group3D->addChild(combinationsGroup.release());
1407
1408                 textureFilteringTests->addChild(group3D.release());
1409         }
1410 }
1411
1412 } // anonymous
1413
1414 tcu::TestCaseGroup*     createTextureFilteringTests     (tcu::TestContext& testCtx)
1415 {
1416         return createTestGroup(testCtx, "filtering", "Texture filtering tests.", populateTextureFilteringTests);
1417 }
1418
1419 } // texture
1420 } // vkt