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