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