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