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