Merge "Fix extension support checks in negative api tests" into nougat-cts-dev am...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fTextureShadowTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Shadow texture lookup tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fTextureShadowTests.hpp"
25 #include "gluTexture.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluTextureUtil.hpp"
28 #include "glsTextureTestUtil.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "tcuTexCompareVerifier.hpp"
32 #include "deString.h"
33 #include "deMath.h"
34 #include "deStringUtil.hpp"
35 #include "glwFunctions.hpp"
36 #include "glwEnums.hpp"
37
38 namespace deqp
39 {
40 namespace gles3
41 {
42 namespace Functional
43 {
44
45 using std::vector;
46 using std::string;
47 using tcu::TestLog;
48 using namespace deqp::gls::TextureTestUtil;
49 using namespace glu::TextureTestUtil;
50
51 enum
52 {
53         TEX2D_VIEWPORT_WIDTH            = 64,
54         TEX2D_VIEWPORT_HEIGHT           = 64,
55         TEX2D_MIN_VIEWPORT_WIDTH        = 64,
56         TEX2D_MIN_VIEWPORT_HEIGHT       = 64
57 };
58
59 static bool isFloatingPointDepthFormat (const tcu::TextureFormat& format)
60 {
61         // Only two depth and depth-stencil formats are floating point
62         return  (format.order == tcu::TextureFormat::D && format.type == tcu::TextureFormat::FLOAT) ||
63                         (format.order == tcu::TextureFormat::DS && format.type == tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV);
64 }
65
66 static void clampFloatingPointTexture (const tcu::PixelBufferAccess& access)
67 {
68         DE_ASSERT(isFloatingPointDepthFormat(access.getFormat()));
69
70         for (int z = 0; z < access.getDepth(); ++z)
71         for (int y = 0; y < access.getHeight(); ++y)
72         for (int x = 0; x < access.getWidth(); ++x)
73                 access.setPixDepth( de::clamp(access.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z);
74 }
75
76 static void clampFloatingPointTexture (tcu::Texture2D& target)
77 {
78         for (int level = 0; level < target.getNumLevels(); ++level)
79                 if (!target.isLevelEmpty(level))
80                         clampFloatingPointTexture(target.getLevel(level));
81 }
82
83 static void clampFloatingPointTexture (tcu::Texture2DArray& target)
84 {
85         for (int level = 0; level < target.getNumLevels(); ++level)
86                 if (!target.isLevelEmpty(level))
87                         clampFloatingPointTexture(target.getLevel(level));
88 }
89
90 static void clampFloatingPointTexture (tcu::TextureCube& target)
91 {
92         for (int level = 0; level < target.getNumLevels(); ++level)
93                 for (int face = tcu::CUBEFACE_NEGATIVE_X; face < tcu::CUBEFACE_LAST; ++face)
94                         clampFloatingPointTexture(target.getLevelFace(level, (tcu::CubeFace)face));
95 }
96
97 template<typename TextureType>
98 bool verifyTexCompareResult (tcu::TestContext&                                          testCtx,
99                                                          const tcu::ConstPixelBufferAccess&             result,
100                                                          const TextureType&                                             src,
101                                                          const float*                                                   texCoord,
102                                                          const ReferenceParams&                                 sampleParams,
103                                                          const tcu::TexComparePrecision&                comparePrec,
104                                                          const tcu::LodPrecision&                               lodPrec,
105                                                          const tcu::PixelFormat&                                pixelFormat)
106 {
107         tcu::TestLog&   log                                     = testCtx.getLog();
108         tcu::Surface    reference                       (result.getWidth(), result.getHeight());
109         tcu::Surface    errorMask                       (result.getWidth(), result.getHeight());
110         const tcu::Vec3 nonShadowThreshold      = tcu::computeFixedPointThreshold(getBitsVec(pixelFormat)-1).swizzle(1,2,3);
111         int                             numFailedPixels;
112
113         // sampleTexture() expects source image to be the same state as it would be in a GL implementation, that is
114         // the floating point depth values should be in [0, 1] range as data is clamped during texture upload. Since
115         // we don't have a separate "uploading" phase and just reuse the buffer we used for GL-upload, do the clamping
116         // here if necessary.
117
118         if (isFloatingPointDepthFormat(src.getFormat()))
119         {
120                 TextureType clampedSource(src);
121
122                 clampFloatingPointTexture(clampedSource);
123
124                 // sample clamped values
125
126                 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), clampedSource, texCoord, sampleParams);
127                 numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), clampedSource, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
128         }
129         else
130         {
131                 // sample raw values (they are guaranteed to be in [0, 1] range as the format cannot represent any other values)
132
133                 sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
134                 numFailedPixels = computeTextureCompareDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold);
135         }
136
137         if (numFailedPixels > 0)
138                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
139
140         log << TestLog::ImageSet("VerifyResult", "Verification result")
141                 << TestLog::Image("Rendered", "Rendered image", result);
142
143         if (numFailedPixels > 0)
144         {
145                 log << TestLog::Image("Reference", "Ideal reference image", reference)
146                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
147         }
148
149         log << TestLog::EndImageSet;
150
151         return numFailedPixels == 0;
152 }
153
154 class Texture2DShadowCase : public TestCase
155 {
156 public:
157                                                                         Texture2DShadowCase                     (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, deUint32 compareFunc);
158                                                                         ~Texture2DShadowCase            (void);
159
160         void                                                    init                                            (void);
161         void                                                    deinit                                          (void);
162         IterateResult                                   iterate                                         (void);
163
164 private:
165                                                                         Texture2DShadowCase                     (const Texture2DShadowCase& other);
166         Texture2DShadowCase&                    operator=                                       (const Texture2DShadowCase& other);
167
168         const deUint32                                  m_minFilter;
169         const deUint32                                  m_magFilter;
170         const deUint32                                  m_wrapS;
171         const deUint32                                  m_wrapT;
172         const deUint32                                  m_format;
173         const int                                               m_width;
174         const int                                               m_height;
175         const deUint32                                  m_compareFunc;
176
177         struct FilterCase
178         {
179                 const glu::Texture2D*   texture;
180                 tcu::Vec2                               minCoord;
181                 tcu::Vec2                               maxCoord;
182                 float                                   ref;
183
184                 FilterCase (void)
185                         : texture       (DE_NULL)
186                         , ref           (0.0f)
187                 {
188                 }
189
190                 FilterCase (const glu::Texture2D* tex_, const float ref_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
191                         : texture       (tex_)
192                         , minCoord      (minCoord_)
193                         , maxCoord      (maxCoord_)
194                         , ref           (ref_)
195                 {
196                 }
197         };
198
199         std::vector<glu::Texture2D*>    m_textures;
200         std::vector<FilterCase>                 m_cases;
201
202         TextureRenderer                                 m_renderer;
203
204         int                                                             m_caseNdx;
205 };
206
207 Texture2DShadowCase::Texture2DShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, deUint32 compareFunc)
208         : TestCase                      (context, name, desc)
209         , m_minFilter           (minFilter)
210         , m_magFilter           (magFilter)
211         , m_wrapS                       (wrapS)
212         , m_wrapT                       (wrapT)
213         , m_format                      (format)
214         , m_width                       (width)
215         , m_height                      (height)
216         , m_compareFunc         (compareFunc)
217         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
218         , m_caseNdx                     (0)
219 {
220 }
221
222 Texture2DShadowCase::~Texture2DShadowCase (void)
223 {
224         deinit();
225 }
226
227 void Texture2DShadowCase::init (void)
228 {
229         try
230         {
231                 // Create 2 textures.
232                 m_textures.reserve(2);
233                 m_textures.push_back(new glu::Texture2D(m_context.getRenderContext(), m_format, m_width, m_height));
234                 m_textures.push_back(new glu::Texture2D(m_context.getRenderContext(), m_format, m_width, m_height));
235
236                 int numLevels = m_textures[0]->getRefTexture().getNumLevels();
237
238                 // Fill first gradient texture.
239                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
240                 {
241                         m_textures[0]->getRefTexture().allocLevel(levelNdx);
242                         tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
243                 }
244
245                 // Fill second with grid texture.
246                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
247                 {
248                         deUint32        step    = 0x00ffffff / numLevels;
249                         deUint32        rgb             = step*levelNdx;
250                         deUint32        colorA  = 0xff000000 | rgb;
251                         deUint32        colorB  = 0xff000000 | ~rgb;
252
253                         m_textures[1]->getRefTexture().allocLevel(levelNdx);
254                         tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec(), tcu::RGBA(colorB).toVec());
255                 }
256
257                 // Upload.
258                 for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
259                         (*i)->upload();
260         }
261         catch (const std::exception&)
262         {
263                 // Clean up to save memory.
264                 Texture2DShadowCase::deinit();
265                 throw;
266         }
267
268         // Compute cases.
269         {
270                 const float refInRangeUpper             = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
271                 const float refInRangeLower             = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 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                         int             texNdx;
278                         float   ref;
279                         float   lodX;
280                         float   lodY;
281                         float   oX;
282                         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                 const float     viewportW       = (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_context.getRenderTarget().getWidth());
294                 const float     viewportH       = (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_context.getRenderTarget().getHeight());
295
296                 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
297                 {
298                         const int       texNdx  = de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
299                         const float ref         = cases[caseNdx].ref;
300                         const float     lodX    = cases[caseNdx].lodX;
301                         const float     lodY    = cases[caseNdx].lodY;
302                         const float     oX              = cases[caseNdx].oX;
303                         const float     oY              = cases[caseNdx].oY;
304                         const float     sX              = deFloatExp2(lodX)*viewportW / float(m_textures[texNdx]->getRefTexture().getWidth());
305                         const float     sY              = deFloatExp2(lodY)*viewportH / float(m_textures[texNdx]->getRefTexture().getHeight());
306
307                         m_cases.push_back(FilterCase(m_textures[texNdx], ref, tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
308                 }
309         }
310
311         m_caseNdx = 0;
312         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
313 }
314
315 void Texture2DShadowCase::deinit (void)
316 {
317         for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
318                 delete *i;
319         m_textures.clear();
320
321         m_renderer.clear();
322         m_cases.clear();
323 }
324
325 Texture2DShadowCase::IterateResult Texture2DShadowCase::iterate (void)
326 {
327         const glw::Functions&                   gl                              = m_context.getRenderContext().getFunctions();
328         const RandomViewport                    viewport                (m_context.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
329         const FilterCase&                               curCase                 = m_cases[m_caseNdx];
330         const tcu::ScopedLogSection             section                 (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
331         ReferenceParams                                 sampleParams    (TEXTURETYPE_2D);
332         tcu::Surface                                    rendered                (viewport.width, viewport.height);
333         vector<float>                                   texCoord;
334
335         if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
336                 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
337
338         // Setup params for reference.
339         sampleParams.sampler                    = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
340         sampleParams.sampler.compare    = glu::mapGLCompareFunc(m_compareFunc);
341         sampleParams.samplerType                = SAMPLERTYPE_SHADOW;
342         sampleParams.lodMode                    = LODMODE_EXACT;
343         sampleParams.ref                                = curCase.ref;
344
345         m_testCtx.getLog() << TestLog::Message << "Compare reference value =  " << sampleParams.ref << TestLog::EndMessage;
346
347         // Compute texture coordinates.
348         m_testCtx.getLog() << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
349         computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
350
351         gl.bindTexture  (GL_TEXTURE_2D, curCase.texture->getGLTexture());
352         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,          m_minFilter);
353         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,          m_magFilter);
354         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,                      m_wrapS);
355         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,                      m_wrapT);
356         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,        GL_COMPARE_REF_TO_TEXTURE);
357         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC,        m_compareFunc);
358
359         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
360         m_renderer.renderQuad(0, &texCoord[0], sampleParams);
361         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
362
363         {
364                 const tcu::PixelFormat          pixelFormat             = m_context.getRenderTarget().getPixelFormat();
365                 tcu::LodPrecision                       lodPrecision;
366                 tcu::TexComparePrecision        texComparePrecision;
367
368                 lodPrecision.derivateBits                       = 18;
369                 lodPrecision.lodBits                            = 6;
370                 texComparePrecision.coordBits           = tcu::IVec3(20,20,0);
371                 texComparePrecision.uvwBits                     = tcu::IVec3(7,7,0);
372                 texComparePrecision.pcfBits                     = 5;
373                 texComparePrecision.referenceBits       = 16;
374                 texComparePrecision.resultBits          = pixelFormat.redBits-1;
375
376                 const bool isHighQuality = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
377                                                                                                                   &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
378
379                 if (!isHighQuality)
380                 {
381                         m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
382
383                         lodPrecision.lodBits                    = 4;
384                         texComparePrecision.uvwBits             = tcu::IVec3(4,4,0);
385                         texComparePrecision.pcfBits             = 0;
386
387                         const bool isOk = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
388                                                                                                          &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
389
390                         if (!isOk)
391                         {
392                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
393                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
394                         }
395                         else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
396                                 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
397                 }
398         }
399
400         m_caseNdx += 1;
401         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
402 }
403
404 class TextureCubeShadowCase : public TestCase
405 {
406 public:
407                                                                 TextureCubeShadowCase           (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int size, deUint32 compareFunc);
408                                                                 ~TextureCubeShadowCase          (void);
409
410         void                                            init                                            (void);
411         void                                            deinit                                          (void);
412         IterateResult                           iterate                                         (void);
413
414 private:
415                                                                 TextureCubeShadowCase           (const TextureCubeShadowCase& other);
416         TextureCubeShadowCase&          operator=                                       (const TextureCubeShadowCase& other);
417
418         const deUint32                          m_minFilter;
419         const deUint32                          m_magFilter;
420         const deUint32                          m_wrapS;
421         const deUint32                          m_wrapT;
422
423         const deUint32                          m_format;
424         const int                                       m_size;
425
426         const deUint32                          m_compareFunc;
427
428         struct FilterCase
429         {
430                 const glu::TextureCube* texture;
431                 tcu::Vec2                               bottomLeft;
432                 tcu::Vec2                               topRight;
433                 float                                   ref;
434
435                 FilterCase (void)
436                         : texture       (DE_NULL)
437                         , ref           (0.0f)
438                 {
439                 }
440
441                 FilterCase (const glu::TextureCube* tex_, const float ref_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
442                         : texture       (tex_)
443                         , bottomLeft(bottomLeft_)
444                         , topRight      (topRight_)
445                         , ref           (ref_)
446                 {
447                 }
448         };
449
450         glu::TextureCube*                       m_gradientTex;
451         glu::TextureCube*                       m_gridTex;
452         std::vector<FilterCase>         m_cases;
453
454         TextureRenderer                         m_renderer;
455
456         int                                                     m_caseNdx;
457 };
458
459 TextureCubeShadowCase::TextureCubeShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int size, deUint32 compareFunc)
460         : TestCase                      (context, name, desc)
461         , m_minFilter           (minFilter)
462         , m_magFilter           (magFilter)
463         , m_wrapS                       (wrapS)
464         , m_wrapT                       (wrapT)
465         , m_format                      (format)
466         , m_size                        (size)
467         , m_compareFunc         (compareFunc)
468         , m_gradientTex         (DE_NULL)
469         , m_gridTex                     (DE_NULL)
470         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
471         , m_caseNdx                     (0)
472 {
473 }
474
475 TextureCubeShadowCase::~TextureCubeShadowCase (void)
476 {
477         TextureCubeShadowCase::deinit();
478 }
479
480 void TextureCubeShadowCase::init (void)
481 {
482         try
483         {
484                 DE_ASSERT(!m_gradientTex && !m_gridTex);
485
486                 int                                             numLevels       = deLog2Floor32(m_size)+1;
487                 tcu::TextureFormat              texFmt          = glu::mapGLInternalFormat(m_format);
488                 tcu::TextureFormatInfo  fmtInfo         = tcu::getTextureFormatInfo(texFmt);
489                 tcu::Vec4                               cBias           = fmtInfo.valueMin;
490                 tcu::Vec4                               cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
491
492                 // Create textures.
493                 m_gradientTex   = new glu::TextureCube(m_context.getRenderContext(), m_format, m_size);
494                 m_gridTex               = new glu::TextureCube(m_context.getRenderContext(), m_format, m_size);
495
496                 // Fill first with gradient texture.
497                 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
498                 {
499                         { tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
500                         { tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
501                         { tcu::Vec4(-1.0f,  0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
502                         { tcu::Vec4(-1.0f, -1.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
503                         { tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
504                         { tcu::Vec4( 0.0f,  0.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
505                 };
506                 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
507                 {
508                         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
509                         {
510                                 m_gradientTex->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
511                                 tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
512                         }
513                 }
514
515                 // Fill second with grid texture.
516                 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
517                 {
518                         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
519                         {
520                                 deUint32        step    = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
521                                 deUint32        rgb             = step*levelNdx*face;
522                                 deUint32        colorA  = 0xff000000 | rgb;
523                                 deUint32        colorB  = 0xff000000 | ~rgb;
524
525                                 m_gridTex->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
526                                 tcu::fillWithGrid(m_gridTex->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
527                         }
528                 }
529
530                 // Upload.
531                 m_gradientTex->upload();
532                 m_gridTex->upload();
533         }
534         catch (const std::exception&)
535         {
536                 // Clean up to save memory.
537                 TextureCubeShadowCase::deinit();
538                 throw;
539         }
540
541         // Compute cases
542         {
543                 const float refInRangeUpper             = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
544                 const float refInRangeLower             = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
545                 const float refOutOfBoundsUpper = 1.1f;
546                 const float refOutOfBoundsLower = -0.1f;
547                 const bool      singleSample            = m_context.getRenderTarget().getNumSamples() == 0;
548
549                 if (singleSample)
550                         m_cases.push_back(FilterCase(m_gradientTex,     refInRangeUpper, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f)));    // minification
551                 else
552                         m_cases.push_back(FilterCase(m_gradientTex,     refInRangeUpper, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));    // minification - w/ tuned coordinates to avoid hitting triangle edges
553
554                 m_cases.push_back(FilterCase(m_gradientTex,     refInRangeLower,                tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f)));       // magnification
555                 m_cases.push_back(FilterCase(m_gridTex,         refInRangeUpper,                tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));     // minification
556                 m_cases.push_back(FilterCase(m_gridTex,         refInRangeLower,                tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f)));     // magnification
557                 m_cases.push_back(FilterCase(m_gridTex,         refOutOfBoundsUpper,    tcu::Vec2(-0.61f, -0.1f), tcu::Vec2(0.9f, 1.18f)));     // reference value clamp, upper
558
559                 if (singleSample)
560                         m_cases.push_back(FilterCase(m_gridTex, refOutOfBoundsLower, tcu::Vec2(-0.75f, 1.0f), tcu::Vec2(0.05f, 0.75f)));        // reference value clamp, lower
561                 else
562                         m_cases.push_back(FilterCase(m_gridTex, refOutOfBoundsLower, tcu::Vec2(-0.75f, 1.0f), tcu::Vec2(0.25f, 0.75f)));        // reference value clamp, lower
563         }
564
565         m_caseNdx = 0;
566         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
567 }
568
569 void TextureCubeShadowCase::deinit (void)
570 {
571         delete m_gradientTex;
572         delete m_gridTex;
573
574         m_gradientTex   = DE_NULL;
575         m_gridTex               = DE_NULL;
576
577         m_renderer.clear();
578         m_cases.clear();
579 }
580
581 static const char* getFaceDesc (const tcu::CubeFace face)
582 {
583         switch (face)
584         {
585                 case tcu::CUBEFACE_NEGATIVE_X:  return "-X";
586                 case tcu::CUBEFACE_POSITIVE_X:  return "+X";
587                 case tcu::CUBEFACE_NEGATIVE_Y:  return "-Y";
588                 case tcu::CUBEFACE_POSITIVE_Y:  return "+Y";
589                 case tcu::CUBEFACE_NEGATIVE_Z:  return "-Z";
590                 case tcu::CUBEFACE_POSITIVE_Z:  return "+Z";
591                 default:
592                         DE_ASSERT(false);
593                         return DE_NULL;
594         }
595 }
596
597 TextureCubeShadowCase::IterateResult TextureCubeShadowCase::iterate (void)
598 {
599         const glw::Functions&                   gl                              = m_context.getRenderContext().getFunctions();
600         const int                                               viewportSize    = 28;
601         const RandomViewport                    viewport                (m_context.getRenderTarget(), viewportSize, viewportSize, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
602         const tcu::ScopedLogSection             iterSection             (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
603         const FilterCase&                               curCase                 = m_cases[m_caseNdx];
604         ReferenceParams                                 sampleParams    (TEXTURETYPE_CUBE);
605
606         if (viewport.width < viewportSize || viewport.height < viewportSize)
607                 throw tcu::NotSupportedError("Too small render target", DE_NULL, __FILE__, __LINE__);
608
609         // Setup texture
610         gl.bindTexture  (GL_TEXTURE_CUBE_MAP, curCase.texture->getGLTexture());
611         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,    m_minFilter);
612         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,    m_magFilter);
613         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,                m_wrapS);
614         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,                m_wrapT);
615         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE,  GL_COMPARE_REF_TO_TEXTURE);
616         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC,  m_compareFunc);
617
618         // Other state
619         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
620
621         // Params for reference computation.
622         sampleParams.sampler                                    = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
623         sampleParams.sampler.seamlessCubeMap    = true;
624         sampleParams.sampler.compare                    = glu::mapGLCompareFunc(m_compareFunc);
625         sampleParams.samplerType                                = SAMPLERTYPE_SHADOW;
626         sampleParams.lodMode                                    = LODMODE_EXACT;
627         sampleParams.ref                                                = curCase.ref;
628
629         m_testCtx.getLog()
630                 << TestLog::Message
631                 << "Compare reference value =  " << sampleParams.ref << "\n"
632                 << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight
633                 << TestLog::EndMessage;
634
635         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
636         {
637                 const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
638                 tcu::Surface                    result          (viewport.width, viewport.height);
639                 vector<float>                   texCoord;
640
641                 computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
642
643                 m_testCtx.getLog() << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
644
645                 // \todo Log texture coordinates.
646
647                 m_renderer.renderQuad(0, &texCoord[0], sampleParams);
648                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
649
650                 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, result.getAccess());
651                 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
652
653                 {
654                         const tcu::PixelFormat          pixelFormat             = m_context.getRenderTarget().getPixelFormat();
655                         tcu::LodPrecision                       lodPrecision;
656                         tcu::TexComparePrecision        texComparePrecision;
657
658                         lodPrecision.derivateBits                       = 10;
659                         lodPrecision.lodBits                            = 5;
660                         texComparePrecision.coordBits           = tcu::IVec3(10,10,10);
661                         texComparePrecision.uvwBits                     = tcu::IVec3(6,6,0);
662                         texComparePrecision.pcfBits                     = 5;
663                         texComparePrecision.referenceBits       = 16;
664                         texComparePrecision.resultBits          = pixelFormat.redBits-1;
665
666                         const bool isHighQuality = verifyTexCompareResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
667                                                                                                                           &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
668
669                         if (!isHighQuality)
670                         {
671                                 m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
672
673                                 lodPrecision.lodBits                    = 4;
674                                 texComparePrecision.uvwBits             = tcu::IVec3(4,4,0);
675                                 texComparePrecision.pcfBits             = 0;
676
677                                 const bool isOk = verifyTexCompareResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
678                                                                                                                  &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
679
680                                 if (!isOk)
681                                 {
682                                         m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
683                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
684                                 }
685                                 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
686                                         m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
687                         }
688                 }
689         }
690
691         m_caseNdx += 1;
692         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
693 }
694
695 class Texture2DArrayShadowCase : public TestCase
696 {
697 public:
698                                                                 Texture2DArrayShadowCase        (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, int numLayers, deUint32 compareFunc);
699                                                                 ~Texture2DArrayShadowCase       (void);
700
701         void                                            init                                            (void);
702         void                                            deinit                                          (void);
703         IterateResult                           iterate                                         (void);
704
705 private:
706                                                                 Texture2DArrayShadowCase        (const Texture2DArrayShadowCase& other);
707         Texture2DArrayShadowCase&       operator=                                       (const Texture2DArrayShadowCase& other);
708
709         const deUint32                          m_minFilter;
710         const deUint32                          m_magFilter;
711         const deUint32                          m_wrapS;
712         const deUint32                          m_wrapT;
713
714         const deUint32                          m_format;
715         const int                                       m_width;
716         const int                                       m_height;
717         const int                                       m_numLayers;
718
719         const deUint32                          m_compareFunc;
720
721         struct FilterCase
722         {
723                 const glu::Texture2DArray*      texture;
724                 tcu::Vec3                                       minCoord;
725                 tcu::Vec3                                       maxCoord;
726                 float                                           ref;
727
728                 FilterCase (void)
729                         : texture       (DE_NULL)
730                         , ref           (0.0f)
731                 {
732                 }
733
734                 FilterCase (const glu::Texture2DArray* tex_, float ref_, const tcu::Vec3& minCoord_, const tcu::Vec3& maxCoord_)
735                         : texture       (tex_)
736                         , minCoord      (minCoord_)
737                         , maxCoord      (maxCoord_)
738                         , ref           (ref_)
739                 {
740                 }
741         };
742
743         glu::Texture2DArray*            m_gradientTex;
744         glu::Texture2DArray*            m_gridTex;
745         std::vector<FilterCase>         m_cases;
746
747         TextureRenderer                         m_renderer;
748
749         int                                                     m_caseNdx;
750 };
751
752 Texture2DArrayShadowCase::Texture2DArrayShadowCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 format, int width, int height, int numLayers, deUint32 compareFunc)
753         : TestCase                      (context, name, desc)
754         , m_minFilter           (minFilter)
755         , m_magFilter           (magFilter)
756         , m_wrapS                       (wrapS)
757         , m_wrapT                       (wrapT)
758         , m_format                      (format)
759         , m_width                       (width)
760         , m_height                      (height)
761         , m_numLayers           (numLayers)
762         , m_compareFunc         (compareFunc)
763         , m_gradientTex         (DE_NULL)
764         , m_gridTex                     (DE_NULL)
765         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
766         , m_caseNdx                     (0)
767 {
768 }
769
770 Texture2DArrayShadowCase::~Texture2DArrayShadowCase (void)
771 {
772         Texture2DArrayShadowCase::deinit();
773 }
774
775 void Texture2DArrayShadowCase::init (void)
776 {
777         try
778         {
779                 tcu::TextureFormat              texFmt          = glu::mapGLInternalFormat(m_format);
780                 tcu::TextureFormatInfo  fmtInfo         = tcu::getTextureFormatInfo(texFmt);
781                 tcu::Vec4                               cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
782                 tcu::Vec4                               cBias           = fmtInfo.valueMin;
783                 int                                             numLevels       = deLog2Floor32(de::max(m_width, m_height)) + 1;
784
785                 // Create textures.
786                 m_gradientTex   = new glu::Texture2DArray(m_context.getRenderContext(), m_format, m_width, m_height, m_numLayers);
787                 m_gridTex               = new glu::Texture2DArray(m_context.getRenderContext(), m_format, m_width, m_height, m_numLayers);
788
789                 // Fill first gradient texture.
790                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
791                 {
792                         tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f)*cScale + cBias;
793                         tcu::Vec4 gMax = tcu::Vec4( 1.0f,  1.0f,  1.0f, 0.0f)*cScale + cBias;
794
795                         m_gradientTex->getRefTexture().allocLevel(levelNdx);
796                         tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax);
797                 }
798
799                 // Fill second with grid texture.
800                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
801                 {
802                         deUint32        step    = 0x00ffffff / numLevels;
803                         deUint32        rgb             = step*levelNdx;
804                         deUint32        colorA  = 0xff000000 | rgb;
805                         deUint32        colorB  = 0xff000000 | ~rgb;
806
807                         m_gridTex->getRefTexture().allocLevel(levelNdx);
808                         tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
809                 }
810
811                 // Upload.
812                 m_gradientTex->upload();
813                 m_gridTex->upload();
814         }
815         catch (...)
816         {
817                 // Clean up to save memory.
818                 Texture2DArrayShadowCase::deinit();
819                 throw;
820         }
821
822         // Compute cases.
823         {
824                 const float refInRangeUpper             = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 1.0f : 0.5f;
825                 const float refInRangeLower             = (m_compareFunc == GL_EQUAL || m_compareFunc == GL_NOTEQUAL) ? 0.0f : 0.5f;
826                 const float refOutOfBoundsUpper = 1.1f;         // !< lookup function should clamp values to [0, 1] range
827                 const float refOutOfBoundsLower = -0.1f;
828
829                 const struct
830                 {
831                         int             texNdx;
832                         float   ref;
833                         float   lodX;
834                         float   lodY;
835                         float   oX;
836                         float   oY;
837                 } cases[] =
838                 {
839                         { 0,    refInRangeUpper,                1.6f,   2.9f,   -1.0f,  -2.7f   },
840                         { 0,    refInRangeLower,                -2.0f,  -1.35f, -0.2f,  0.7f    },
841                         { 1,    refInRangeUpper,                0.14f,  0.275f, -1.5f,  -1.1f   },
842                         { 1,    refInRangeLower,                -0.92f, -2.64f, 0.4f,   -0.1f   },
843                         { 1,    refOutOfBoundsUpper,    -0.49f, -0.22f, 0.45f,  0.97f   },
844                         { 1,    refOutOfBoundsLower,    -0.85f, 0.75f,  0.25f,  0.61f   },
845                 };
846
847                 const float     viewportW       = (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_context.getRenderTarget().getWidth());
848                 const float     viewportH       = (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_context.getRenderTarget().getHeight());
849
850                 const float     minLayer        = -0.5f;
851                 const float     maxLayer        = (float)m_numLayers;
852
853                 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
854                 {
855                         const glu::Texture2DArray*      tex             = cases[caseNdx].texNdx > 0 ? m_gridTex : m_gradientTex;
856                         const float                                     ref             = cases[caseNdx].ref;
857                         const float                                     lodX    = cases[caseNdx].lodX;
858                         const float                                     lodY    = cases[caseNdx].lodY;
859                         const float                                     oX              = cases[caseNdx].oX;
860                         const float                                     oY              = cases[caseNdx].oY;
861                         const float                                     sX              = deFloatExp2(lodX)*viewportW / float(tex->getRefTexture().getWidth());
862                         const float                                     sY              = deFloatExp2(lodY)*viewportH / float(tex->getRefTexture().getHeight());
863
864                         m_cases.push_back(FilterCase(tex, ref, tcu::Vec3(oX, oY, minLayer), tcu::Vec3(oX+sX, oY+sY, maxLayer)));
865                 }
866         }
867
868         m_caseNdx = 0;
869         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
870 }
871
872 void Texture2DArrayShadowCase::deinit (void)
873 {
874         delete m_gradientTex;
875         delete m_gridTex;
876
877         m_gradientTex   = DE_NULL;
878         m_gridTex               = DE_NULL;
879
880         m_renderer.clear();
881         m_cases.clear();
882 }
883
884 Texture2DArrayShadowCase::IterateResult Texture2DArrayShadowCase::iterate (void)
885 {
886         const glw::Functions&                   gl                              = m_context.getRenderContext().getFunctions();
887         const RandomViewport                    viewport                (m_context.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
888         const FilterCase&                               curCase                 = m_cases[m_caseNdx];
889         const tcu::ScopedLogSection             section                 (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
890         ReferenceParams                                 sampleParams    (TEXTURETYPE_2D_ARRAY);
891         tcu::Surface                                    rendered                (viewport.width, viewport.height);
892
893         const float                                             texCoord[]              =
894         {
895                 curCase.minCoord.x(), curCase.minCoord.y(), curCase.minCoord.z(),
896                 curCase.minCoord.x(), curCase.maxCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
897                 curCase.maxCoord.x(), curCase.minCoord.y(), (curCase.minCoord.z() + curCase.maxCoord.z()) / 2.0f,
898                 curCase.maxCoord.x(), curCase.maxCoord.y(), curCase.maxCoord.z()
899         };
900
901         if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
902                 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
903
904         // Setup params for reference.
905         sampleParams.sampler                    = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
906         sampleParams.sampler.compare    = glu::mapGLCompareFunc(m_compareFunc);
907         sampleParams.samplerType                = SAMPLERTYPE_SHADOW;
908         sampleParams.lodMode                    = LODMODE_EXACT;
909         sampleParams.ref                                = curCase.ref;
910
911         m_testCtx.getLog()
912                 << TestLog::Message
913                 << "Compare reference value =  " << sampleParams.ref << "\n"
914                 << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord
915                 << TestLog::EndMessage;
916
917         gl.bindTexture  (GL_TEXTURE_2D_ARRAY, curCase.texture->getGLTexture());
918         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,    m_minFilter);
919         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,    m_magFilter);
920         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S,                m_wrapS);
921         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T,                m_wrapT);
922         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE,  GL_COMPARE_REF_TO_TEXTURE);
923         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC,  m_compareFunc);
924
925         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
926         m_renderer.renderQuad(0, &texCoord[0], sampleParams);
927         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
928
929         {
930                 const tcu::PixelFormat          pixelFormat             = m_context.getRenderTarget().getPixelFormat();
931                 tcu::LodPrecision                       lodPrecision;
932                 tcu::TexComparePrecision        texComparePrecision;
933
934                 lodPrecision.derivateBits                       = 18;
935                 lodPrecision.lodBits                            = 6;
936                 texComparePrecision.coordBits           = tcu::IVec3(20,20,20);
937                 texComparePrecision.uvwBits                     = tcu::IVec3(7,7,7);
938                 texComparePrecision.pcfBits                     = 5;
939                 texComparePrecision.referenceBits       = 16;
940                 texComparePrecision.resultBits          = pixelFormat.redBits-1;
941
942                 const bool isHighQuality = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
943                                                                                                                   &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
944
945                 if (!isHighQuality)
946                 {
947                         m_testCtx.getLog() << TestLog::Message << "Warning: Verification assuming high-quality PCF filtering failed." << TestLog::EndMessage;
948
949                         lodPrecision.lodBits                    = 4;
950                         texComparePrecision.uvwBits             = tcu::IVec3(4,4,4);
951                         texComparePrecision.pcfBits             = 0;
952
953                         const bool isOk = verifyTexCompareResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
954                                                                                                          &texCoord[0], sampleParams, texComparePrecision, lodPrecision, pixelFormat);
955
956                         if (!isOk)
957                         {
958                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
959                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
960                         }
961                         else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
962                                 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality result");
963                 }
964         }
965
966         m_caseNdx += 1;
967         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
968 }
969
970 TextureShadowTests::TextureShadowTests (Context& context)
971         : TestCaseGroup(context, "shadow", "Shadow texture lookup tests")
972 {
973 }
974
975 TextureShadowTests::~TextureShadowTests (void)
976 {
977 }
978
979 void TextureShadowTests::init (void)
980 {
981         static const struct
982         {
983                 const char*             name;
984                 deUint32                format;
985         } formats[] =
986         {
987                 { "depth_component16",  GL_DEPTH_COMPONENT16    },
988                 { "depth_component32f", GL_DEPTH_COMPONENT32F   },
989                 { "depth24_stencil8",   GL_DEPTH24_STENCIL8             }
990         };
991
992         static const struct
993         {
994                 const char*             name;
995                 deUint32                minFilter;
996                 deUint32                magFilter;
997         } filters[] =
998         {
999                 { "nearest",                            GL_NEAREST,                                     GL_NEAREST      },
1000                 { "linear",                                     GL_LINEAR,                                      GL_LINEAR       },
1001                 { "nearest_mipmap_nearest",     GL_NEAREST_MIPMAP_NEAREST,      GL_LINEAR       },
1002                 { "linear_mipmap_nearest",      GL_LINEAR_MIPMAP_NEAREST,       GL_LINEAR       },
1003                 { "nearest_mipmap_linear",      GL_NEAREST_MIPMAP_LINEAR,       GL_LINEAR       },
1004                 { "linear_mipmap_linear",       GL_LINEAR_MIPMAP_LINEAR,        GL_LINEAR       }
1005         };
1006
1007         static const struct
1008         {
1009                 const char*             name;
1010                 deUint32                func;
1011         } compareFuncs[] =
1012         {
1013                 { "less_or_equal",              GL_LEQUAL       },
1014                 { "greater_or_equal",   GL_GEQUAL       },
1015                 { "less",                               GL_LESS         },
1016                 { "greater",                    GL_GREATER      },
1017                 { "equal",                              GL_EQUAL        },
1018                 { "not_equal",                  GL_NOTEQUAL     },
1019                 { "always",                             GL_ALWAYS       },
1020                 { "never",                              GL_NEVER        }
1021         };
1022
1023         // 2D cases.
1024         {
1025                 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D texture shadow lookup tests");
1026                 addChild(group2D);
1027
1028                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1029                 {
1030                         tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1031                         group2D->addChild(filterGroup);
1032
1033                         for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1034                         {
1035                                 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1036                                 {
1037                                         deUint32                minFilter               = filters[filterNdx].minFilter;
1038                                         deUint32                magFilter               = filters[filterNdx].magFilter;
1039                                         deUint32                format                  = formats[formatNdx].format;
1040                                         deUint32                compareFunc             = compareFuncs[compareNdx].func;
1041                                         const deUint32  wrapS                   = GL_REPEAT;
1042                                         const deUint32  wrapT                   = GL_REPEAT;
1043                                         const int               width                   = 32;
1044                                         const int               height                  = 64;
1045                                         string                  name                    = string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1046
1047                                         filterGroup->addChild(new Texture2DShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, width, height, compareFunc));
1048                                 }
1049                         }
1050                 }
1051         }
1052
1053         // Cubemap cases.
1054         {
1055                 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube map texture shadow lookup tests");
1056                 addChild(groupCube);
1057
1058                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1059                 {
1060                         tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1061                         groupCube->addChild(filterGroup);
1062
1063                         for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1064                         {
1065                                 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1066                                 {
1067                                         deUint32                minFilter               = filters[filterNdx].minFilter;
1068                                         deUint32                magFilter               = filters[filterNdx].magFilter;
1069                                         deUint32                format                  = formats[formatNdx].format;
1070                                         deUint32                compareFunc             = compareFuncs[compareNdx].func;
1071                                         const deUint32  wrapS                   = GL_REPEAT;
1072                                         const deUint32  wrapT                   = GL_REPEAT;
1073                                         const int               size                    = 32;
1074                                         string                  name                    = string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1075
1076                                         filterGroup->addChild(new TextureCubeShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, size, compareFunc));
1077                                 }
1078                         }
1079                 }
1080         }
1081
1082         // 2D array cases.
1083         {
1084                 tcu::TestCaseGroup* group2DArray = new tcu::TestCaseGroup(m_testCtx, "2d_array", "2D texture array shadow lookup tests");
1085                 addChild(group2DArray);
1086
1087                 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(filters); filterNdx++)
1088                 {
1089                         tcu::TestCaseGroup* filterGroup = new tcu::TestCaseGroup(m_testCtx, filters[filterNdx].name, "");
1090                         group2DArray->addChild(filterGroup);
1091
1092                         for (int compareNdx = 0; compareNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compareNdx++)
1093                         {
1094                                 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
1095                                 {
1096                                         deUint32                minFilter               = filters[filterNdx].minFilter;
1097                                         deUint32                magFilter               = filters[filterNdx].magFilter;
1098                                         deUint32                format                  = formats[formatNdx].format;
1099                                         deUint32                compareFunc             = compareFuncs[compareNdx].func;
1100                                         const deUint32  wrapS                   = GL_REPEAT;
1101                                         const deUint32  wrapT                   = GL_REPEAT;
1102                                         const int               width                   = 32;
1103                                         const int               height                  = 64;
1104                                         const int               numLayers               = 8;
1105                                         string                  name                    = string(compareFuncs[compareNdx].name) + "_" + formats[formatNdx].name;
1106
1107                                         filterGroup->addChild(new Texture2DArrayShadowCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, width, height, numLayers, compareFunc));
1108                                 }
1109                         }
1110                 }
1111         }
1112 }
1113
1114 } // Functional
1115 } // gles3
1116 } // deqp