Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fTextureFilteringTests.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 Texture filtering tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fTextureFilteringTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluTexture.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuImageCompare.hpp"
31 #include "tcuTexLookupVerifier.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "deStringUtil.hpp"
34 #include "deString.h"
35 #include "glwFunctions.hpp"
36 #include "glwEnums.hpp"
37 #include "gluContextInfo.hpp"
38 #include "deUniquePtr.hpp"
39
40 using de::MovePtr;
41 using glu::ContextInfo;
42
43 namespace deqp
44 {
45 namespace gles3
46 {
47 namespace Functional
48 {
49
50 using std::vector;
51 using std::string;
52 using tcu::TestLog;
53 using namespace gls::TextureTestUtil;
54 using namespace glu::TextureTestUtil;
55
56 enum
57 {
58         TEX2D_VIEWPORT_WIDTH            = 64,
59         TEX2D_VIEWPORT_HEIGHT           = 64,
60         TEX2D_MIN_VIEWPORT_WIDTH        = 64,
61         TEX2D_MIN_VIEWPORT_HEIGHT       = 64,
62
63         TEX3D_VIEWPORT_WIDTH            = 64,
64         TEX3D_VIEWPORT_HEIGHT           = 64,
65         TEX3D_MIN_VIEWPORT_WIDTH        = 64,
66         TEX3D_MIN_VIEWPORT_HEIGHT       = 64
67 };
68
69 namespace
70 {
71
72 void checkSupport (const glu::ContextInfo& info, deUint32 internalFormat)
73 {
74         if (internalFormat == GL_SR8_EXT && !info.isExtensionSupported("GL_EXT_texture_sRGB_R8"))
75                 TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_R8 is not supported.");
76
77         if (internalFormat == GL_SRG8_EXT && !info.isExtensionSupported("GL_EXT_texture_sRGB_RG8"))
78                 TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_RG8 is not supported.");
79 }
80
81 } // anonymous
82
83 class Texture2DFilteringCase : public tcu::TestCase
84 {
85 public:
86                                                                         Texture2DFilteringCase          (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height);
87                                                                         Texture2DFilteringCase          (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames);
88                                                                         ~Texture2DFilteringCase         (void);
89
90         void                                                    init                                            (void);
91         void                                                    deinit                                          (void);
92         IterateResult                                   iterate                                         (void);
93
94 private:
95                                                                         Texture2DFilteringCase          (const Texture2DFilteringCase& other);
96         Texture2DFilteringCase&                 operator=                                       (const Texture2DFilteringCase& other);
97
98         glu::RenderContext&                             m_renderCtx;
99         const glu::ContextInfo&                 m_renderCtxInfo;
100
101         const deUint32                                  m_minFilter;
102         const deUint32                                  m_magFilter;
103         const deUint32                                  m_wrapS;
104         const deUint32                                  m_wrapT;
105
106         const deUint32                                  m_internalFormat;
107         const int                                               m_width;
108         const int                                               m_height;
109
110         const std::vector<std::string>  m_filenames;
111
112         struct FilterCase
113         {
114                 const glu::Texture2D*   texture;
115                 tcu::Vec2                               minCoord;
116                 tcu::Vec2                               maxCoord;
117
118                 FilterCase (void)
119                         : texture(DE_NULL)
120                 {
121                 }
122
123                 FilterCase (const glu::Texture2D* tex_, const tcu::Vec2& minCoord_, const tcu::Vec2& maxCoord_)
124                         : texture       (tex_)
125                         , minCoord      (minCoord_)
126                         , maxCoord      (maxCoord_)
127                 {
128                 }
129         };
130
131         std::vector<glu::Texture2D*>    m_textures;
132         std::vector<FilterCase>                 m_cases;
133
134         TextureRenderer                                 m_renderer;
135
136         int                                                             m_caseNdx;
137 };
138
139 Texture2DFilteringCase::Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height)
140         : TestCase                      (testCtx, name, desc)
141         , m_renderCtx           (renderCtx)
142         , m_renderCtxInfo       (ctxInfo)
143         , m_minFilter           (minFilter)
144         , m_magFilter           (magFilter)
145         , m_wrapS                       (wrapS)
146         , m_wrapT                       (wrapT)
147         , m_internalFormat      (internalFormat)
148         , m_width                       (width)
149         , m_height                      (height)
150         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
151         , m_caseNdx                     (0)
152 {
153 }
154
155 Texture2DFilteringCase::Texture2DFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, const std::vector<std::string>& filenames)
156         : TestCase                      (testCtx, name, desc)
157         , m_renderCtx           (renderCtx)
158         , m_renderCtxInfo       (ctxInfo)
159         , m_minFilter           (minFilter)
160         , m_magFilter           (magFilter)
161         , m_wrapS                       (wrapS)
162         , m_wrapT                       (wrapT)
163         , m_internalFormat      (GL_NONE)
164         , m_width                       (0)
165         , m_height                      (0)
166         , m_filenames           (filenames)
167         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
168         , m_caseNdx                     (0)
169 {
170 }
171
172 Texture2DFilteringCase::~Texture2DFilteringCase (void)
173 {
174         deinit();
175 }
176
177 void Texture2DFilteringCase::init (void)
178 {
179         checkSupport(m_renderCtxInfo, m_internalFormat);
180
181         try
182         {
183                 if (!m_filenames.empty())
184                 {
185                         m_textures.reserve(1);
186                         m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size(), m_filenames));
187                 }
188                 else
189                 {
190                         // Create 2 textures.
191                         m_textures.reserve(2);
192                         for (int ndx = 0; ndx < 2; ndx++)
193                                 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_internalFormat, m_width, m_height));
194
195                         const bool                                              mipmaps         = true;
196                         const int                                               numLevels       = mipmaps ? deLog2Floor32(de::max(m_width, m_height))+1 : 1;
197                         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
198                         const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
199                         const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
200
201                         // Fill first gradient texture.
202                         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
203                         {
204                                 tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
205                                 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
206
207                                 m_textures[0]->getRefTexture().allocLevel(levelNdx);
208                                 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
209                         }
210
211                         // Fill second with grid texture.
212                         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
213                         {
214                                 deUint32        step    = 0x00ffffff / numLevels;
215                                 deUint32        rgb             = step*levelNdx;
216                                 deUint32        colorA  = 0xff000000 | rgb;
217                                 deUint32        colorB  = 0xff000000 | ~rgb;
218
219                                 m_textures[1]->getRefTexture().allocLevel(levelNdx);
220                                 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
221                         }
222
223                         // Upload.
224                         for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
225                                 (*i)->upload();
226                 }
227
228                 // Compute cases.
229                 {
230                         const struct
231                         {
232                                 int             texNdx;
233                                 float   lodX;
234                                 float   lodY;
235                                 float   oX;
236                                 float   oY;
237                         } cases[] =
238                         {
239                                 { 0,    1.6f,   2.9f,   -1.0f,  -2.7f   },
240                                 { 0,    -2.0f,  -1.35f, -0.2f,  0.7f    },
241                                 { 1,    0.14f,  0.275f, -1.5f,  -1.1f   },
242                                 { 1,    -0.92f, -2.64f, 0.4f,   -0.1f   },
243                         };
244
245                         const float     viewportW       = (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_renderCtx.getRenderTarget().getWidth());
246                         const float     viewportH       = (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_renderCtx.getRenderTarget().getHeight());
247
248                         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
249                         {
250                                 const int       texNdx  = de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size()-1);
251                                 const float     lodX    = cases[caseNdx].lodX;
252                                 const float     lodY    = cases[caseNdx].lodY;
253                                 const float     oX              = cases[caseNdx].oX;
254                                 const float     oY              = cases[caseNdx].oY;
255                                 const float     sX              = deFloatExp2(lodX)*viewportW / float(m_textures[texNdx]->getRefTexture().getWidth());
256                                 const float     sY              = deFloatExp2(lodY)*viewportH / float(m_textures[texNdx]->getRefTexture().getHeight());
257
258                                 m_cases.push_back(FilterCase(m_textures[texNdx], tcu::Vec2(oX, oY), tcu::Vec2(oX+sX, oY+sY)));
259                         }
260                 }
261
262                 m_caseNdx = 0;
263                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
264         }
265         catch (...)
266         {
267                 // Clean up to save memory.
268                 Texture2DFilteringCase::deinit();
269                 throw;
270         }
271 }
272
273 void Texture2DFilteringCase::deinit (void)
274 {
275         for (std::vector<glu::Texture2D*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
276                 delete *i;
277         m_textures.clear();
278
279         m_renderer.clear();
280         m_cases.clear();
281 }
282
283 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate (void)
284 {
285         const glw::Functions&                   gl                      = m_renderCtx.getFunctions();
286         const RandomViewport                    viewport        (m_renderCtx.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
287         const tcu::TextureFormat                texFmt          = m_textures[0]->getRefTexture().getFormat();
288         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
289         const FilterCase&                               curCase         = m_cases[m_caseNdx];
290         const tcu::ScopedLogSection             section         (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
291         ReferenceParams                                 refParams       (TEXTURETYPE_2D);
292         tcu::Surface                                    rendered        (viewport.width, viewport.height);
293         vector<float>                                   texCoord;
294
295         if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
296                 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
297
298         // Setup params for reference.
299         refParams.sampler               = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
300         refParams.samplerType   = getSamplerType(texFmt);
301         refParams.lodMode               = LODMODE_EXACT;
302         refParams.colorBias             = fmtInfo.lookupBias;
303         refParams.colorScale    = fmtInfo.lookupScale;
304
305         // Compute texture coordinates.
306         m_testCtx.getLog() << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord << TestLog::EndMessage;
307         computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
308
309         gl.bindTexture  (GL_TEXTURE_2D, curCase.texture->getGLTexture());
310         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,  m_minFilter);
311         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,  m_magFilter);
312         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,              m_wrapS);
313         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,              m_wrapT);
314
315         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
316         m_renderer.renderQuad(0, &texCoord[0], refParams);
317         glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess());
318
319         {
320                 const bool                              isNearestOnly   = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
321                 const tcu::PixelFormat  pixelFormat             = m_renderCtx.getRenderTarget().getPixelFormat();
322                 const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
323                 tcu::LodPrecision               lodPrecision;
324                 tcu::LookupPrecision    lookupPrecision;
325
326                 lodPrecision.derivateBits               = 18;
327                 lodPrecision.lodBits                    = 6;
328                 lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
329                 lookupPrecision.coordBits               = tcu::IVec3(20,20,0);
330                 lookupPrecision.uvwBits                 = tcu::IVec3(7,7,0);
331                 lookupPrecision.colorMask               = getCompareMask(pixelFormat);
332
333                 const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
334                                                                                                            &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
335
336                 if (!isHighQuality)
337                 {
338                         // Evaluate against lower precision requirements.
339                         lodPrecision.lodBits    = 4;
340                         lookupPrecision.uvwBits = tcu::IVec3(4,4,0);
341
342                         m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
343
344                         const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
345                                                                                                   &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
346
347                         if (!isOk)
348                         {
349                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
350                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
351                         }
352                         else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
353                                 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
354                 }
355         }
356
357         m_caseNdx += 1;
358         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
359 }
360
361 class TextureCubeFilteringCase : public tcu::TestCase
362 {
363 public:
364                                                                         TextureCubeFilteringCase        (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, deUint32 internalFormat, int width, int height);
365                                                                         TextureCubeFilteringCase        (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, const std::vector<std::string>& filenames);
366                                                                         ~TextureCubeFilteringCase       (void);
367
368         void                                                    init                                            (void);
369         void                                                    deinit                                          (void);
370         IterateResult                                   iterate                                         (void);
371
372 private:
373                                                                         TextureCubeFilteringCase        (const TextureCubeFilteringCase& other);
374         TextureCubeFilteringCase&               operator=                                       (const TextureCubeFilteringCase& other);
375
376         glu::RenderContext&                             m_renderCtx;
377         const glu::ContextInfo&                 m_renderCtxInfo;
378
379         const deUint32                                  m_minFilter;
380         const deUint32                                  m_magFilter;
381         const deUint32                                  m_wrapS;
382         const deUint32                                  m_wrapT;
383         const bool                                              m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
384
385         const deUint32                                  m_internalFormat;
386         const int                                               m_width;
387         const int                                               m_height;
388
389         const std::vector<std::string>  m_filenames;
390
391         struct FilterCase
392         {
393                 const glu::TextureCube* texture;
394                 tcu::Vec2                               bottomLeft;
395                 tcu::Vec2                               topRight;
396
397                 FilterCase (void)
398                         : texture(DE_NULL)
399                 {
400                 }
401
402                 FilterCase (const glu::TextureCube* tex_, const tcu::Vec2& bottomLeft_, const tcu::Vec2& topRight_)
403                         : texture       (tex_)
404                         , bottomLeft(bottomLeft_)
405                         , topRight      (topRight_)
406                 {
407                 }
408         };
409
410         std::vector<glu::TextureCube*>  m_textures;
411         std::vector<FilterCase>                 m_cases;
412
413         TextureRenderer                                 m_renderer;
414
415         int                                                             m_caseNdx;
416 };
417
418 TextureCubeFilteringCase::TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, deUint32 internalFormat, int width, int height)
419         : TestCase                                      (testCtx, name, desc)
420         , m_renderCtx                           (renderCtx)
421         , m_renderCtxInfo                       (ctxInfo)
422         , m_minFilter                           (minFilter)
423         , m_magFilter                           (magFilter)
424         , m_wrapS                                       (wrapS)
425         , m_wrapT                                       (wrapT)
426         , m_onlySampleFaceInterior      (onlySampleFaceInterior)
427         , m_internalFormat                      (internalFormat)
428         , m_width                                       (width)
429         , m_height                                      (height)
430         , m_renderer                            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
431         , m_caseNdx                                     (0)
432 {
433 }
434
435 TextureCubeFilteringCase::TextureCubeFilteringCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, bool onlySampleFaceInterior, const std::vector<std::string>& filenames)
436         : TestCase                                      (testCtx, name, desc)
437         , m_renderCtx                           (renderCtx)
438         , m_renderCtxInfo                       (ctxInfo)
439         , m_minFilter                           (minFilter)
440         , m_magFilter                           (magFilter)
441         , m_wrapS                                       (wrapS)
442         , m_wrapT                                       (wrapT)
443         , m_onlySampleFaceInterior      (onlySampleFaceInterior)
444         , m_internalFormat                      (GL_NONE)
445         , m_width                                       (0)
446         , m_height                                      (0)
447         , m_filenames                           (filenames)
448         , m_renderer                            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
449         , m_caseNdx                                     (0)
450 {
451 }
452
453 TextureCubeFilteringCase::~TextureCubeFilteringCase (void)
454 {
455         deinit();
456 }
457
458 void TextureCubeFilteringCase::init (void)
459 {
460         checkSupport(m_renderCtxInfo, m_internalFormat);
461
462         try
463         {
464                 if (!m_filenames.empty())
465                 {
466                         m_textures.reserve(1);
467                         m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(), (int)m_filenames.size() / 6, m_filenames));
468                 }
469                 else
470                 {
471                         DE_ASSERT(m_width == m_height);
472                         m_textures.reserve(2);
473                         for (int ndx = 0; ndx < 2; ndx++)
474                                 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_internalFormat, m_width));
475
476                         const int                               numLevels       = deLog2Floor32(de::max(m_width, m_height))+1;
477                         tcu::TextureFormatInfo  fmtInfo         = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
478                         tcu::Vec4                               cBias           = fmtInfo.valueMin;
479                         tcu::Vec4                               cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
480
481                         // Fill first with gradient texture.
482                         static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
483                         {
484                                 { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
485                                 { tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
486                                 { tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
487                                 { tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
488                                 { tcu::Vec4(0.0f, 0.0f, 0.0f, 0.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
489                                 { tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
490                         };
491                         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
492                         {
493                                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
494                                 {
495                                         m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
496                                         tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), gradients[face][0]*cScale + cBias, gradients[face][1]*cScale + cBias);
497                                 }
498                         }
499
500                         // Fill second with grid texture.
501                         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
502                         {
503                                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
504                                 {
505                                         deUint32        step    = 0x00ffffff / (numLevels*tcu::CUBEFACE_LAST);
506                                         deUint32        rgb             = step*levelNdx*face;
507                                         deUint32        colorA  = 0xff000000 | rgb;
508                                         deUint32        colorB  = 0xff000000 | ~rgb;
509
510                                         m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
511                                         tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
512                                 }
513                         }
514
515                         // Upload.
516                         for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
517                                 (*i)->upload();
518                 }
519
520                 // Compute cases
521                 {
522                         const glu::TextureCube* tex0    = m_textures[0];
523                         const glu::TextureCube* tex1    = m_textures.size() > 1 ? m_textures[1] : tex0;
524
525                         if (m_onlySampleFaceInterior)
526                         {
527                                 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));   // minification
528                                 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f,  0.8f)));    // magnification
529                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f,  0.8f)));   // minification
530                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f,  0.5f)));             // magnification
531                         }
532                         else
533                         {
534                                 if (m_renderCtx.getRenderTarget().getNumSamples() == 0)
535                                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f)));  // minification
536                                 else
537                                         m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));  // minification - w/ tweak to avoid hitting triangle edges with face switchpoint
538
539                                 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f)));    // magnification
540                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f)));  // minification
541                                 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f)));  // magnification
542                         }
543                 }
544
545                 m_caseNdx = 0;
546                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
547         }
548         catch (...)
549         {
550                 // Clean up to save memory.
551                 TextureCubeFilteringCase::deinit();
552                 throw;
553         }
554 }
555
556 void TextureCubeFilteringCase::deinit (void)
557 {
558         for (std::vector<glu::TextureCube*>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
559                 delete *i;
560         m_textures.clear();
561
562         m_renderer.clear();
563         m_cases.clear();
564 }
565
566 static const char* getFaceDesc (const tcu::CubeFace face)
567 {
568         switch (face)
569         {
570                 case tcu::CUBEFACE_NEGATIVE_X:  return "-X";
571                 case tcu::CUBEFACE_POSITIVE_X:  return "+X";
572                 case tcu::CUBEFACE_NEGATIVE_Y:  return "-Y";
573                 case tcu::CUBEFACE_POSITIVE_Y:  return "+Y";
574                 case tcu::CUBEFACE_NEGATIVE_Z:  return "-Z";
575                 case tcu::CUBEFACE_POSITIVE_Z:  return "+Z";
576                 default:
577                         DE_ASSERT(false);
578                         return DE_NULL;
579         }
580 }
581
582 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate (void)
583 {
584         const glw::Functions&                   gl                              = m_renderCtx.getFunctions();
585         const int                                               viewportSize    = 28;
586         const RandomViewport                    viewport                (m_renderCtx.getRenderTarget(), viewportSize, viewportSize, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
587         const tcu::ScopedLogSection             iterSection             (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
588         const FilterCase&                               curCase                 = m_cases[m_caseNdx];
589         const tcu::TextureFormat&               texFmt                  = curCase.texture->getRefTexture().getFormat();
590         const tcu::TextureFormatInfo    fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
591         ReferenceParams                                 sampleParams    (TEXTURETYPE_CUBE);
592
593         if (viewport.width < viewportSize || viewport.height < viewportSize)
594                 throw tcu::NotSupportedError("Too small render target", DE_NULL, __FILE__, __LINE__);
595
596         // Setup texture
597         gl.bindTexture  (GL_TEXTURE_CUBE_MAP, curCase.texture->getGLTexture());
598         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,    m_minFilter);
599         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,    m_magFilter);
600         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,                m_wrapS);
601         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,                m_wrapT);
602
603         // Other state
604         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
605
606         // Params for reference computation.
607         sampleParams.sampler                                    = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
608         sampleParams.sampler.seamlessCubeMap    = true;
609         sampleParams.samplerType                                = getSamplerType(texFmt);
610         sampleParams.colorBias                                  = fmtInfo.lookupBias;
611         sampleParams.colorScale                                 = fmtInfo.lookupScale;
612         sampleParams.lodMode                                    = LODMODE_EXACT;
613
614         m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight << TestLog::EndMessage;
615
616         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
617         {
618                 const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
619                 tcu::Surface                    result          (viewport.width, viewport.height);
620                 vector<float>                   texCoord;
621
622                 computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
623
624                 m_testCtx.getLog() << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
625
626                 // \todo Log texture coordinates.
627
628                 m_renderer.renderQuad(0, &texCoord[0], sampleParams);
629                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
630
631                 glu::readPixels(m_renderCtx, viewport.x, viewport.y, result.getAccess());
632                 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
633
634                 {
635                         const bool                              isNearestOnly   = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
636                         const tcu::PixelFormat  pixelFormat             = m_renderCtx.getRenderTarget().getPixelFormat();
637                         const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
638                         tcu::LodPrecision               lodPrecision;
639                         tcu::LookupPrecision    lookupPrecision;
640
641                         lodPrecision.derivateBits               = 10;
642                         lodPrecision.lodBits                    = 5;
643                         lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / sampleParams.colorScale;
644                         lookupPrecision.coordBits               = tcu::IVec3(10,10,10);
645                         lookupPrecision.uvwBits                 = tcu::IVec3(6,6,0);
646                         lookupPrecision.colorMask               = getCompareMask(pixelFormat);
647
648                         const bool isHighQuality = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
649                                                                                                                    &texCoord[0], sampleParams, lookupPrecision, lodPrecision, pixelFormat);
650
651                         if (!isHighQuality)
652                         {
653                                 // Evaluate against lower precision requirements.
654                                 lodPrecision.lodBits    = 4;
655                                 lookupPrecision.uvwBits = tcu::IVec3(4,4,0);
656
657                                 m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
658
659                                 const bool isOk = verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(),
660                                                                                                           &texCoord[0], sampleParams, lookupPrecision, lodPrecision, pixelFormat);
661
662                                 if (!isOk)
663                                 {
664                                         m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
665                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
666                                 }
667                                 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
668                                         m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
669                         }
670                 }
671         }
672
673         m_caseNdx += 1;
674         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
675 }
676
677 // 2D array filtering
678
679 class Texture2DArrayFilteringCase : public TestCase
680 {
681 public:
682                                                                         Texture2DArrayFilteringCase             (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height, int numLayers);
683                                                                         ~Texture2DArrayFilteringCase    (void);
684
685         void                                                    init                                                    (void);
686         void                                                    deinit                                                  (void);
687         IterateResult                                   iterate                                                 (void);
688
689 private:
690                                                                         Texture2DArrayFilteringCase             (const Texture2DArrayFilteringCase&);
691         Texture2DArrayFilteringCase&    operator=                                               (const Texture2DArrayFilteringCase&);
692
693         const deUint32                                  m_minFilter;
694         const deUint32                                  m_magFilter;
695         const deUint32                                  m_wrapS;
696         const deUint32                                  m_wrapT;
697
698         const deUint32                                  m_internalFormat;
699         const int                                               m_width;
700         const int                                               m_height;
701         const int                                               m_numLayers;
702
703         struct FilterCase
704         {
705                 const glu::Texture2DArray*      texture;
706                 tcu::Vec2                                       lod;
707                 tcu::Vec2                                       offset;
708                 tcu::Vec2                                       layerRange;
709
710                 FilterCase (void)
711                         : texture(DE_NULL)
712                 {
713                 }
714
715                 FilterCase (const glu::Texture2DArray* tex_, const tcu::Vec2& lod_, const tcu::Vec2& offset_, const tcu::Vec2& layerRange_)
716                         : texture       (tex_)
717                         , lod           (lod_)
718                         , offset        (offset_)
719                         , layerRange(layerRange_)
720                 {
721                 }
722         };
723
724         glu::Texture2DArray*                    m_gradientTex;
725         glu::Texture2DArray*                    m_gridTex;
726
727         TextureRenderer                                 m_renderer;
728
729         std::vector<FilterCase>                 m_cases;
730         int                                                             m_caseNdx;
731 };
732
733 Texture2DArrayFilteringCase::Texture2DArrayFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 internalFormat, int width, int height, int numLayers)
734         : TestCase                      (context, name, desc)
735         , m_minFilter           (minFilter)
736         , m_magFilter           (magFilter)
737         , m_wrapS                       (wrapS)
738         , m_wrapT                       (wrapT)
739         , m_internalFormat      (internalFormat)
740         , m_width                       (width)
741         , m_height                      (height)
742         , m_numLayers           (numLayers)
743         , m_gradientTex         (DE_NULL)
744         , m_gridTex                     (DE_NULL)
745         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
746         , m_caseNdx                     (0)
747 {
748 }
749
750 Texture2DArrayFilteringCase::~Texture2DArrayFilteringCase (void)
751 {
752         Texture2DArrayFilteringCase::deinit();
753 }
754
755 void Texture2DArrayFilteringCase::init (void)
756 {
757         checkSupport(m_context.getContextInfo(), m_internalFormat);
758
759         try
760         {
761                 const tcu::TextureFormat                texFmt          = glu::mapGLInternalFormat(m_internalFormat);
762                 const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
763                 const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
764                 const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
765                 const int                                               numLevels       = deLog2Floor32(de::max(m_width, m_height)) + 1;
766
767                 // Create textures.
768                 m_gradientTex   = new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers);
769                 m_gridTex               = new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers);
770
771                 const tcu::IVec4 levelSwz[] =
772                 {
773                         tcu::IVec4(0,1,2,3),
774                         tcu::IVec4(2,1,3,0),
775                         tcu::IVec4(3,0,1,2),
776                         tcu::IVec4(1,3,2,0),
777                 };
778
779                 // Fill first gradient texture (gradient direction varies between layers).
780                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
781                 {
782                         m_gradientTex->getRefTexture().allocLevel(levelNdx);
783
784                         const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
785
786                         for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++)
787                         {
788                                 const tcu::IVec4        swz             = levelSwz[layerNdx%DE_LENGTH_OF_ARRAY(levelSwz)];
789                                 const tcu::Vec4         gMin    = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
790                                 const tcu::Vec4         gMax    = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0],swz[1],swz[2],swz[3])*cScale + cBias;
791
792                                 tcu::fillWithComponentGradients(tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin, gMax);
793                         }
794                 }
795
796                 // Fill second with grid texture (each layer has unique colors).
797                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
798                 {
799                         m_gridTex->getRefTexture().allocLevel(levelNdx);
800
801                         const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
802
803                         for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++)
804                         {
805                                 const deUint32  step    = 0x00ffffff / (numLevels*m_numLayers - 1);
806                                 const deUint32  rgb             = step * (levelNdx + layerNdx*numLevels);
807                                 const deUint32  colorA  = 0xff000000 | rgb;
808                                 const deUint32  colorB  = 0xff000000 | ~rgb;
809
810                                 tcu::fillWithGrid(tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1),
811                                                                   4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
812                         }
813                 }
814
815                 // Upload.
816                 m_gradientTex->upload();
817                 m_gridTex->upload();
818
819                 // Test cases
820                 m_cases.push_back(FilterCase(m_gradientTex,     tcu::Vec2( 1.5f,  2.8f  ),      tcu::Vec2(-1.0f, -2.7f), tcu::Vec2(-0.5f, float(m_numLayers)+0.5f)));
821                 m_cases.push_back(FilterCase(m_gridTex,         tcu::Vec2( 0.2f,  0.175f),      tcu::Vec2(-2.0f, -3.7f), tcu::Vec2(-0.5f, float(m_numLayers)+0.5f)));
822                 m_cases.push_back(FilterCase(m_gridTex,         tcu::Vec2(-0.8f, -2.3f  ),      tcu::Vec2( 0.2f, -0.1f), tcu::Vec2(float(m_numLayers)+0.5f, -0.5f)));
823
824                 // Level rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
825                 if (m_context.getRenderTarget().getNumSamples() == 0)
826                         m_cases.push_back(FilterCase(m_gradientTex,     tcu::Vec2(-2.0f, -1.5f  ),      tcu::Vec2(-0.1f,  0.9f), tcu::Vec2(1.50001f, 1.49999f)));
827
828                 m_caseNdx = 0;
829                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
830         }
831         catch (...)
832         {
833                 // Clean up to save memory.
834                 Texture2DArrayFilteringCase::deinit();
835                 throw;
836         }
837 }
838
839 void Texture2DArrayFilteringCase::deinit (void)
840 {
841         delete m_gradientTex;
842         delete m_gridTex;
843
844         m_gradientTex   = DE_NULL;
845         m_gridTex               = DE_NULL;
846
847         m_renderer.clear();
848         m_cases.clear();
849 }
850
851 Texture2DArrayFilteringCase::IterateResult Texture2DArrayFilteringCase::iterate (void)
852 {
853         const glw::Functions&                   gl                      = m_context.getRenderContext().getFunctions();
854         const RandomViewport                    viewport        (m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
855         const FilterCase&                               curCase         = m_cases[m_caseNdx];
856         const tcu::TextureFormat                texFmt          = curCase.texture->getRefTexture().getFormat();
857         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
858         const tcu::ScopedLogSection             section         (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
859         ReferenceParams                                 refParams       (TEXTURETYPE_2D_ARRAY);
860         tcu::Surface                                    rendered        (viewport.width, viewport.height);
861         tcu::Vec3                                               texCoord[4];
862
863         if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT)
864                 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
865
866         // Setup params for reference.
867         refParams.sampler               = glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapT, m_minFilter, m_magFilter);
868         refParams.samplerType   = getSamplerType(texFmt);
869         refParams.lodMode               = LODMODE_EXACT;
870         refParams.colorBias             = fmtInfo.lookupBias;
871         refParams.colorScale    = fmtInfo.lookupScale;
872
873         // Compute texture coordinates.
874         m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
875
876         {
877                 const float     lodX    = curCase.lod.x();
878                 const float     lodY    = curCase.lod.y();
879                 const float     oX              = curCase.offset.x();
880                 const float     oY              = curCase.offset.y();
881                 const float     sX              = deFloatExp2(lodX)*float(viewport.width)       / float(m_gradientTex->getRefTexture().getWidth());
882                 const float     sY              = deFloatExp2(lodY)*float(viewport.height)      / float(m_gradientTex->getRefTexture().getHeight());
883                 const float     l0              = curCase.layerRange.x();
884                 const float     l1              = curCase.layerRange.y();
885
886                 texCoord[0] = tcu::Vec3(oX,             oY,             l0);
887                 texCoord[1] = tcu::Vec3(oX,             oY+sY,  l0*0.5f + l1*0.5f);
888                 texCoord[2] = tcu::Vec3(oX+sX,  oY,             l0*0.5f + l1*0.5f);
889                 texCoord[3] = tcu::Vec3(oX+sX,  oY+sY,  l1);
890         }
891
892         gl.bindTexture  (GL_TEXTURE_2D_ARRAY, curCase.texture->getGLTexture());
893         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,    m_minFilter);
894         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,    m_magFilter);
895         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S,                m_wrapS);
896         gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T,                m_wrapT);
897
898         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
899         m_renderer.renderQuad(0, (const float*)&texCoord[0], refParams);
900         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
901
902         {
903                 const bool                              isNearestOnly   = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
904                 const tcu::PixelFormat  pixelFormat             = m_context.getRenderTarget().getPixelFormat();
905                 const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
906                 tcu::LodPrecision               lodPrecision;
907                 tcu::LookupPrecision    lookupPrecision;
908
909                 lodPrecision.derivateBits               = 18;
910                 lodPrecision.lodBits                    = 6;
911                 lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
912                 lookupPrecision.coordBits               = tcu::IVec3(20,20,20);
913                 lookupPrecision.uvwBits                 = tcu::IVec3(7,7,0);
914                 lookupPrecision.colorMask               = getCompareMask(pixelFormat);
915
916                 const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
917                                                                                                            (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
918
919                 if (!isHighQuality)
920                 {
921                         // Evaluate against lower precision requirements.
922                         lodPrecision.lodBits    = 4;
923                         lookupPrecision.uvwBits = tcu::IVec3(4,4,0);
924
925                         m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
926
927                         const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
928                                                                                                   (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
929
930                         if (!isOk)
931                         {
932                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
933                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
934                         }
935                         else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
936                                 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
937                 }
938         }
939
940         m_caseNdx += 1;
941         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
942 }
943
944 // 3D filtering
945
946 class Texture3DFilteringCase : public TestCase
947 {
948 public:
949                                                                         Texture3DFilteringCase          (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 internalFormat, int width, int height, int depth);
950                                                                         ~Texture3DFilteringCase         (void);
951
952         void                                                    init                                            (void);
953         void                                                    deinit                                          (void);
954         IterateResult                                   iterate                                         (void);
955
956 private:
957                                                                         Texture3DFilteringCase          (const Texture3DFilteringCase& other);
958         Texture3DFilteringCase&                 operator=                                       (const Texture3DFilteringCase& other);
959
960         const deUint32                                  m_minFilter;
961         const deUint32                                  m_magFilter;
962         const deUint32                                  m_wrapS;
963         const deUint32                                  m_wrapT;
964         const deUint32                                  m_wrapR;
965
966         const deUint32                                  m_internalFormat;
967         const int                                               m_width;
968         const int                                               m_height;
969         const int                                               m_depth;
970
971         struct FilterCase
972         {
973                 const glu::Texture3D*   texture;
974                 tcu::Vec3                               lod;
975                 tcu::Vec3                               offset;
976
977                 FilterCase (void)
978                         : texture(DE_NULL)
979                 {
980                 }
981
982                 FilterCase (const glu::Texture3D* tex_, const tcu::Vec3& lod_, const tcu::Vec3& offset_)
983                         : texture       (tex_)
984                         , lod           (lod_)
985                         , offset        (offset_)
986                 {
987                 }
988         };
989
990         glu::Texture3D*                                 m_gradientTex;
991         glu::Texture3D*                                 m_gridTex;
992
993         TextureRenderer                                 m_renderer;
994
995         std::vector<FilterCase>                 m_cases;
996         int                                                             m_caseNdx;
997 };
998
999 Texture3DFilteringCase::Texture3DFilteringCase (Context& context, const char* name, const char* desc, deUint32 minFilter, deUint32 magFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 internalFormat, int width, int height, int depth)
1000         : TestCase                      (context, name, desc)
1001         , m_minFilter           (minFilter)
1002         , m_magFilter           (magFilter)
1003         , m_wrapS                       (wrapS)
1004         , m_wrapT                       (wrapT)
1005         , m_wrapR                       (wrapR)
1006         , m_internalFormat      (internalFormat)
1007         , m_width                       (width)
1008         , m_height                      (height)
1009         , m_depth                       (depth)
1010         , m_gradientTex         (DE_NULL)
1011         , m_gridTex                     (DE_NULL)
1012         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1013         , m_caseNdx                     (0)
1014 {
1015 }
1016
1017 Texture3DFilteringCase::~Texture3DFilteringCase (void)
1018 {
1019         Texture3DFilteringCase::deinit();
1020 }
1021
1022 void Texture3DFilteringCase::init (void)
1023 {
1024         checkSupport(m_context.getContextInfo(), m_internalFormat);
1025
1026         try
1027         {
1028                 const tcu::TextureFormat                texFmt          = glu::mapGLInternalFormat(m_internalFormat);
1029                 const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
1030                 const tcu::Vec4                                 cScale          = fmtInfo.valueMax-fmtInfo.valueMin;
1031                 const tcu::Vec4                                 cBias           = fmtInfo.valueMin;
1032                 const int                                               numLevels       = deLog2Floor32(de::max(de::max(m_width, m_height), m_depth)) + 1;
1033
1034                 // Create textures.
1035                 m_gradientTex   = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1036                 m_gridTex               = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1037
1038                 // Fill first gradient texture.
1039                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1040                 {
1041                         tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)*cScale + cBias;
1042                         tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)*cScale + cBias;
1043
1044                         m_gradientTex->getRefTexture().allocLevel(levelNdx);
1045                         tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax);
1046                 }
1047
1048                 // Fill second with grid texture.
1049                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1050                 {
1051                         deUint32        step    = 0x00ffffff / numLevels;
1052                         deUint32        rgb             = step*levelNdx;
1053                         deUint32        colorA  = 0xff000000 | rgb;
1054                         deUint32        colorB  = 0xff000000 | ~rgb;
1055
1056                         m_gridTex->getRefTexture().allocLevel(levelNdx);
1057                         tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4, tcu::RGBA(colorA).toVec()*cScale + cBias, tcu::RGBA(colorB).toVec()*cScale + cBias);
1058                 }
1059
1060                 // Upload.
1061                 m_gradientTex->upload();
1062                 m_gridTex->upload();
1063
1064                 // Test cases
1065                 m_cases.push_back(FilterCase(m_gradientTex,     tcu::Vec3(1.5f, 2.8f, 1.0f),    tcu::Vec3(-1.0f, -2.7f, -2.275f)));
1066                 m_cases.push_back(FilterCase(m_gradientTex,     tcu::Vec3(-2.0f, -1.5f, -1.8f), tcu::Vec3(-0.1f, 0.9f, -0.25f)));
1067                 m_cases.push_back(FilterCase(m_gridTex,         tcu::Vec3(0.2f, 0.175f, 0.3f),  tcu::Vec3(-2.0f, -3.7f, -1.825f)));
1068                 m_cases.push_back(FilterCase(m_gridTex,         tcu::Vec3(-0.8f, -2.3f, -2.5f), tcu::Vec3(0.2f, -0.1f, 1.325f)));
1069
1070                 m_caseNdx = 0;
1071                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1072         }
1073         catch (...)
1074         {
1075                 // Clean up to save memory.
1076                 Texture3DFilteringCase::deinit();
1077                 throw;
1078         }
1079 }
1080
1081 void Texture3DFilteringCase::deinit (void)
1082 {
1083         delete m_gradientTex;
1084         delete m_gridTex;
1085
1086         m_gradientTex   = DE_NULL;
1087         m_gridTex               = DE_NULL;
1088
1089         m_renderer.clear();
1090         m_cases.clear();
1091 }
1092
1093 Texture3DFilteringCase::IterateResult Texture3DFilteringCase::iterate (void)
1094 {
1095         const glw::Functions&                   gl                      = m_context.getRenderContext().getFunctions();
1096         const RandomViewport                    viewport        (m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT, deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
1097         const FilterCase&                               curCase         = m_cases[m_caseNdx];
1098         const tcu::TextureFormat                texFmt          = curCase.texture->getRefTexture().getFormat();
1099         const tcu::TextureFormatInfo    fmtInfo         = tcu::getTextureFormatInfo(texFmt);
1100         const tcu::ScopedLogSection             section         (m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx), string("Test ") + de::toString(m_caseNdx));
1101         ReferenceParams                                 refParams       (TEXTURETYPE_3D);
1102         tcu::Surface                                    rendered        (viewport.width, viewport.height);
1103         tcu::Vec3                                               texCoord[4];
1104
1105         if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT)
1106                 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
1107
1108         // Setup params for reference.
1109         refParams.sampler               = glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, m_magFilter);
1110         refParams.samplerType   = getSamplerType(texFmt);
1111         refParams.lodMode               = LODMODE_EXACT;
1112         refParams.colorBias             = fmtInfo.lookupBias;
1113         refParams.colorScale    = fmtInfo.lookupScale;
1114
1115         // Compute texture coordinates.
1116         m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod << ", offset = " << curCase.offset << TestLog::EndMessage;
1117
1118         {
1119                 const float     lodX    = curCase.lod.x();
1120                 const float     lodY    = curCase.lod.y();
1121                 const float     lodZ    = curCase.lod.z();
1122                 const float     oX              = curCase.offset.x();
1123                 const float     oY              = curCase.offset.y();
1124                 const float oZ          = curCase.offset.z();
1125                 const float     sX              = deFloatExp2(lodX)*float(viewport.width)                                                       / float(m_gradientTex->getRefTexture().getWidth());
1126                 const float     sY              = deFloatExp2(lodY)*float(viewport.height)                                                      / float(m_gradientTex->getRefTexture().getHeight());
1127                 const float     sZ              = deFloatExp2(lodZ)*float(de::max(viewport.width, viewport.height))     / float(m_gradientTex->getRefTexture().getDepth());
1128
1129                 texCoord[0] = tcu::Vec3(oX,             oY,             oZ);
1130                 texCoord[1] = tcu::Vec3(oX,             oY+sY,  oZ + sZ*0.5f);
1131                 texCoord[2] = tcu::Vec3(oX+sX,  oY,             oZ + sZ*0.5f);
1132                 texCoord[3] = tcu::Vec3(oX+sX,  oY+sY,  oZ + sZ);
1133         }
1134
1135         gl.bindTexture  (GL_TEXTURE_3D, curCase.texture->getGLTexture());
1136         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,  m_minFilter);
1137         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,  m_magFilter);
1138         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,              m_wrapS);
1139         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,              m_wrapT);
1140         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,              m_wrapR);
1141
1142         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
1143         m_renderer.renderQuad(0, (const float*)&texCoord[0], refParams);
1144         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
1145
1146         {
1147                 const bool                              isNearestOnly   = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
1148                 const tcu::PixelFormat  pixelFormat             = m_context.getRenderTarget().getPixelFormat();
1149                 const tcu::IVec4                colorBits               = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2), tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
1150                 tcu::LodPrecision               lodPrecision;
1151                 tcu::LookupPrecision    lookupPrecision;
1152
1153                 lodPrecision.derivateBits               = 18;
1154                 lodPrecision.lodBits                    = 6;
1155                 lookupPrecision.colorThreshold  = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
1156                 lookupPrecision.coordBits               = tcu::IVec3(20,20,20);
1157                 lookupPrecision.uvwBits                 = tcu::IVec3(7,7,7);
1158                 lookupPrecision.colorMask               = getCompareMask(pixelFormat);
1159
1160                 const bool isHighQuality = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1161                                                                                                            (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1162
1163                 if (!isHighQuality)
1164                 {
1165                         // Evaluate against lower precision requirements.
1166                         lodPrecision.lodBits    = 4;
1167                         lookupPrecision.uvwBits = tcu::IVec3(4,4,4);
1168
1169                         m_testCtx.getLog() << TestLog::Message << "Warning: Verification against high precision requirements failed, trying with lower requirements." << TestLog::EndMessage;
1170
1171                         const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1172                                                                                                   (const float*)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1173
1174                         if (!isOk)
1175                         {
1176                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Verification against low precision requirements failed, failing test case." << TestLog::EndMessage;
1177                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1178                         }
1179                         else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1180                                 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
1181                 }
1182         }
1183
1184         m_caseNdx += 1;
1185         return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
1186 }
1187
1188 TextureFilteringTests::TextureFilteringTests (Context& context)
1189         : TestCaseGroup(context, "filtering", "Texture Filtering Tests")
1190 {
1191 }
1192
1193 TextureFilteringTests::~TextureFilteringTests (void)
1194 {
1195 }
1196
1197 void TextureFilteringTests::init (void)
1198 {
1199         static const struct
1200         {
1201                 const char*             name;
1202                 deUint32                mode;
1203         } wrapModes[] =
1204         {
1205                 { "clamp",              GL_CLAMP_TO_EDGE },
1206                 { "repeat",             GL_REPEAT },
1207                 { "mirror",             GL_MIRRORED_REPEAT }
1208         };
1209
1210         static const struct
1211         {
1212                 const char*             name;
1213                 deUint32                mode;
1214         } minFilterModes[] =
1215         {
1216                 { "nearest",                            GL_NEAREST                                      },
1217                 { "linear",                                     GL_LINEAR                                       },
1218                 { "nearest_mipmap_nearest",     GL_NEAREST_MIPMAP_NEAREST       },
1219                 { "linear_mipmap_nearest",      GL_LINEAR_MIPMAP_NEAREST        },
1220                 { "nearest_mipmap_linear",      GL_NEAREST_MIPMAP_LINEAR        },
1221                 { "linear_mipmap_linear",       GL_LINEAR_MIPMAP_LINEAR         }
1222         };
1223
1224         static const struct
1225         {
1226                 const char*             name;
1227                 deUint32                mode;
1228         } magFilterModes[] =
1229         {
1230                 { "nearest",    GL_NEAREST },
1231                 { "linear",             GL_LINEAR }
1232         };
1233
1234         static const struct
1235         {
1236                 int width;
1237                 int height;
1238         } sizes2D[] =
1239         {
1240                 {   4,    8 },
1241                 {  32,   64 },
1242                 { 128,  128     },
1243                 {   3,    7 },
1244                 {  31,   55 },
1245                 { 127,   99 }
1246         };
1247
1248         static const struct
1249         {
1250                 int width;
1251                 int height;
1252         } sizesCube[] =
1253         {
1254                 {   8,   8 },
1255                 {  64,  64 },
1256                 { 128, 128 },
1257                 {   7,   7 },
1258                 {  63,  63 }
1259         };
1260
1261         static const struct
1262         {
1263                 int width;
1264                 int height;
1265                 int numLayers;
1266         } sizes2DArray[] =
1267         {
1268                 {   4,   8,   8 },
1269                 {  32,  64,  16 },
1270                 { 128,  32,  64 },
1271                 {   3,   7,   5 },
1272                 {  63,  63,  63 }
1273         };
1274
1275         static const struct
1276         {
1277                 int width;
1278                 int height;
1279                 int depth;
1280         } sizes3D[] =
1281         {
1282                 {   4,   8,   8 },
1283                 {  32,  64,  16 },
1284                 { 128,  32,  64 },
1285                 {   3,   7,   5 },
1286                 {  63,  63,  63 }
1287         };
1288
1289         static const struct
1290         {
1291                 const char*             name;
1292                 deUint32                format;
1293         } filterableFormatsByType[] =
1294         {
1295                 { "rgba16f",            GL_RGBA16F                      },
1296                 { "r11f_g11f_b10f",     GL_R11F_G11F_B10F       },
1297                 { "rgb9_e5",            GL_RGB9_E5                      },
1298                 { "rgba8",                      GL_RGBA8                        },
1299                 { "rgba8_snorm",        GL_RGBA8_SNORM          },
1300                 { "rgb565",                     GL_RGB565                       },
1301                 { "rgba4",                      GL_RGBA4                        },
1302                 { "rgb5_a1",            GL_RGB5_A1                      },
1303                 { "srgb8_alpha8",       GL_SRGB8_ALPHA8         },
1304                 { "srgb_r8",            GL_SR8_EXT                      },
1305                 { "srgb_rg8",           GL_SRG8_EXT                     },
1306                 { "rgb10_a2",           GL_RGB10_A2                     }
1307         };
1308
1309         // 2D texture filtering.
1310         {
1311                 tcu::TestCaseGroup* group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering");
1312                 addChild(group2D);
1313
1314                 // Formats.
1315                 tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats");
1316                 group2D->addChild(formatsGroup);
1317                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1318                 {
1319                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1320                         {
1321                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1322                                 const char*             filterName      = minFilterModes[filterNdx].name;
1323                                 deUint32                format          = filterableFormatsByType[fmtNdx].format;
1324                                 const char*             formatName      = filterableFormatsByType[fmtNdx].name;
1325                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1326                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1327                                 string                  name            = string(formatName) + "_" + filterName;
1328                                 deUint32                wrapS           = GL_REPEAT;
1329                                 deUint32                wrapT           = GL_REPEAT;
1330                                 int                             width           = 64;
1331                                 int                             height          = 64;
1332
1333                                 formatsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1334                                                                                                                                   name.c_str(), "",
1335                                                                                                                                   minFilter, magFilter,
1336                                                                                                                                   wrapS, wrapT,
1337                                                                                                                                   format,
1338                                                                                                                                   width, height));
1339                         }
1340                 }
1341
1342                 // ETC1 format.
1343                 {
1344                         std::vector<std::string> filenames;
1345                         for (int i = 0; i <= 7; i++)
1346                                 filenames.push_back(string("data/etc1/photo_helsinki_mip_") + de::toString(i) + ".pkm");
1347
1348                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1349                         {
1350                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1351                                 const char*             filterName      = minFilterModes[filterNdx].name;
1352                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1353                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1354                                 string                  name            = string("etc1_rgb8_") + filterName;
1355                                 deUint32                wrapS           = GL_REPEAT;
1356                                 deUint32                wrapT           = GL_REPEAT;
1357
1358                                 formatsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1359                                                                                                                                   name.c_str(), "",
1360                                                                                                                                   minFilter, magFilter,
1361                                                                                                                                   wrapS, wrapT,
1362                                                                                                                                   filenames));
1363                         }
1364                 }
1365
1366                 // Sizes.
1367                 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1368                 group2D->addChild(sizesGroup);
1369                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
1370                 {
1371                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1372                         {
1373                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1374                                 const char*             filterName      = minFilterModes[filterNdx].name;
1375                                 deUint32                format          = GL_RGBA8;
1376                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1377                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1378                                 deUint32                wrapS           = GL_REPEAT;
1379                                 deUint32                wrapT           = GL_REPEAT;
1380                                 int                             width           = sizes2D[sizeNdx].width;
1381                                 int                             height          = sizes2D[sizeNdx].height;
1382                                 string                  name            = de::toString(width) + "x" + de::toString(height) + "_" + filterName;
1383
1384                                 sizesGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1385                                                                                                                                 name.c_str(), "",
1386                                                                                                                                 minFilter, magFilter,
1387                                                                                                                                 wrapS, wrapT,
1388                                                                                                                                 format,
1389                                                                                                                                 width, height));
1390                         }
1391                 }
1392
1393                 // Wrap modes.
1394                 tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1395                 group2D->addChild(combinationsGroup);
1396                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1397                 {
1398                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1399                         {
1400                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1401                                 {
1402                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1403                                         {
1404                                                 deUint32                minFilter       = minFilterModes[minFilterNdx].mode;
1405                                                 deUint32                magFilter       = magFilterModes[magFilterNdx].mode;
1406                                                 deUint32                format          = GL_RGBA8;
1407                                                 deUint32                wrapS           = wrapModes[wrapSNdx].mode;
1408                                                 deUint32                wrapT           = wrapModes[wrapTNdx].mode;
1409                                                 int                             width           = 63;
1410                                                 int                             height          = 57;
1411                                                 string                  name            = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1412
1413                                                 combinationsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1414                                                                                                                                                            name.c_str(), "",
1415                                                                                                                                                            minFilter, magFilter,
1416                                                                                                                                                            wrapS, wrapT,
1417                                                                                                                                                            format,
1418                                                                                                                                                            width, height));
1419                                         }
1420                                 }
1421                         }
1422                 }
1423         }
1424
1425         // Cube map texture filtering.
1426         {
1427                 tcu::TestCaseGroup* groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Texture Filtering");
1428                 addChild(groupCube);
1429
1430                 // Formats.
1431                 tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats");
1432                 groupCube->addChild(formatsGroup);
1433                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1434                 {
1435                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1436                         {
1437                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1438                                 const char*             filterName      = minFilterModes[filterNdx].name;
1439                                 deUint32                format          = filterableFormatsByType[fmtNdx].format;
1440                                 const char*             formatName      = filterableFormatsByType[fmtNdx].name;
1441                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1442                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1443                                 string                  name            = string(formatName) + "_" + filterName;
1444                                 deUint32                wrapS           = GL_REPEAT;
1445                                 deUint32                wrapT           = GL_REPEAT;
1446                                 int                             width           = 64;
1447                                 int                             height          = 64;
1448
1449                                 formatsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1450                                                                                                                                         name.c_str(), "",
1451                                                                                                                                         minFilter, magFilter,
1452                                                                                                                                         wrapS, wrapT,
1453                                                                                                                                         false /* always sample exterior as well */,
1454                                                                                                                                         format,
1455                                                                                                                                         width, height));
1456                         }
1457                 }
1458
1459                 // ETC1 format.
1460                 {
1461                         static const char* faceExt[] = { "neg_x", "pos_x", "neg_y", "pos_y", "neg_z", "pos_z" };
1462
1463                         const int               numLevels       = 7;
1464                         vector<string>  filenames;
1465                         for (int level = 0; level < numLevels; level++)
1466                                 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1467                                         filenames.push_back(string("data/etc1/skybox_") + faceExt[face] + "_mip_" + de::toString(level) + ".pkm");
1468
1469                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1470                         {
1471                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1472                                 const char*             filterName      = minFilterModes[filterNdx].name;
1473                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1474                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1475                                 string                  name            = string("etc1_rgb8_") + filterName;
1476                                 deUint32                wrapS           = GL_REPEAT;
1477                                 deUint32                wrapT           = GL_REPEAT;
1478
1479                                 formatsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1480                                                                                                                                         name.c_str(), "",
1481                                                                                                                                         minFilter, magFilter,
1482                                                                                                                                         wrapS, wrapT,
1483                                                                                                                                         false /* always sample exterior as well */,
1484                                                                                                                                         filenames));
1485                         }
1486                 }
1487
1488                 // Sizes.
1489                 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1490                 groupCube->addChild(sizesGroup);
1491                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++)
1492                 {
1493                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1494                         {
1495                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1496                                 const char*             filterName      = minFilterModes[filterNdx].name;
1497                                 deUint32                format          = GL_RGBA8;
1498                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1499                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1500                                 deUint32                wrapS           = GL_REPEAT;
1501                                 deUint32                wrapT           = GL_REPEAT;
1502                                 int                             width           = sizesCube[sizeNdx].width;
1503                                 int                             height          = sizesCube[sizeNdx].height;
1504                                 string                  name            = de::toString(width) + "x" + de::toString(height) + "_" + filterName;
1505
1506                                 sizesGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1507                                                                                                                                   name.c_str(), "",
1508                                                                                                                                   minFilter, magFilter,
1509                                                                                                                                   wrapS, wrapT,
1510                                                                                                                                   false,
1511                                                                                                                                   format,
1512                                                                                                                                   width, height));
1513                         }
1514                 }
1515
1516                 // Filter/wrap mode combinations.
1517                 tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1518                 groupCube->addChild(combinationsGroup);
1519                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1520                 {
1521                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1522                         {
1523                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1524                                 {
1525                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1526                                         {
1527                                                 deUint32                minFilter       = minFilterModes[minFilterNdx].mode;
1528                                                 deUint32                magFilter       = magFilterModes[magFilterNdx].mode;
1529                                                 deUint32                format          = GL_RGBA8;
1530                                                 deUint32                wrapS           = wrapModes[wrapSNdx].mode;
1531                                                 deUint32                wrapT           = wrapModes[wrapTNdx].mode;
1532                                                 int                             width           = 63;
1533                                                 int                             height          = 63;
1534                                                 string                  name            = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1535
1536                                                 combinationsGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1537                                                                                                                                                                  name.c_str(), "",
1538                                                                                                                                                                  minFilter, magFilter,
1539                                                                                                                                                                  wrapS, wrapT,
1540                                                                                                                                                                  false,
1541                                                                                                                                                                  format,
1542                                                                                                                                                                  width, height));
1543                                         }
1544                                 }
1545                         }
1546                 }
1547
1548                 // Cases with no visible cube edges.
1549                 tcu::TestCaseGroup* onlyFaceInteriorGroup = new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
1550                 groupCube->addChild(onlyFaceInteriorGroup);
1551
1552                 for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
1553                 {
1554                         bool            isLinear        = isLinearI != 0;
1555                         deUint32        filter          = isLinear ? GL_LINEAR : GL_NEAREST;
1556
1557                         onlyFaceInteriorGroup->addChild(new TextureCubeFilteringCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1558                                                                                                                                                  isLinear ? "linear" : "nearest", "",
1559                                                                                                                                                  filter, filter,
1560                                                                                                                                                  GL_REPEAT, GL_REPEAT,
1561                                                                                                                                                  true,
1562                                                                                                                                                  GL_RGBA8,
1563                                                                                                                                                  63, 63));
1564                 }
1565         }
1566
1567         // 2D array texture filtering.
1568         {
1569                 tcu::TestCaseGroup* const group2DArray = new tcu::TestCaseGroup(m_testCtx, "2d_array", "2D Array Texture Filtering");
1570                 addChild(group2DArray);
1571
1572                 // Formats.
1573                 tcu::TestCaseGroup* const formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Array Texture Formats");
1574                 group2DArray->addChild(formatsGroup);
1575                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1576                 {
1577                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1578                         {
1579                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1580                                 const char*             filterName      = minFilterModes[filterNdx].name;
1581                                 deUint32                format          = filterableFormatsByType[fmtNdx].format;
1582                                 const char*             formatName      = filterableFormatsByType[fmtNdx].name;
1583                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1584                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1585                                 string                  name            = string(formatName) + "_" + filterName;
1586                                 deUint32                wrapS           = GL_REPEAT;
1587                                 deUint32                wrapT           = GL_REPEAT;
1588                                 int                             width           = 128;
1589                                 int                             height          = 128;
1590                                 int                             numLayers       = 8;
1591
1592                                 formatsGroup->addChild(new Texture2DArrayFilteringCase(m_context,
1593                                                                                                                                            name.c_str(), "",
1594                                                                                                                                            minFilter, magFilter,
1595                                                                                                                                            wrapS, wrapT,
1596                                                                                                                                            format,
1597                                                                                                                                            width, height, numLayers));
1598                         }
1599                 }
1600
1601                 // Sizes.
1602                 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1603                 group2DArray->addChild(sizesGroup);
1604                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2DArray); sizeNdx++)
1605                 {
1606                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1607                         {
1608                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1609                                 const char*             filterName      = minFilterModes[filterNdx].name;
1610                                 deUint32                format          = GL_RGBA8;
1611                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1612                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1613                                 deUint32                wrapS           = GL_REPEAT;
1614                                 deUint32                wrapT           = GL_REPEAT;
1615                                 int                             width           = sizes2DArray[sizeNdx].width;
1616                                 int                             height          = sizes2DArray[sizeNdx].height;
1617                                 int                             numLayers       = sizes2DArray[sizeNdx].numLayers;
1618                                 string                  name            = de::toString(width) + "x" + de::toString(height) + "x" + de::toString(numLayers) + "_" + filterName;
1619
1620                                 sizesGroup->addChild(new Texture2DArrayFilteringCase(m_context,
1621                                                                                                                                          name.c_str(), "",
1622                                                                                                                                          minFilter, magFilter,
1623                                                                                                                                          wrapS, wrapT,
1624                                                                                                                                          format,
1625                                                                                                                                          width, height, numLayers));
1626                         }
1627                 }
1628
1629                 // Wrap modes.
1630                 tcu::TestCaseGroup* const combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1631                 group2DArray->addChild(combinationsGroup);
1632                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1633                 {
1634                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1635                         {
1636                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1637                                 {
1638                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1639                                         {
1640                                                 deUint32                minFilter       = minFilterModes[minFilterNdx].mode;
1641                                                 deUint32                magFilter       = magFilterModes[magFilterNdx].mode;
1642                                                 deUint32                format          = GL_RGBA8;
1643                                                 deUint32                wrapS           = wrapModes[wrapSNdx].mode;
1644                                                 deUint32                wrapT           = wrapModes[wrapTNdx].mode;
1645                                                 int                             width           = 123;
1646                                                 int                             height          = 107;
1647                                                 int                             numLayers       = 7;
1648                                                 string                  name            = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name;
1649
1650                                                 combinationsGroup->addChild(new Texture2DArrayFilteringCase(m_context,
1651                                                                                                                                                                         name.c_str(), "",
1652                                                                                                                                                                         minFilter, magFilter,
1653                                                                                                                                                                         wrapS, wrapT,
1654                                                                                                                                                                         format,
1655                                                                                                                                                                         width, height, numLayers));
1656                                         }
1657                                 }
1658                         }
1659                 }
1660         }
1661
1662         // 3D texture filtering.
1663         {
1664                 tcu::TestCaseGroup* group3D = new tcu::TestCaseGroup(m_testCtx, "3d", "3D Texture Filtering");
1665                 addChild(group3D);
1666
1667                 // Formats.
1668                 tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "3D Texture Formats");
1669                 group3D->addChild(formatsGroup);
1670                 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1671                 {
1672                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1673                         {
1674                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1675                                 const char*             filterName      = minFilterModes[filterNdx].name;
1676                                 deUint32                format          = filterableFormatsByType[fmtNdx].format;
1677                                 const char*             formatName      = filterableFormatsByType[fmtNdx].name;
1678                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1679                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1680                                 string                  name            = string(formatName) + "_" + filterName;
1681                                 deUint32                wrapS           = GL_REPEAT;
1682                                 deUint32                wrapT           = GL_REPEAT;
1683                                 deUint32                wrapR           = GL_REPEAT;
1684                                 int                             width           = 64;
1685                                 int                             height          = 64;
1686                                 int                             depth           = 64;
1687
1688                                 formatsGroup->addChild(new Texture3DFilteringCase(m_context,
1689                                                                                                                                   name.c_str(), "",
1690                                                                                                                                   minFilter, magFilter,
1691                                                                                                                                   wrapS, wrapT, wrapR,
1692                                                                                                                                   format,
1693                                                                                                                                   width, height, depth));
1694                         }
1695                 }
1696
1697                 // Sizes.
1698                 tcu::TestCaseGroup* sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1699                 group3D->addChild(sizesGroup);
1700                 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes3D); sizeNdx++)
1701                 {
1702                         for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1703                         {
1704                                 deUint32                minFilter       = minFilterModes[filterNdx].mode;
1705                                 const char*             filterName      = minFilterModes[filterNdx].name;
1706                                 deUint32                format          = GL_RGBA8;
1707                                 bool                    isMipmap        = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1708                                 deUint32                magFilter       = isMipmap ? GL_LINEAR : minFilter;
1709                                 deUint32                wrapS           = GL_REPEAT;
1710                                 deUint32                wrapT           = GL_REPEAT;
1711                                 deUint32                wrapR           = GL_REPEAT;
1712                                 int                             width           = sizes3D[sizeNdx].width;
1713                                 int                             height          = sizes3D[sizeNdx].height;
1714                                 int                             depth           = sizes3D[sizeNdx].depth;
1715                                 string                  name            = de::toString(width) + "x" + de::toString(height) + "x" + de::toString(depth) + "_" + filterName;
1716
1717                                 sizesGroup->addChild(new Texture3DFilteringCase(m_context,
1718                                                                                                                                 name.c_str(), "",
1719                                                                                                                                 minFilter, magFilter,
1720                                                                                                                                 wrapS, wrapT, wrapR,
1721                                                                                                                                 format,
1722                                                                                                                                 width, height, depth));
1723                         }
1724                 }
1725
1726                 // Wrap modes.
1727                 tcu::TestCaseGroup* combinationsGroup = new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1728                 group3D->addChild(combinationsGroup);
1729                 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1730                 {
1731                         for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1732                         {
1733                                 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1734                                 {
1735                                         for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1736                                         {
1737                                                 for (int wrapRNdx = 0; wrapRNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapRNdx++)
1738                                                 {
1739                                                         deUint32                minFilter       = minFilterModes[minFilterNdx].mode;
1740                                                         deUint32                magFilter       = magFilterModes[magFilterNdx].mode;
1741                                                         deUint32                format          = GL_RGBA8;
1742                                                         deUint32                wrapS           = wrapModes[wrapSNdx].mode;
1743                                                         deUint32                wrapT           = wrapModes[wrapTNdx].mode;
1744                                                         deUint32                wrapR           = wrapModes[wrapRNdx].mode;
1745                                                         int                             width           = 63;
1746                                                         int                             height          = 57;
1747                                                         int                             depth           = 67;
1748                                                         string                  name            = string(minFilterModes[minFilterNdx].name) + "_" + magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" + wrapModes[wrapTNdx].name + "_" + wrapModes[wrapRNdx].name;
1749
1750                                                         combinationsGroup->addChild(new Texture3DFilteringCase(m_context,
1751                                                                                                                                                                    name.c_str(), "",
1752                                                                                                                                                                    minFilter, magFilter,
1753                                                                                                                                                                    wrapS, wrapT, wrapR,
1754                                                                                                                                                                    format,
1755                                                                                                                                                                    width, height, depth));
1756                                                 }
1757                                         }
1758                                 }
1759                         }
1760                 }
1761         }
1762 }
1763
1764 } // Functional
1765 } // gles3
1766 } // deqp