Merge changes I85492417,I93389a2c into nougat-cts-dev am: 37eaa88ac2 am: 89da6ddd7b...
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / texture / vktTextureShadowTests.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  * Copyright (c) 2016 The Khronos Group Inc.
7  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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 Shadow texture lookup tests.
24  *//*--------------------------------------------------------------------*/
25
26 #include "vktTextureShadowTests.hpp"
27
28 #include "deMath.h"
29 #include "deString.h"
30 #include "deStringUtil.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "gluTextureTestUtil.hpp"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 #include "tcuImageIO.hpp"
36 #include "tcuRenderTarget.hpp"
37 #include "tcuTexCompareVerifier.hpp"
38 #include "tcuTexVerifierUtil.hpp"
39 #include "tcuTexture.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "vkImageUtil.hpp"
42 #include "vkTypeUtil.hpp"
43 #include "vktTestGroupUtil.hpp"
44 #include "vktTextureTestUtil.hpp"
45
46 using namespace vk;
47
48 namespace vkt
49 {
50 namespace texture
51 {
52 namespace
53 {
54
55 using std::vector;
56 using std::string;
57 using tcu::TestLog;
58 using tcu::Sampler;
59 using namespace texture::util;
60 using namespace glu::TextureTestUtil;
61
62 enum
63 {
64         TEXCUBE_VIEWPORT_SIZE   = 28,
65         TEX2D_VIEWPORT_WIDTH    = 64,
66         TEX2D_VIEWPORT_HEIGHT   = 64
67 };
68
69 struct TextureShadowCommonTestCaseParameters
70 {
71                                                         TextureShadowCommonTestCaseParameters   (void);
72         Sampler::CompareMode    compareOp;
73 };
74
75 TextureShadowCommonTestCaseParameters::TextureShadowCommonTestCaseParameters (void)
76         : compareOp                             (Sampler::COMPAREMODE_EQUAL)
77 {
78 }
79
80 struct Texture2DShadowTestCaseParameters : public Texture2DTestCaseParameters, public TextureShadowCommonTestCaseParameters
81 {
82 };
83
84 bool isFloatingPointDepthFormat (const tcu::TextureFormat& format)
85 {
86         // Only two depth and depth-stencil formats are floating point
87         return  (format.order == tcu::TextureFormat::D && format.type == tcu::TextureFormat::FLOAT) ||
88                         (format.order == tcu::TextureFormat::DS && format.type == tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV);
89 }
90
91 void clampFloatingPointTexture (const tcu::PixelBufferAccess& access)
92 {
93         DE_ASSERT(isFloatingPointDepthFormat(access.getFormat()));
94
95         for (int z = 0; z < access.getDepth(); ++z)
96         for (int y = 0; y < access.getHeight(); ++y)
97         for (int x = 0; x < access.getWidth(); ++x)
98                 access.setPixDepth(de::clamp(access.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
99 }
100
101 void clampFloatingPointTexture (tcu::Texture2D& target)
102 {
103         for (int level = 0; level < target.getNumLevels(); ++level)
104                 if (!target.isLevelEmpty(level))
105                         clampFloatingPointTexture(target.getLevel(level));
106 }
107
108 static void clampFloatingPointTexture (tcu::Texture2DArray& target)
109 {
110         for (int level = 0; level < target.getNumLevels(); ++level)
111                 if (!target.isLevelEmpty(level))
112                         clampFloatingPointTexture(target.getLevel(level));
113 }
114
115 void clampFloatingPointTexture (tcu::TextureCube& target)
116 {
117         for (int level = 0; level < target.getNumLevels(); ++level)
118                 for (int face = tcu::CUBEFACE_NEGATIVE_X; face < tcu::CUBEFACE_LAST; ++face)
119                         clampFloatingPointTexture(target.getLevelFace(level, (tcu::CubeFace)face));
120 }
121
122 tcu::PixelFormat getPixelFormat(tcu::TextureFormat texFormat)
123 {
124         const tcu::IVec4                        formatBitDepth          = tcu::getTextureFormatBitDepth(tcu::getEffectiveDepthStencilTextureFormat(texFormat, Sampler::MODE_DEPTH));
125         return tcu::PixelFormat(formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
126 }
127
128 template<typename TextureType>
129 bool verifyTexCompareResult (tcu::TestContext&                                          testCtx,
130                                                          const tcu::ConstPixelBufferAccess&             result,
131                                                          const TextureType&                                             src,
132                                                          const float*                                                   texCoord,
133                                                          const ReferenceParams&                                 sampleParams,
134                                                          const tcu::TexComparePrecision&                comparePrec,
135                                                          const tcu::LodPrecision&                               lodPrec,
136                                                          const tcu::PixelFormat&                                pixelFormat)
137 {
138         tcu::TestLog&   log                                     = testCtx.getLog();
139         tcu::Surface    reference                       (result.getWidth(), result.getHeight());
140         tcu::Surface    errorMask                       (result.getWidth(), result.getHeight());
141         const tcu::Vec3 nonShadowThreshold      = tcu::computeFixedPointThreshold(getBitsVec(pixelFormat)-1).swizzle(1,2,3);
142         int                             numFailedPixels;
143
144         // sampleTexture() expects source image to be the same state as it would be in a GL implementation, that is
145         // the floating point depth values should be in [0, 1] range as data is clamped during texture upload. Since
146         // we don't have a separate "uploading" phase and just reuse the buffer we used for GL-upload, do the clamping
147         // here if necessary.
148
149         if (isFloatingPointDepthFormat(src.getFormat()))
150         {
151                 TextureType clampedSource(src);
152
153                 clampFloatingPointTexture(clampedSource);
154
155                 // sample clamped values
156
157                 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), clampedSource, texCoord, sampleParams);
158                 numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), clampedSource, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
159         }
160         else
161         {
162                 // sample raw values (they are guaranteed to be in [0, 1] range as the format cannot represent any other values)
163
164                 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
165                 numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
166         }
167
168         if (numFailedPixels > 0)
169                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
170
171         log << TestLog::ImageSet("VerifyResult", "Verification result")
172                 << TestLog::Image("Rendered", "Rendered image", result);
173
174         if (numFailedPixels > 0)
175         {
176                 log << TestLog::Image("Reference", "Ideal reference image", reference)
177                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
178         }
179
180         log << TestLog::EndImageSet;
181
182         return numFailedPixels == 0;
183 }
184
185 class Texture2DShadowTestInstance : public TestInstance
186 {
187 public:
188         typedef Texture2DShadowTestCaseParameters       ParameterType;
189                                                                                                 Texture2DShadowTestInstance             (Context& context, const ParameterType& testParameters);
190                                                                                                 ~Texture2DShadowTestInstance    (void);
191
192         virtual tcu::TestStatus                                         iterate                                                 (void);
193
194 private:
195                                                                                                 Texture2DShadowTestInstance             (const Texture2DShadowTestInstance& other);
196         Texture2DShadowTestInstance&                            operator=                                               (const Texture2DShadowTestInstance& other);
197
198         struct FilterCase
199         {
200                 int                     textureIndex;
201
202                 tcu::Vec2       minCoord;
203                 tcu::Vec2       maxCoord;
204                 float           ref;
205
206                 FilterCase      (void)
207                         : textureIndex(-1)
208                         , ref           (0.0f)
209                 {
210                 }
211
212                 FilterCase      (int tex_, const float ref_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
213                         : textureIndex  (tex_)
214                         , minCoord              (minCoord_)
215                         , maxCoord              (maxCoord_)
216                         , ref                   (ref_)
217                 {
218                 }
219         };
220
221         const ParameterType&                    m_testParameters;
222         std::vector<TestTexture2DSp>    m_textures;
223         std::vector<FilterCase>                 m_cases;
224
225         TextureRenderer                                 m_renderer;
226
227         int                                                             m_caseNdx;
228 };
229
230 Texture2DShadowTestInstance::Texture2DShadowTestInstance (Context& context, const ParameterType& testParameters)
231         : TestInstance                  (context)
232         , m_testParameters              (testParameters)
233         , m_renderer                    (context, testParameters.sampleCount, TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT)
234         , m_caseNdx                             (0)
235 {
236         // Create 2 textures.
237         m_textures.reserve(2);
238         for (int ndx = 0; ndx < 2; ndx++)
239         {
240                 m_textures.push_back(TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height)));
241         }
242
243         const int       numLevels       = m_textures[0]->getNumLevels();
244
245         // Fill first gradient texture.
246         for (int levelNdx = 0; levelNdx < numLevels; ++levelNdx)
247         {
248                 tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, 0), tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
249         }
250
251         // Fill second with grid texture.
252         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
253         {
254                 const deUint32  step    = 0x00ffffff / numLevels;
255                 const deUint32  rgb             = step*levelNdx;
256                 const deUint32  colorA  = 0xff000000 | rgb;
257                 const deUint32  colorB  = 0xff000000 | ~rgb;
258
259                 tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, 0), 4, tcu::RGBA(colorA).toVec(), tcu::RGBA(colorB).toVec());
260         }
261
262         // Upload.
263         for (std::vector<TestTexture2DSp>::iterator i = m_textures.begin(); i != m_textures.end(); ++i)
264         {
265                 m_renderer.add2DTexture(*i);
266         }
267
268         // Compute cases.
269         {
270                 const float refInRangeUpper             = (m_testParameters.compareOp == Sampler::COMPAREMODE_EQUAL || m_testParameters.compareOp == Sampler::COMPAREMODE_NOT_EQUAL) ? 1.0f : 0.5f;
271                 const float refInRangeLower             = (m_testParameters.compareOp == Sampler::COMPAREMODE_EQUAL || m_testParameters.compareOp == Sampler::COMPAREMODE_NOT_EQUAL) ? 0.0f : 0.5f;
272                 const float refOutOfBoundsUpper = 1.1f;         // !< lookup function should clamp values to [0, 1] range
273                 const float refOutOfBoundsLower = -0.1f;
274
275                 const struct
276                 {
277                         const int       texNdx;
278                         const float     ref;
279                         const float     lodX;
280                         const float     lodY;
281                         const float     oX;
282                         const float     oY;
283                 } cases[] =
284                 {
285                         { 0,    refInRangeUpper,                1.6f,   2.9f,   -1.0f,  -2.7f   },
286                         { 0,    refInRangeLower,                -2.0f,  -1.35f, -0.2f,  0.7f    },
287                         { 1,    refInRangeUpper,                0.14f,  0.275f, -1.5f,  -1.1f   },
288                         { 1,    refInRangeLower,                -0.92f, -2.64f, 0.4f,   -0.1f   },
289                         { 1,    refOutOfBoundsUpper,    -0.39f, -0.52f, 0.65f,  0.87f   },
290                         { 1,    refOutOfBoundsLower,    -1.55f, 0.65f,  0.35f,  0.91f   },
291                 };
292
293                 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
294                 {
295                         const int       texNdx  = de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
296                         const float ref         = cases[caseNdx].ref;
297                         const float     lodX    = cases[caseNdx].lodX;
298                         const float     lodY    = cases[caseNdx].lodY;
299                         const float     oX              = cases[caseNdx].oX;
300                         const float     oY              = cases[caseNdx].oY;
301                         const float     sX              = deFloatExp2(lodX) * float(m_renderer.getRenderWidth()) / float(m_textures[texNdx]->getTexture().getWidth());
302                         const float     sY              = deFloatExp2(lodY) * float(m_renderer.getRenderHeight()) / float(m_textures[texNdx]->getTexture().getHeight());
303
304                         m_cases.push_back(FilterCase(texNdx, ref, tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
305                 }
306         }
307
308         m_caseNdx = 0;
309 }
310
311 Texture2DShadowTestInstance::~Texture2DShadowTestInstance (void)
312 {
313         m_textures.clear();
314         m_cases.clear();
315 }
316
317 tcu::TestStatus Texture2DShadowTestInstance::iterate (void)
318 {
319         tcu::TestLog&                                   log                             = m_context.getTestContext().getLog();
320         const pipeline::TestTexture2D&  texture                 = m_renderer.get2DTexture(m_cases[m_caseNdx].textureIndex);
321         const tcu::TextureFormat                texFmt                  = texture.getTextureFormat();
322         const tcu::TextureFormatInfo    fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
323         const tcu::ScopedLogSection             section                 (log, string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
324
325         const FilterCase&                               curCase                 = m_cases[m_caseNdx];
326         ReferenceParams                                 sampleParams    (TEXTURETYPE_2D);
327         tcu::Surface                                    rendered                (m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
328         vector<float>                                   texCoord;
329
330         // Setup params for reference.
331         sampleParams.sampler                    = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
332         sampleParams.sampler.compare    = m_testParameters.compareOp;
333         sampleParams.samplerType                = SAMPLERTYPE_SHADOW;
334         sampleParams.lodMode                    = LODMODE_EXACT;
335         sampleParams.colorBias                  = fmtInfo.lookupBias;
336         sampleParams.colorScale                 = fmtInfo.lookupScale;
337         sampleParams.ref                                = curCase.ref;
338
339         log << TestLog::Message << "Compare reference value = " << sampleParams.ref << TestLog::EndMessage;
340
341         // Compute texture coordinates.
342         log << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
343         computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
344
345         m_renderer.renderQuad(rendered, curCase.textureIndex, &texCoord[0], sampleParams);
346
347         {
348                 const tcu::PixelFormat          pixelFormat                     = getPixelFormat(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
349                 tcu::LodPrecision                       lodPrecision;
350                 tcu::TexComparePrecision        texComparePrecision;
351
352                 lodPrecision.derivateBits                       = 18;
353                 lodPrecision.lodBits                            = 6;
354                 texComparePrecision.coordBits           = tcu::IVec3(20,20,0);
355                 texComparePrecision.uvwBits                     = tcu::IVec3(7,7,0);
356                 texComparePrecision.pcfBits                     = 5;
357                 texComparePrecision.referenceBits       = 16;
358                 texComparePrecision.resultBits          = pixelFormat.redBits-1;
359
360                 const bool isHighQuality = verifyTexCompareResult(m_context.getTestContext(), rendered.getAccess(), texture.getTexture(),
361                                                                                                                   &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
362
363                 if (!isHighQuality)
364                 {
365                         m_context.getTestContext().getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
366
367                         lodPrecision.lodBits                    = 4;
368                         texComparePrecision.uvwBits             = tcu::IVec3(4,4,0);
369                         texComparePrecision.pcfBits             = 0;
370
371                         const bool isOk = verifyTexCompareResult(m_context.getTestContext(), rendered.getAccess(), texture.getTexture(),
372                                                                                                          &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
373
374                         if (!isOk)
375                         {
376                                 m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
377                                 return tcu::TestStatus::fail("Image verification failed");
378                         }
379                 }
380         }
381
382         m_caseNdx += 1;
383         return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
384 }
385
386 struct TextureCubeShadowTestCaseParameters : public TextureShadowCommonTestCaseParameters, public TextureCubeTestCaseParameters
387 {
388 };
389
390 class TextureCubeShadowTestInstance : public TestInstance
391 {
392 public:
393         typedef TextureCubeShadowTestCaseParameters ParameterType;
394                                                                                                 TextureCubeShadowTestInstance           (Context& context, const ParameterType& testParameters);
395                                                                                                 ~TextureCubeShadowTestInstance          (void);
396
397         virtual tcu::TestStatus                                         iterate                                                         (void);
398
399 private:
400                                                                                                 TextureCubeShadowTestInstance           (const TextureCubeShadowTestInstance& other);
401         TextureCubeShadowTestInstance&                          operator=                                                       (const TextureCubeShadowTestInstance& other);
402
403         struct FilterCase
404         {
405                 int                                             textureIndex;
406                 tcu::Vec2                               bottomLeft;
407                 tcu::Vec2                               topRight;
408                 float                                   ref;
409
410                 FilterCase (void)
411                         : textureIndex  (-1)
412                         , ref                   (0.0f)
413                 {
414                 }
415
416                 FilterCase (const int tex_, const float ref_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
417                         : textureIndex  (tex_)
418                         , bottomLeft    (bottomLeft_)
419                         , topRight              (topRight_)
420                         , ref                   (ref_)
421                 {
422                 }
423         };
424
425         const ParameterType&            m_testParameters;
426         vector<TestTextureCubeSp>       m_textures;
427         std::vector<FilterCase>         m_cases;
428
429         TextureRenderer                         m_renderer;
430         int                                                     m_caseNdx;
431 };
432
433 TextureCubeShadowTestInstance::TextureCubeShadowTestInstance (Context& context, const ParameterType& testParameters)
434         : TestInstance                  (context)
435         , m_testParameters              (testParameters)
436         , m_renderer                    (context, testParameters.sampleCount, TEXCUBE_VIEWPORT_SIZE, TEXCUBE_VIEWPORT_SIZE)
437         , m_caseNdx                             (0)
438 {
439         const int                                               numLevels       = deLog2Floor32(m_testParameters.size)+1;
440         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
441         const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
442         const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
443
444         // Create textures.
445
446         m_textures.reserve(2);
447         for (int ndx = 0; ndx < 2; ndx++)
448         {
449                 m_textures.push_back(TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(m_testParameters.format), m_testParameters.size)));
450         }
451
452         // Fill first with gradient texture.
453         static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
454         {
455                 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
456                 { tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
457                 { tcu::Vec4(-1.0f,  0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
458                 { tcu::Vec4(-1.0f, -1.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
459                 { tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
460                 { tcu::Vec4( 0.0f,  0.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
461         };
462         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
463         {
464                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
465                 {
466                         tcu::fillWithComponentGradients(m_textures[0]->getLevel(levelNdx, face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
467                 }
468         }
469
470         // Fill second with grid texture.
471         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
472         {
473                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
474                 {
475                         const deUint32  step    = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
476                         const deUint32  rgb             = step*levelNdx*face;
477                         const deUint32  colorA  = 0xff000000 | rgb;
478                         const deUint32  colorB  = 0xff000000 | ~rgb;
479
480                         tcu::fillWithGrid(m_textures[1]->getLevel(levelNdx, face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
481                 }
482         }
483
484         // Upload.
485         for (vector<TestTextureCubeSp>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
486         {
487                 m_renderer.addCubeTexture(*i);
488         }
489
490         // Compute cases
491         {
492                 const float refInRangeUpper             = (m_testParameters.compareOp == Sampler::COMPAREMODE_EQUAL || m_testParameters.compareOp == Sampler::COMPAREMODE_NOT_EQUAL) ? 1.0f : 0.5f;
493                 const float refInRangeLower             = (m_testParameters.compareOp == Sampler::COMPAREMODE_EQUAL || m_testParameters.compareOp == Sampler::COMPAREMODE_NOT_EQUAL) ? 0.0f : 0.5f;
494                 const float refOutOfBoundsUpper = 1.1f;
495                 const float refOutOfBoundsLower = -0.1f;
496
497                 m_cases.push_back(FilterCase(0, refInRangeUpper,                tcu::Vec2(-1.25f, -1.2f),       tcu::Vec2(1.2f, 1.25f)));       // minification
498                 m_cases.push_back(FilterCase(0, refInRangeLower,                tcu::Vec2(0.8f, 0.8f),          tcu::Vec2(1.25f, 1.20f)));      // magnification
499                 m_cases.push_back(FilterCase(1, refInRangeUpper,                tcu::Vec2(-1.19f, -1.3f),       tcu::Vec2(1.1f, 1.35f)));       // minification
500                 m_cases.push_back(FilterCase(1, refInRangeLower,                tcu::Vec2(-1.2f, -1.1f),        tcu::Vec2(-0.8f, -0.8f)));      // magnification
501                 m_cases.push_back(FilterCase(1, refOutOfBoundsUpper,    tcu::Vec2(-0.61f, -0.1f),       tcu::Vec2(0.9f, 1.18f)));       // reference value clamp, upper
502                 m_cases.push_back(FilterCase(1, refOutOfBoundsLower,    tcu::Vec2(-0.75f, 1.0f),        tcu::Vec2(0.05f, 0.75f)));      // reference value clamp, lower
503         }
504 }
505
506 TextureCubeShadowTestInstance::~TextureCubeShadowTestInstance   (void)
507 {
508 }
509
510 static const char* getFaceDesc (const tcu::CubeFace face)
511 {
512         switch (face)
513         {
514                 case tcu::CUBEFACE_NEGATIVE_X:  return "-X";
515                 case tcu::CUBEFACE_POSITIVE_X:  return "+X";
516                 case tcu::CUBEFACE_NEGATIVE_Y:  return "-Y";
517                 case tcu::CUBEFACE_POSITIVE_Y:  return "+Y";
518                 case tcu::CUBEFACE_NEGATIVE_Z:  return "-Z";
519                 case tcu::CUBEFACE_POSITIVE_Z:  return "+Z";
520                 default:
521                         DE_ASSERT(false);
522                         return DE_NULL;
523         }
524 }
525
526 tcu::TestStatus TextureCubeShadowTestInstance::iterate (void)
527 {
528
529         tcu::TestLog&                                           log                             = m_context.getTestContext().getLog();
530         const tcu::ScopedLogSection                     iterSection             (log, string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
531         const FilterCase&                                       curCase                 = m_cases[m_caseNdx];
532         const pipeline::TestTextureCube&        texture                 = m_renderer.getCubeTexture(curCase.textureIndex);
533
534         ReferenceParams                                         sampleParams    (TEXTURETYPE_CUBE);
535
536         // Params for reference computation.
537         sampleParams.sampler                                    = util::createSampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, m_testParameters.minFilter, m_testParameters.magFilter);
538         sampleParams.sampler.seamlessCubeMap    = true;
539         sampleParams.sampler.compare                    = m_testParameters.compareOp;
540         sampleParams.samplerType                                = SAMPLERTYPE_SHADOW;
541         sampleParams.lodMode                                    = LODMODE_EXACT;
542         sampleParams.ref                                                = curCase.ref;
543
544         log     << TestLog::Message
545                 << "Compare reference value = " << sampleParams.ref << "\n"
546                 << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight
547                 << TestLog::EndMessage;
548
549         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
550         {
551                 const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
552                 tcu::Surface                    result          (m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
553                 vector<float>                   texCoord;
554
555                 computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
556
557                 log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
558
559                 // \todo Log texture coordinates.
560
561                 m_renderer.renderQuad(result, curCase.textureIndex, &texCoord[0], sampleParams);
562
563                 {
564                         const tcu::PixelFormat          pixelFormat                     = getPixelFormat(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
565                         tcu::LodPrecision                       lodPrecision;
566                         tcu::TexComparePrecision        texComparePrecision;
567
568                         lodPrecision.derivateBits                       = 10;
569                         lodPrecision.lodBits                            = 5;
570                         texComparePrecision.coordBits           = tcu::IVec3(10,10,10);
571                         texComparePrecision.uvwBits                     = tcu::IVec3(6,6,0);
572                         texComparePrecision.pcfBits                     = 5;
573                         texComparePrecision.referenceBits       = 16;
574                         texComparePrecision.resultBits          = pixelFormat.redBits-1;
575
576                         const bool isHighQuality = verifyTexCompareResult(m_context.getTestContext(), result.getAccess(), texture.getTexture(),
577                                                                                                                           &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
578
579                         if (!isHighQuality)
580                         {
581                                 log << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
582
583                                 lodPrecision.lodBits                    = 4;
584                                 texComparePrecision.uvwBits             = tcu::IVec3(4,4,0);
585                                 texComparePrecision.pcfBits             = 0;
586
587                                 const bool isOk = verifyTexCompareResult(m_context.getTestContext(), result.getAccess(), texture.getTexture(),
588                                                                                                                  &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
589
590                                 if (!isOk)
591                                 {
592                                         log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
593                                         return tcu::TestStatus::fail("Image verification failed");
594                                 }
595                         }
596                 }
597         }
598
599         m_caseNdx += 1;
600         return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
601 }
602
603 struct Texture2DArrayShadowTestCaseParameters : public TextureShadowCommonTestCaseParameters, public Texture2DArrayTestCaseParameters
604 {
605 };
606
607 class Texture2DArrayShadowTestInstance : public TestInstance
608 {
609 public:
610         typedef Texture2DArrayShadowTestCaseParameters  ParameterType;
611                                                                                                         Texture2DArrayShadowTestInstance                (Context& context, const ParameterType& testParameters);
612                                                                                                         ~Texture2DArrayShadowTestInstance               (void);
613
614         virtual tcu::TestStatus                                                 iterate                                                                 (void);
615
616 private:
617                                                                                                         Texture2DArrayShadowTestInstance                (const Texture2DArrayShadowTestInstance& other);
618         Texture2DArrayShadowTestInstance&                               operator=                                                               (const Texture2DArrayShadowTestInstance& other);
619
620         struct FilterCase
621         {
622                 int                                                     textureIndex;
623                 tcu::Vec3                                       minCoord;
624                 tcu::Vec3                                       maxCoord;
625                 float                                           ref;
626
627                 FilterCase (void)
628                         : textureIndex  (-1)
629                         , ref                   (0.0f)
630                 {
631                 }
632
633                 FilterCase (const int tex_, float ref_, const tcu::Vec3& minCoord_, const tcu::Vec3& maxCoord_)
634                         : textureIndex  (tex_)
635                         , minCoord              (minCoord_)
636                         , maxCoord              (maxCoord_)
637                         , ref                   (ref_)
638                 {
639                 }
640         };
641
642         const ParameterType&                            m_testParameters;
643         std::vector<TestTexture2DArraySp>       m_textures;
644         std::vector<FilterCase>                         m_cases;
645
646         TextureRenderer                                         m_renderer;
647
648         int                                                                     m_caseNdx;
649 };
650
651 Texture2DArrayShadowTestInstance::Texture2DArrayShadowTestInstance (Context& context, const ParameterType& testParameters)
652         : TestInstance                  (context)
653         , m_testParameters              (testParameters)
654         , m_renderer                    (context, testParameters.sampleCount, TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT)
655         , m_caseNdx                             (0)
656 {
657         const int                                               numLevels       = deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height))+1;
658         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(vk::mapVkFormat(m_testParameters.format));
659         const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
660         const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
661
662         // Create 2 textures.
663         m_textures.reserve(2);
664         for (int ndx = 0; ndx < 2; ndx++)
665         {
666                 m_textures.push_back(TestTexture2DArraySp(new pipeline::TestTexture2DArray(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.numLayers)));
667         }
668
669         // Fill first gradient texture.
670         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
671         {
672                 const tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
673                 const tcu::Vec4 gMax = tcu::Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
674
675                 tcu::fillWithComponentGradients(m_textures[0]->getTexture().getLevel(levelNdx), gMin, gMax);
676         }
677
678         // Fill second with grid texture.
679         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
680         {
681                 const deUint32  step    = 0x00ffffff / numLevels;
682                 const deUint32  rgb             = step*levelNdx;
683                 const deUint32  colorA  = 0xff000000 | rgb;
684                 const deUint32  colorB  = 0xff000000 | ~rgb;
685
686                 tcu::fillWithGrid(m_textures[1]->getTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
687         }
688
689         // Upload.
690         for (std::vector<TestTexture2DArraySp>::iterator i = m_textures.begin(); i != m_textures.end(); ++i)
691         {
692                 m_renderer.add2DArrayTexture(*i);
693         }
694
695         // Compute cases.
696         {
697                 const float refInRangeUpper             = (m_testParameters.compareOp == Sampler::COMPAREMODE_EQUAL || m_testParameters.compareOp == Sampler::COMPAREMODE_NOT_EQUAL) ? 1.0f : 0.5f;
698                 const float refInRangeLower             = (m_testParameters.compareOp == Sampler::COMPAREMODE_EQUAL || m_testParameters.compareOp == Sampler::COMPAREMODE_NOT_EQUAL) ? 0.0f : 0.5f;
699                 const float refOutOfBoundsUpper = 1.1f;         // !< lookup function should clamp values to [0, 1] range
700                 const float refOutOfBoundsLower = -0.1f;
701
702                 const struct
703                 {
704                         const int       texNdx;
705                         const float     ref;
706                         const float     lodX;
707                         const float     lodY;
708                         const float     oX;
709                         const float     oY;
710                 } cases[] =
711                 {
712                         { 0,    refInRangeUpper,                1.6f,   2.9f,   -1.0f,  -2.7f   },
713                         { 0,    refInRangeLower,                -2.0f,  -1.35f, -0.2f,  0.7f    },
714                         { 1,    refInRangeUpper,                0.14f,  0.275f, -1.5f,  -1.1f   },
715                         { 1,    refInRangeLower,                -0.92f, -2.64f, 0.4f,   -0.1f   },
716                         { 1,    refOutOfBoundsUpper,    -0.49f, -0.22f, 0.45f,  0.97f   },
717                         { 1,    refOutOfBoundsLower,    -0.85f, 0.75f,  0.25f,  0.61f   },
718                 };
719
720                 const float     minLayer        = -0.5f;
721                 const float     maxLayer        = (float)m_testParameters.numLayers;
722
723                 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
724                 {
725                         const int       tex             = cases[caseNdx].texNdx > 0 ? 1 : 0;
726                         const float     ref             = cases[caseNdx].ref;
727                         const float     lodX    = cases[caseNdx].lodX;
728                         const float     lodY    = cases[caseNdx].lodY;
729                         const float     oX              = cases[caseNdx].oX;
730                         const float     oY              = cases[caseNdx].oY;
731                         const float     sX              = deFloatExp2(lodX) * float(m_renderer.getRenderWidth()) / float(m_textures[tex]->getTexture().getWidth());
732                         const float     sY              = deFloatExp2(lodY) * float(m_renderer.getRenderHeight()) / float(m_textures[tex]->getTexture().getHeight());
733
734                         m_cases.push_back(FilterCase(tex, ref, tcu::Vec3(oX, oY, minLayer), tcu::Vec3(oX+sX, oY+sY, maxLayer)));
735                 }
736         }
737 }
738
739 Texture2DArrayShadowTestInstance::~Texture2DArrayShadowTestInstance (void)
740 {
741 }
742
743 tcu::TestStatus Texture2DArrayShadowTestInstance::iterate (void)
744 {
745         tcu::TestLog&                                           log                             = m_context.getTestContext().getLog();
746         const FilterCase&                                       curCase                 = m_cases[m_caseNdx];
747         const pipeline::TestTexture2DArray&     texture                 = m_renderer.get2DArrayTexture(curCase.textureIndex);
748
749         ReferenceParams                                         sampleParams    (TEXTURETYPE_2D_ARRAY);
750         tcu::Surface                                            rendered                (m_renderer.getRenderWidth(), m_renderer.getRenderHeight());
751         const tcu::ScopedLogSection                     section                 (log, string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
752
753         const float                                                     texCoord[]              =
754         {
755                 curCase.minCoord.x(), curCase.minCoord.y(), curCase.minCoord.z(),
756                 curCase.minCoord.x(), curCase.maxCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
757                 curCase.maxCoord.x(), curCase.minCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
758                 curCase.maxCoord.x(), curCase.maxCoord.y(), curCase.maxCoord.z()
759         };
760
761         // Setup params for reference.
762         sampleParams.sampler                    = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
763         sampleParams.sampler.compare    = m_testParameters.compareOp;
764         sampleParams.samplerType                = SAMPLERTYPE_SHADOW;
765         sampleParams.lodMode                    = LODMODE_EXACT;
766         sampleParams.ref                                = curCase.ref;
767
768         log     << TestLog::Message
769                 << "Compare reference value = " << sampleParams.ref << "\n"
770                 << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord
771                 << TestLog::EndMessage;
772
773         m_renderer.renderQuad(rendered, curCase.textureIndex, &texCoord[0], sampleParams);
774
775         {
776                 const tcu::PixelFormat          pixelFormat                     = getPixelFormat(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
777                 tcu::LodPrecision                       lodPrecision;
778                 tcu::TexComparePrecision        texComparePrecision;
779
780                 lodPrecision.derivateBits                       = 18;
781                 lodPrecision.lodBits                            = 6;
782                 texComparePrecision.coordBits           = tcu::IVec3(20,20,20);
783                 texComparePrecision.uvwBits                     = tcu::IVec3(7,7,7);
784                 texComparePrecision.pcfBits                     = 5;
785                 texComparePrecision.referenceBits       = 16;
786                 texComparePrecision.resultBits          = pixelFormat.redBits-1;
787
788                 const bool isHighQuality = verifyTexCompareResult(m_context.getTestContext(), rendered.getAccess(), texture.getTexture(),
789                                                                                                                   &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
790
791                 if (!isHighQuality)
792                 {
793                         log << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
794
795                         lodPrecision.lodBits                    = 4;
796                         texComparePrecision.uvwBits             = tcu::IVec3(4,4,4);
797                         texComparePrecision.pcfBits             = 0;
798
799                         const bool isOk = verifyTexCompareResult(m_context.getTestContext(), rendered.getAccess(), texture.getTexture(),
800                                                                                                          &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
801
802                         if (!isOk)
803                         {
804                                 log << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
805                                 return tcu::TestStatus::fail("Image verification failed");
806                         }
807                 }
808         }
809
810         m_caseNdx += 1;
811         return m_caseNdx < (int)m_cases.size() ? tcu::TestStatus::incomplete() : tcu::TestStatus::pass("Pass");
812 }
813
814 void populateTextureShadowTests (tcu::TestCaseGroup* textureShadowTests)
815 {
816         tcu::TestContext&                               testCtx                         = textureShadowTests->getTestContext();
817
818         static const struct
819         {
820                 const char*             name;
821                 const VkFormat  format;
822         } formats[] =
823         {
824                 { "d16_unorm",                          VK_FORMAT_D16_UNORM                             },
825                 { "x8_d24_unorm_pack32",        VK_FORMAT_X8_D24_UNORM_PACK32   },
826                 { "d32_sfloat",                         VK_FORMAT_D32_SFLOAT                    },
827                 { "d16_unorm_s8_uint",          VK_FORMAT_D16_UNORM_S8_UINT             },
828                 { "d24_unorm_s8_uint",          VK_FORMAT_D24_UNORM_S8_UINT             },
829                 { "d32_sfloat_s8_uint",         VK_FORMAT_D32_SFLOAT_S8_UINT    }
830         };
831
832         static const struct
833         {
834                 const char*                                     name;
835                 const Sampler::FilterMode       minFilter;
836                 const Sampler::FilterMode       magFilter;
837         } filters[] =
838         {
839                 { "nearest",                            Sampler::NEAREST,                                       Sampler::NEAREST        },
840                 { "linear",                                     Sampler::LINEAR,                                        Sampler::LINEAR         },
841                 { "nearest_mipmap_nearest",     Sampler::NEAREST_MIPMAP_NEAREST,        Sampler::LINEAR         },
842                 { "linear_mipmap_nearest",      Sampler::LINEAR_MIPMAP_NEAREST,         Sampler::LINEAR         },
843                 { "nearest_mipmap_linear",      Sampler::NEAREST_MIPMAP_LINEAR,         Sampler::LINEAR         },
844                 { "linear_mipmap_linear",       Sampler::LINEAR_MIPMAP_LINEAR,          Sampler::LINEAR         }
845         };
846
847         static const struct
848         {
849                 const char*                                     name;
850                 const Sampler::CompareMode      op;
851         } compareOp[] =
852         {
853                 { "less_or_equal",              Sampler::COMPAREMODE_LESS_OR_EQUAL              },
854                 { "greater_or_equal",   Sampler::COMPAREMODE_GREATER_OR_EQUAL   },
855                 { "less",                               Sampler::COMPAREMODE_LESS                               },
856                 { "greater",                    Sampler::COMPAREMODE_GREATER                    },
857                 { "equal",                              Sampler::COMPAREMODE_EQUAL                              },
858                 { "not_equal",                  Sampler::COMPAREMODE_NOT_EQUAL                  },
859                 { "always",                             Sampler::COMPAREMODE_ALWAYS                             },
860                 { "never",                              Sampler::COMPAREMODE_NEVER                              }
861         };
862
863         // 2D cases.
864         {
865                 de::MovePtr<tcu::TestCaseGroup> group2D (new tcu::TestCaseGroup(testCtx, "2d", "2D texture shadow lookup tests"));
866
867                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
868                 {
869                         de::MovePtr<tcu::TestCaseGroup> filterGroup     (new tcu::TestCaseGroup(testCtx, filters[filterNdx].name, ""));
870
871                         for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareOp); compareNdx++)
872                         {
873                                 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
874                                 {
875                                         const string                                            name                    = string(compareOp[compareNdx].name) + "_" + formats[formatNdx].name;
876                                         Texture2DShadowTestCaseParameters       testParameters;
877
878                                         testParameters.minFilter        = filters[filterNdx].minFilter;
879                                         testParameters.magFilter        = filters[filterNdx].magFilter;
880                                         testParameters.format           = formats[formatNdx].format;
881                                         testParameters.compareOp        = compareOp[compareNdx].op;
882                                         testParameters.wrapS            = Sampler::REPEAT_GL;
883                                         testParameters.wrapT            = Sampler::REPEAT_GL;
884                                         testParameters.width            = 32;
885                                         testParameters.height           = 64;
886
887                                         testParameters.programs.push_back(PROGRAM_2D_SHADOW);
888
889                                         filterGroup->addChild(new TextureTestCase<Texture2DShadowTestInstance>(testCtx, name.c_str(), "", testParameters));
890                                 }
891                         }
892
893                         group2D->addChild(filterGroup.release());
894                 }
895
896                 textureShadowTests->addChild(group2D.release());
897         }
898
899         // Cubemap cases.
900         {
901                 de::MovePtr<tcu::TestCaseGroup> groupCube       (new tcu::TestCaseGroup(testCtx, "cube", "Cube map texture shadow lookup tests"));
902
903                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
904                 {
905                         de::MovePtr<tcu::TestCaseGroup> filterGroup     (new tcu::TestCaseGroup(testCtx, filters[filterNdx].name, ""));
906
907                         for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareOp); compareNdx++)
908                         {
909                                 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
910                                 {
911                                         const string                                                    name                    = string(compareOp[compareNdx].name) + "_" + formats[formatNdx].name;
912                                         TextureCubeShadowTestCaseParameters             testParameters;
913
914                                         testParameters.minFilter        = filters[filterNdx].minFilter;
915                                         testParameters.magFilter        = filters[filterNdx].magFilter;
916                                         testParameters.format           = formats[formatNdx].format;
917                                         testParameters.compareOp        = compareOp[compareNdx].op;
918                                         testParameters.wrapS            = Sampler::REPEAT_GL;
919                                         testParameters.wrapT            = Sampler::REPEAT_GL;
920                                         testParameters.size                     = 32;
921
922                                         testParameters.programs.push_back(PROGRAM_CUBE_SHADOW);
923
924                                         filterGroup->addChild(new TextureTestCase<TextureCubeShadowTestInstance>(testCtx, name.c_str(), "", testParameters));
925                                 }
926                         }
927
928                         groupCube->addChild(filterGroup.release());
929                 }
930
931                 textureShadowTests->addChild(groupCube.release());
932         }
933
934         // 2D array cases.
935         {
936                 de::MovePtr<tcu::TestCaseGroup> group2DArray    (new tcu::TestCaseGroup(testCtx, "2d_array", "2D texture array shadow lookup tests"));
937
938                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
939                 {
940                         de::MovePtr<tcu::TestCaseGroup> filterGroup     (new tcu::TestCaseGroup(testCtx, filters[filterNdx].name, ""));
941
942                         for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareOp); compareNdx++)
943                         {
944                                 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
945                                 {
946                                         const string                                                    name                    = string(compareOp[compareNdx].name) + "_" + formats[formatNdx].name;
947                                         Texture2DArrayShadowTestCaseParameters  testParameters;
948
949                                         testParameters.minFilter        = filters[filterNdx].minFilter;
950                                         testParameters.magFilter        = filters[filterNdx].magFilter;
951                                         testParameters.format           = formats[formatNdx].format;
952                                         testParameters.compareOp        = compareOp[compareNdx].op;
953                                         testParameters.wrapS            = Sampler::REPEAT_GL;
954                                         testParameters.wrapT            = Sampler::REPEAT_GL;
955                                         testParameters.width            = 32;
956                                         testParameters.height           = 64;
957                                         testParameters.numLayers        = 8;
958
959                                         testParameters.programs.push_back(PROGRAM_2D_ARRAY_SHADOW);
960
961                                         filterGroup->addChild(new TextureTestCase<Texture2DArrayShadowTestInstance>(testCtx, name.c_str(), "", testParameters));
962                                 }
963                         }
964
965                         group2DArray->addChild(filterGroup.release());
966                 }
967
968                 textureShadowTests->addChild(group2DArray.release());
969         }
970 }
971
972 } // anonymous
973
974 tcu::TestCaseGroup* createTextureShadowTests (tcu::TestContext& testCtx)
975 {
976         return createTestGroup(testCtx, "shadow", "Texture shadow tests.", populateTextureShadowTests);
977 }
978
979 } // texture
980 } // vkt