xref: /aosp_15_r20/external/deqp/modules/gles3/accuracy/es3aTextureFilteringTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 accuracy tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3aTextureFilteringTests.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 "deStringUtil.hpp"
32 #include "deString.h"
33 
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
36 
37 namespace deqp
38 {
39 namespace gles3
40 {
41 namespace Accuracy
42 {
43 
44 using std::string;
45 using std::vector;
46 using tcu::TestLog;
47 using namespace gls::TextureTestUtil;
48 using namespace glu::TextureTestUtil;
49 
50 class Texture2DFilteringCase : public tcu::TestCase
51 {
52 public:
53     Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
54                            const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
55                            uint32_t wrapT, uint32_t internalFormat, int width, int height);
56     Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
57                            const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
58                            uint32_t wrapT, const std::vector<std::string> &filenames);
59     ~Texture2DFilteringCase(void);
60 
61     void init(void);
62     void deinit(void);
63     IterateResult iterate(void);
64 
65 private:
66     Texture2DFilteringCase(const Texture2DFilteringCase &other);
67     Texture2DFilteringCase &operator=(const Texture2DFilteringCase &other);
68 
69     glu::RenderContext &m_renderCtx;
70     const glu::ContextInfo &m_renderCtxInfo;
71 
72     uint32_t m_minFilter;
73     uint32_t m_magFilter;
74     uint32_t m_wrapS;
75     uint32_t m_wrapT;
76 
77     uint32_t m_internalFormat;
78     int m_width;
79     int m_height;
80 
81     std::vector<std::string> m_filenames;
82 
83     std::vector<glu::Texture2D *> m_textures;
84     TextureRenderer m_renderer;
85 };
86 
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)87 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
88                                                const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
89                                                uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
90                                                uint32_t internalFormat, int width, int height)
91     : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
92     , m_renderCtx(renderCtx)
93     , m_renderCtxInfo(ctxInfo)
94     , m_minFilter(minFilter)
95     , m_magFilter(magFilter)
96     , m_wrapS(wrapS)
97     , m_wrapT(wrapT)
98     , m_internalFormat(internalFormat)
99     , m_width(width)
100     , m_height(height)
101     , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
102 {
103 }
104 
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)105 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
106                                                const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
107                                                uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
108                                                const std::vector<std::string> &filenames)
109     : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
110     , m_renderCtx(renderCtx)
111     , m_renderCtxInfo(ctxInfo)
112     , m_minFilter(minFilter)
113     , m_magFilter(magFilter)
114     , m_wrapS(wrapS)
115     , m_wrapT(wrapT)
116     , m_internalFormat(GL_NONE)
117     , m_width(0)
118     , m_height(0)
119     , m_filenames(filenames)
120     , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_HIGHP)
121 {
122 }
123 
~Texture2DFilteringCase(void)124 Texture2DFilteringCase::~Texture2DFilteringCase(void)
125 {
126     deinit();
127 }
128 
init(void)129 void Texture2DFilteringCase::init(void)
130 {
131     try
132     {
133         if (!m_filenames.empty())
134         {
135             m_textures.reserve(1);
136             m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
137                                                         (int)m_filenames.size(), m_filenames));
138         }
139         else
140         {
141             // Create 2 textures.
142             m_textures.reserve(2);
143             for (int ndx = 0; ndx < 2; ndx++)
144                 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_internalFormat, m_width, m_height));
145 
146             const int numLevels            = deLog2Floor32(de::max(m_width, m_height)) + 1;
147             tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
148             tcu::Vec4 cBias                = fmtInfo.valueMin;
149             tcu::Vec4 cScale               = fmtInfo.valueMax - fmtInfo.valueMin;
150 
151             // Fill first gradient texture.
152             for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
153             {
154                 tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f) * cScale + cBias;
155                 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
156 
157                 m_textures[0]->getRefTexture().allocLevel(levelNdx);
158                 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
159             }
160 
161             // Fill second with grid texture.
162             for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
163             {
164                 uint32_t step   = 0x00ffffff / numLevels;
165                 uint32_t rgb    = step * levelNdx;
166                 uint32_t colorA = 0xff000000 | rgb;
167                 uint32_t colorB = 0xff000000 | ~rgb;
168 
169                 m_textures[1]->getRefTexture().allocLevel(levelNdx);
170                 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4,
171                                   tcu::RGBA(colorA).toVec() * cScale + cBias,
172                                   tcu::RGBA(colorB).toVec() * cScale + cBias);
173             }
174 
175             // Upload.
176             for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
177                 (*i)->upload();
178         }
179     }
180     catch (...)
181     {
182         // Clean up to save memory.
183         Texture2DFilteringCase::deinit();
184         throw;
185     }
186 }
187 
deinit(void)188 void Texture2DFilteringCase::deinit(void)
189 {
190     for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
191         delete *i;
192     m_textures.clear();
193 
194     m_renderer.clear();
195 }
196 
iterate(void)197 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate(void)
198 {
199     const glw::Functions &gl    = m_renderCtx.getFunctions();
200     TestLog &log                = m_testCtx.getLog();
201     const int defViewportWidth  = 256;
202     const int defViewportHeight = 256;
203     RandomViewport viewport(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight,
204                             deStringHash(getName()));
205     tcu::Surface renderedFrame(viewport.width, viewport.height);
206     tcu::Surface referenceFrame(viewport.width, viewport.height);
207     const tcu::TextureFormat &texFmt = m_textures[0]->getRefTexture().getFormat();
208     tcu::TextureFormatInfo fmtInfo   = tcu::getTextureFormatInfo(texFmt);
209     ReferenceParams refParams(TEXTURETYPE_2D);
210     vector<float> texCoord;
211 
212     // Accuracy measurements are off unless viewport size is 256x256
213     if (viewport.width < defViewportWidth || viewport.height < defViewportHeight)
214         throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
215 
216     // Viewport is divided into 4 sections.
217     int leftWidth    = viewport.width / 2;
218     int rightWidth   = viewport.width - leftWidth;
219     int bottomHeight = viewport.height / 2;
220     int topHeight    = viewport.height - bottomHeight;
221 
222     int curTexNdx = 0;
223 
224     // Use unit 0.
225     gl.activeTexture(GL_TEXTURE0);
226 
227     // Bind gradient texture and setup sampler parameters.
228     gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
229     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
230     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
231     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
232     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
233 
234     // Setup params for reference.
235     refParams.sampler     = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
236     refParams.samplerType = getSamplerType(texFmt);
237     refParams.lodMode     = LODMODE_EXACT;
238     refParams.colorBias   = fmtInfo.lookupBias;
239     refParams.colorScale  = fmtInfo.lookupScale;
240 
241     // Bottom left: Minification
242     {
243         gl.viewport(viewport.x, viewport.y, leftWidth, bottomHeight);
244 
245         computeQuadTexCoord2D(texCoord, tcu::Vec2(-4.0f, -4.5f), tcu::Vec2(4.0f, 2.5f));
246 
247         m_renderer.renderQuad(0, &texCoord[0], refParams);
248         sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0,
249                                          leftWidth, bottomHeight),
250                       m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
251     }
252 
253     // Bottom right: Magnification
254     {
255         gl.viewport(viewport.x + leftWidth, viewport.y, rightWidth, bottomHeight);
256 
257         computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
258 
259         m_renderer.renderQuad(0, &texCoord[0], refParams);
260         sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0,
261                                          rightWidth, bottomHeight),
262                       m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
263     }
264 
265     if (m_textures.size() >= 2)
266     {
267         curTexNdx += 1;
268 
269         // Setup second texture.
270         gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
271         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
272         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
273         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
274         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
275     }
276 
277     // Top left: Minification
278     // \note Minification is chosen so that 0.0 < lod <= 0.5. This way special minification threshold rule will be triggered.
279     {
280         gl.viewport(viewport.x, viewport.y + bottomHeight, leftWidth, topHeight);
281 
282         float sMin   = -0.5f;
283         float tMin   = -0.2f;
284         float sRange = ((float)leftWidth * 1.2f) / (float)m_textures[curTexNdx]->getRefTexture().getWidth();
285         float tRange = ((float)topHeight * 1.1f) / (float)m_textures[curTexNdx]->getRefTexture().getHeight();
286 
287         computeQuadTexCoord2D(texCoord, tcu::Vec2(sMin, tMin), tcu::Vec2(sMin + sRange, tMin + tRange));
288 
289         m_renderer.renderQuad(0, &texCoord[0], refParams);
290         sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0,
291                                          bottomHeight, leftWidth, topHeight),
292                       m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
293     }
294 
295     // Top right: Magnification
296     {
297         gl.viewport(viewport.x + leftWidth, viewport.y + bottomHeight, rightWidth, topHeight);
298 
299         computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
300 
301         m_renderer.renderQuad(0, &texCoord[0], refParams);
302         sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth,
303                                          bottomHeight, rightWidth, topHeight),
304                       m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
305     }
306 
307     // Read result.
308     glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
309 
310     // Compare and log.
311     {
312         const int bestScoreDiff  = 16;
313         const int worstScoreDiff = 3200;
314 
315         int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
316         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
317     }
318 
319     return STOP;
320 }
321 
322 class TextureCubeFilteringCase : public tcu::TestCase
323 {
324 public:
325     TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
326                              const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
327                              uint32_t wrapT, bool onlySampleFaceInterior, uint32_t internalFormat, int width,
328                              int height);
329     TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
330                              const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
331                              uint32_t wrapT, bool onlySampleFaceInterior, const std::vector<std::string> &filenames);
332     ~TextureCubeFilteringCase(void);
333 
334     void init(void);
335     void deinit(void);
336     IterateResult iterate(void);
337 
338 private:
339     TextureCubeFilteringCase(const TextureCubeFilteringCase &other);
340     TextureCubeFilteringCase &operator=(const TextureCubeFilteringCase &other);
341 
342     glu::RenderContext &m_renderCtx;
343     const glu::ContextInfo &m_renderCtxInfo;
344 
345     uint32_t m_minFilter;
346     uint32_t m_magFilter;
347     uint32_t m_wrapS;
348     uint32_t m_wrapT;
349     bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
350 
351     uint32_t m_internalFormat;
352     int m_width;
353     int m_height;
354 
355     std::vector<std::string> m_filenames;
356 
357     std::vector<glu::TextureCube *> m_textures;
358     TextureRenderer m_renderer;
359 };
360 
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)361 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
362                                                    const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
363                                                    uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
364                                                    uint32_t wrapT, bool onlySampleFaceInterior, uint32_t internalFormat,
365                                                    int width, int height)
366     : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
367     , m_renderCtx(renderCtx)
368     , m_renderCtxInfo(ctxInfo)
369     , m_minFilter(minFilter)
370     , m_magFilter(magFilter)
371     , m_wrapS(wrapS)
372     , m_wrapT(wrapT)
373     , m_onlySampleFaceInterior(onlySampleFaceInterior)
374     , m_internalFormat(internalFormat)
375     , m_width(width)
376     , m_height(height)
377     , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
378 {
379 }
380 
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)381 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
382                                                    const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
383                                                    uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
384                                                    uint32_t wrapT, bool onlySampleFaceInterior,
385                                                    const std::vector<std::string> &filenames)
386     : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
387     , m_renderCtx(renderCtx)
388     , m_renderCtxInfo(ctxInfo)
389     , m_minFilter(minFilter)
390     , m_magFilter(magFilter)
391     , m_wrapS(wrapS)
392     , m_wrapT(wrapT)
393     , m_onlySampleFaceInterior(onlySampleFaceInterior)
394     , m_internalFormat(GL_NONE)
395     , m_width(0)
396     , m_height(0)
397     , m_filenames(filenames)
398     , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
399 {
400 }
401 
~TextureCubeFilteringCase(void)402 TextureCubeFilteringCase::~TextureCubeFilteringCase(void)
403 {
404     deinit();
405 }
406 
init(void)407 void TextureCubeFilteringCase::init(void)
408 {
409     try
410     {
411         if (!m_filenames.empty())
412         {
413             m_textures.reserve(1);
414             m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
415                                                           (int)m_filenames.size() / 6, m_filenames));
416         }
417         else
418         {
419             m_textures.reserve(2);
420             DE_ASSERT(m_width == m_height);
421             for (int ndx = 0; ndx < 2; ndx++)
422                 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_internalFormat, m_width));
423 
424             const int numLevels            = deLog2Floor32(de::max(m_width, m_height)) + 1;
425             tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
426             tcu::Vec4 cBias                = fmtInfo.valueMin;
427             tcu::Vec4 cScale               = fmtInfo.valueMax - fmtInfo.valueMin;
428 
429             // Fill first with gradient texture.
430             static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = {
431                 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative x
432                 {tcu::Vec4(0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)},  // positive x
433                 {tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)},  // negative y
434                 {tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)},  // positive y
435                 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)}, // negative z
436                 {tcu::Vec4(0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}     // positive z
437             };
438             for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
439             {
440                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
441                 {
442                     m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
443                     tcu::fillWithComponentGradients(
444                         m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face),
445                         gradients[face][0] * cScale + cBias, gradients[face][1] * cScale + cBias);
446                 }
447             }
448 
449             // Fill second with grid texture.
450             for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
451             {
452                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
453                 {
454                     uint32_t step   = 0x00ffffff / (numLevels * tcu::CUBEFACE_LAST);
455                     uint32_t rgb    = step * levelNdx * face;
456                     uint32_t colorA = 0xff000000 | rgb;
457                     uint32_t colorB = 0xff000000 | ~rgb;
458 
459                     m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
460                     tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4,
461                                       tcu::RGBA(colorA).toVec() * cScale + cBias,
462                                       tcu::RGBA(colorB).toVec() * cScale + cBias);
463                 }
464             }
465 
466             if (m_magFilter == GL_LINEAR || m_minFilter == GL_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_NEAREST ||
467                 m_minFilter == GL_LINEAR_MIPMAP_LINEAR)
468             {
469                 // Using seamless linear cube map filtering - set all corner texels to the same color, because cube corner sampling in this case is not very well defined by the spec.
470                 // \todo Probably should also do this for cases where textures are loaded from files.
471 
472                 for (int texNdx = 0; texNdx < (int)m_textures.size(); texNdx++)
473                 {
474                     for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
475                     {
476                         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
477                         {
478                             static const tcu::Vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
479                             tcu::PixelBufferAccess access =
480                                 m_textures[texNdx]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face);
481 
482                             access.setPixel(color, 0, 0);
483                             access.setPixel(color, access.getWidth() - 1, 0);
484                             access.setPixel(color, 0, access.getHeight() - 1);
485                             access.setPixel(color, access.getWidth() - 1, access.getHeight() - 1);
486                         }
487                     }
488                 }
489             }
490 
491             // Upload.
492             for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
493                 (*i)->upload();
494         }
495     }
496     catch (const std::exception &)
497     {
498         // Clean up to save memory.
499         TextureCubeFilteringCase::deinit();
500         throw;
501     }
502 }
503 
deinit(void)504 void TextureCubeFilteringCase::deinit(void)
505 {
506     for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
507         delete *i;
508     m_textures.clear();
509 
510     m_renderer.clear();
511 }
512 
renderFaces(const glw::Functions & gl,const tcu::SurfaceAccess & dstRef,const tcu::TextureCube & refTexture,const ReferenceParams & params,TextureRenderer & renderer,int x,int y,int width,int height,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight,const tcu::Vec2 & texCoordTopRightFactor)513 static void renderFaces(const glw::Functions &gl, const tcu::SurfaceAccess &dstRef, const tcu::TextureCube &refTexture,
514                         const ReferenceParams &params, TextureRenderer &renderer, int x, int y, int width, int height,
515                         const tcu::Vec2 &bottomLeft, const tcu::Vec2 &topRight, const tcu::Vec2 &texCoordTopRightFactor)
516 {
517     DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight());
518 
519     vector<float> texCoord;
520 
521     DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6);
522     for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
523     {
524         bool isRightmost = (face == 2) || (face == 5);
525         bool isTop       = face >= 3;
526         int curX         = (face % 3) * (width / 3);
527         int curY         = (face / 3) * (height / 2);
528         int curW         = isRightmost ? (width - curX) : (width / 3);
529         int curH         = isTop ? (height - curY) : (height / 2);
530 
531         computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight);
532 
533         {
534             // Move the top and right edges of the texture coord quad. This is useful when we want a cube edge visible.
535             int texCoordSRow = face == tcu::CUBEFACE_NEGATIVE_X || face == tcu::CUBEFACE_POSITIVE_X ? 2 : 0;
536             int texCoordTRow = face == tcu::CUBEFACE_NEGATIVE_Y || face == tcu::CUBEFACE_POSITIVE_Y ? 2 : 1;
537             texCoord[6 + texCoordSRow] *= texCoordTopRightFactor.x();
538             texCoord[9 + texCoordSRow] *= texCoordTopRightFactor.x();
539             texCoord[3 + texCoordTRow] *= texCoordTopRightFactor.y();
540             texCoord[9 + texCoordTRow] *= texCoordTopRightFactor.y();
541         }
542 
543         gl.viewport(x + curX, y + curY, curW, curH);
544 
545         renderer.renderQuad(0, &texCoord[0], params);
546 
547         sampleTexture(tcu::SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params);
548     }
549 
550     GLU_EXPECT_NO_ERROR(gl.getError(), "Post render");
551 }
552 
iterate(void)553 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate(void)
554 {
555     const glw::Functions &gl    = m_renderCtx.getFunctions();
556     TestLog &log                = m_testCtx.getLog();
557     const int cellSize          = 28;
558     const int defViewportWidth  = cellSize * 6;
559     const int defViewportHeight = cellSize * 4;
560     RandomViewport viewport(m_renderCtx.getRenderTarget(), cellSize * 6, cellSize * 4, deStringHash(getName()));
561     tcu::Surface renderedFrame(viewport.width, viewport.height);
562     tcu::Surface referenceFrame(viewport.width, viewport.height);
563     ReferenceParams sampleParams(TEXTURETYPE_CUBE);
564     const tcu::TextureFormat &texFmt = m_textures[0]->getRefTexture().getFormat();
565     tcu::TextureFormatInfo fmtInfo   = tcu::getTextureFormatInfo(texFmt);
566 
567     // Accuracy measurements are off unless viewport size is exactly as expected.
568     if (getNodeType() == tcu::NODETYPE_ACCURACY &&
569         (viewport.width < defViewportWidth || viewport.height < defViewportHeight))
570         throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
571 
572     // Viewport is divided into 4 sections.
573     int leftWidth    = viewport.width / 2;
574     int rightWidth   = viewport.width - leftWidth;
575     int bottomHeight = viewport.height / 2;
576     int topHeight    = viewport.height - bottomHeight;
577 
578     int curTexNdx = 0;
579 
580     // Sampling parameters.
581     sampleParams.sampler                 = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
582     sampleParams.sampler.seamlessCubeMap = true;
583     sampleParams.samplerType             = getSamplerType(texFmt);
584     sampleParams.colorBias               = fmtInfo.lookupBias;
585     sampleParams.colorScale              = fmtInfo.lookupScale;
586     sampleParams.lodMode                 = LODMODE_EXACT;
587 
588     // Use unit 0.
589     gl.activeTexture(GL_TEXTURE0);
590 
591     // Setup gradient texture.
592     gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
593     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
594     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
595     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
596     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
597 
598     // Bottom left: Minification
599     renderFaces(gl,
600                 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth,
601                                    bottomHeight),
602                 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x, viewport.y, leftWidth,
603                 bottomHeight, m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f),
604                 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f),
605                 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f));
606 
607     // Bottom right: Magnification
608     renderFaces(gl,
609                 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0,
610                                    rightWidth, bottomHeight),
611                 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x + leftWidth, viewport.y,
612                 rightWidth, bottomHeight, tcu::Vec2(0.5f, 0.65f),
613                 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f),
614                 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f));
615 
616     if (m_textures.size() >= 2)
617     {
618         curTexNdx += 1;
619 
620         // Setup second texture.
621         gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
622         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
623         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
624         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
625         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
626     }
627 
628     // Top left: Minification
629     renderFaces(gl,
630                 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight,
631                                    leftWidth, topHeight),
632                 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x, viewport.y + bottomHeight,
633                 leftWidth, topHeight,
634                 m_onlySampleFaceInterior ? tcu::Vec2(-0.81f, -0.81f) : tcu::Vec2(-0.975f, -0.975f),
635                 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, 0.8f) : tcu::Vec2(0.975f, 0.975f),
636                 !m_onlySampleFaceInterior ? tcu::Vec2(1.3f, 1.25f) : tcu::Vec2(1.0f, 1.0f));
637 
638     // Top right: Magnification
639     renderFaces(gl,
640                 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth,
641                                    bottomHeight, rightWidth, topHeight),
642                 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x + leftWidth,
643                 viewport.y + bottomHeight, rightWidth, topHeight, tcu::Vec2(0.5f, -0.65f),
644                 m_onlySampleFaceInterior ? tcu::Vec2(0.8f, -0.8f) : tcu::Vec2(0.975f, -0.975f),
645                 !m_onlySampleFaceInterior ? tcu::Vec2(1.1f, 1.06f) : tcu::Vec2(1.0f, 1.0f));
646 
647     // Read result.
648     glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
649 
650     // Compare and log.
651     {
652         const int bestScoreDiff  = 16;
653         const int worstScoreDiff = 10000;
654 
655         int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
656         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
657     }
658 
659     return STOP;
660 }
661 
TextureFilteringTests(Context & context)662 TextureFilteringTests::TextureFilteringTests(Context &context)
663     : TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests")
664 {
665 }
666 
~TextureFilteringTests(void)667 TextureFilteringTests::~TextureFilteringTests(void)
668 {
669 }
670 
init(void)671 void TextureFilteringTests::init(void)
672 {
673     tcu::TestCaseGroup *group2D   = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering");
674     tcu::TestCaseGroup *groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Filtering");
675     addChild(group2D);
676     addChild(groupCube);
677 
678     static const struct
679     {
680         const char *name;
681         uint32_t mode;
682     } wrapModes[] = {{"clamp", GL_CLAMP_TO_EDGE}, {"repeat", GL_REPEAT}, {"mirror", GL_MIRRORED_REPEAT}};
683 
684     static const struct
685     {
686         const char *name;
687         uint32_t mode;
688     } minFilterModes[] = {{"nearest", GL_NEAREST},
689                           {"linear", GL_LINEAR},
690                           {"nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST},
691                           {"linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST},
692                           {"nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR},
693                           {"linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR}};
694 
695     static const struct
696     {
697         const char *name;
698         uint32_t mode;
699     } magFilterModes[] = {{"nearest", GL_NEAREST}, {"linear", GL_LINEAR}};
700 
701     static const struct
702     {
703         const char *name;
704         int width;
705         int height;
706     } sizes2D[] = {{"pot", 32, 64}, {"npot", 31, 55}};
707 
708     static const struct
709     {
710         const char *name;
711         int width;
712         int height;
713     } sizesCube[] = {{"pot", 64, 64}, {"npot", 63, 63}};
714 
715     static const struct
716     {
717         const char *name;
718         uint32_t format;
719     } formats[] = {{"rgba8", GL_RGBA8}};
720 
721 #define FOR_EACH(ITERATOR, ARRAY, BODY)                                      \
722     for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \
723     BODY
724 
725     // 2D cases.
726     FOR_EACH(minFilter, minFilterModes,
727              FOR_EACH(magFilter, magFilterModes,
728                       FOR_EACH(wrapMode, wrapModes,
729                                FOR_EACH(format, formats, FOR_EACH(size, sizes2D, {
730                                             string name = string("") + minFilterModes[minFilter].name + "_" +
731                                                           magFilterModes[magFilter].name + "_" +
732                                                           wrapModes[wrapMode].name + "_" + formats[format].name +
733                                                           string("_") + sizes2D[size].name;
734 
735                                             group2D->addChild(new Texture2DFilteringCase(
736                                                 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
737                                                 name.c_str(), "", minFilterModes[minFilter].mode,
738                                                 magFilterModes[magFilter].mode, wrapModes[wrapMode].mode,
739                                                 wrapModes[wrapMode].mode, formats[format].format, sizes2D[size].width,
740                                                 sizes2D[size].height));
741                                         })))))
742 
743     // Cubemap cases.
744     FOR_EACH(minFilter, minFilterModes,
745              FOR_EACH(magFilter, magFilterModes,
746                       FOR_EACH(wrapMode, wrapModes,
747                                FOR_EACH(format, formats, FOR_EACH(size, sizesCube, {
748                                             string name = string("") + minFilterModes[minFilter].name + "_" +
749                                                           magFilterModes[magFilter].name + "_" +
750                                                           wrapModes[wrapMode].name + "_" + formats[format].name +
751                                                           string("_") + sizesCube[size].name;
752 
753                                             groupCube->addChild(new TextureCubeFilteringCase(
754                                                 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
755                                                 name.c_str(), "", minFilterModes[minFilter].mode,
756                                                 magFilterModes[magFilter].mode, wrapModes[wrapMode].mode,
757                                                 wrapModes[wrapMode].mode, false, formats[format].format,
758                                                 sizesCube[size].width, sizesCube[size].height));
759                                         })))))
760 }
761 
762 } // namespace Accuracy
763 } // namespace gles3
764 } // namespace deqp
765