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