Relax LOD computation bounds; add mipmap.2d.projected to mustpass
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / functional / es2fTextureMipmapTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Mipmapping tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es2fTextureMipmapTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluTexture.hpp"
27 #include "gluStrUtil.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuVector.hpp"
33 #include "tcuMatrix.hpp"
34 #include "tcuMatrixUtil.hpp"
35 #include "tcuTexLookupVerifier.hpp"
36 #include "tcuVectorUtil.hpp"
37 #include "deStringUtil.hpp"
38 #include "deRandom.hpp"
39 #include "glwFunctions.hpp"
40 #include "glwEnums.hpp"
41
42 namespace deqp
43 {
44 namespace gles2
45 {
46 namespace Functional
47 {
48
49 using tcu::TestLog;
50 using std::vector;
51 using std::string;
52 using tcu::Sampler;
53 using tcu::Vec2;
54 using tcu::Mat2;
55 using tcu::Vec4;
56 using tcu::IVec2;
57 using tcu::IVec4;
58 using namespace glu;
59 using namespace gls::TextureTestUtil;
60 using namespace glu::TextureTestUtil;
61
62 enum CoordType
63 {
64         COORDTYPE_BASIC,                //!< texCoord = translateScale(position).
65         COORDTYPE_BASIC_BIAS,   //!< Like basic, but with bias values.
66         COORDTYPE_AFFINE,               //!< texCoord = translateScaleRotateShear(position).
67         COORDTYPE_PROJECTED,    //!< Projected coordinates, w != 1
68
69         COORDTYPE_LAST
70 };
71
72 // Texture2DMipmapCase
73
74 class Texture2DMipmapCase : public tcu::TestCase
75 {
76 public:
77
78                                                                 Texture2DMipmapCase                     (tcu::TestContext&                      testCtx,
79                                                                                                                          glu::RenderContext&            renderCtx,
80                                                                                                                          const glu::ContextInfo&        renderCtxInfo,
81                                                                                                                          const char*                            name,
82                                                                                                                          const char*                            desc,
83                                                                                                                          CoordType                                      coordType,
84                                                                                                                          deUint32                                       minFilter,
85                                                                                                                          deUint32                                       wrapS,
86                                                                                                                          deUint32                                       wrapT,
87                                                                                                                          deUint32                                       format,
88                                                                                                                          deUint32                                       dataType,
89                                                                                                                          int                                            width,
90                                                                                                                          int                                            height);
91                                                                 ~Texture2DMipmapCase            (void);
92
93         void                                            init                                            (void);
94         void                                            deinit                                          (void);
95         IterateResult                           iterate                                         (void);
96
97 private:
98                                                                 Texture2DMipmapCase                     (const Texture2DMipmapCase& other);
99         Texture2DMipmapCase&            operator=                                       (const Texture2DMipmapCase& other);
100
101         glu::RenderContext&                     m_renderCtx;
102         const glu::ContextInfo&         m_renderCtxInfo;
103
104         CoordType                                       m_coordType;
105         deUint32                                        m_minFilter;
106         deUint32                                        m_wrapS;
107         deUint32                                        m_wrapT;
108         deUint32                                        m_format;
109         deUint32                                        m_dataType;
110         int                                                     m_width;
111         int                                                     m_height;
112
113         glu::Texture2D*                         m_texture;
114         TextureRenderer                         m_renderer;
115 };
116
117 Texture2DMipmapCase::Texture2DMipmapCase (tcu::TestContext&                     testCtx,
118                                                                                   glu::RenderContext&           renderCtx,
119                                                                                   const glu::ContextInfo&       renderCtxInfo,
120                                                                                   const char*                           name,
121                                                                                   const char*                           desc,
122                                                                                   CoordType                                     coordType,
123                                                                                   deUint32                                      minFilter,
124                                                                                   deUint32                                      wrapS,
125                                                                                   deUint32                                      wrapT,
126                                                                                   deUint32                                      format,
127                                                                                   deUint32                                      dataType,
128                                                                                   int                                           width,
129                                                                                   int                                           height)
130         : TestCase                      (testCtx, name, desc)
131         , m_renderCtx           (renderCtx)
132         , m_renderCtxInfo       (renderCtxInfo)
133         , m_coordType           (coordType)
134         , m_minFilter           (minFilter)
135         , m_wrapS                       (wrapS)
136         , m_wrapT                       (wrapT)
137         , m_format                      (format)
138         , m_dataType            (dataType)
139         , m_width                       (width)
140         , m_height                      (height)
141         , m_texture                     (DE_NULL)
142         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES,
143                                                  renderCtxInfo.isFragmentHighPrecisionSupported() ? glu::PRECISION_HIGHP // Use highp if available.
144                                                                                                                                                   : glu::PRECISION_MEDIUMP)
145 {
146 }
147
148 Texture2DMipmapCase::~Texture2DMipmapCase (void)
149 {
150         deinit();
151 }
152
153 void Texture2DMipmapCase::init (void)
154 {
155         if (!m_renderCtxInfo.isFragmentHighPrecisionSupported())
156                 m_testCtx.getLog() << TestLog::Message << "Warning: High precision not supported in fragment shaders." << TestLog::EndMessage;
157
158         if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
159                 throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
160
161         m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
162
163         int numLevels = deLog2Floor32(de::max(m_width, m_height))+1;
164
165         // Fill texture with colored grid.
166         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
167         {
168                 deUint32        step            = 0xff / (numLevels-1);
169                 deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
170                 deUint32        dec                     = 0xff - inc;
171                 deUint32        rgb                     = (inc << 16) | (dec << 8) | 0xff;
172                 deUint32        color           = 0xff000000 | rgb;
173
174                 m_texture->getRefTexture().allocLevel(levelNdx);
175                 tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec());
176         }
177 }
178
179 void Texture2DMipmapCase::deinit (void)
180 {
181         delete m_texture;
182         m_texture = DE_NULL;
183
184         m_renderer.clear();
185 }
186
187 static void getBasicTexCoord2D (std::vector<float>& dst, int cellNdx)
188 {
189         static const struct
190         {
191                 Vec2 bottomLeft;
192                 Vec2 topRight;
193         } s_basicCoords[] =
194         {
195                 { Vec2(-0.1f,  0.1f), Vec2( 0.8f,  1.0f) },
196                 { Vec2(-0.3f, -0.6f), Vec2( 0.7f,  0.4f) },
197                 { Vec2(-0.3f,  0.6f), Vec2( 0.7f, -0.9f) },
198                 { Vec2(-0.8f,  0.6f), Vec2( 0.7f, -0.9f) },
199
200                 { Vec2(-0.5f, -0.5f), Vec2( 1.5f,  1.5f) },
201                 { Vec2( 1.0f, -1.0f), Vec2(-1.3f,  1.0f) },
202                 { Vec2( 1.2f, -1.0f), Vec2(-1.3f,  1.6f) },
203                 { Vec2( 2.2f, -1.1f), Vec2(-1.3f,  0.8f) },
204
205                 { Vec2(-1.5f,  1.6f), Vec2( 1.7f, -1.4f) },
206                 { Vec2( 2.0f,  1.6f), Vec2( 2.3f, -1.4f) },
207                 { Vec2( 1.3f, -2.6f), Vec2(-2.7f,  2.9f) },
208                 { Vec2(-0.8f, -6.6f), Vec2( 6.0f, -0.9f) },
209
210                 { Vec2( -8.0f,   9.0f), Vec2(  8.3f,  -7.0f) },
211                 { Vec2(-16.0f,  10.0f), Vec2( 18.3f,  24.0f) },
212                 { Vec2( 30.2f,  55.0f), Vec2(-24.3f,  -1.6f) },
213                 { Vec2(-33.2f,  64.1f), Vec2( 32.1f, -64.1f) },
214         };
215
216         DE_ASSERT(de::inBounds(cellNdx, 0, DE_LENGTH_OF_ARRAY(s_basicCoords)));
217
218         const Vec2& bottomLeft  = s_basicCoords[cellNdx].bottomLeft;
219         const Vec2& topRight    = s_basicCoords[cellNdx].topRight;
220
221         computeQuadTexCoord2D(dst, bottomLeft, topRight);
222 }
223
224 static void getAffineTexCoord2D (std::vector<float>& dst, int cellNdx)
225 {
226         // Use basic coords as base.
227         getBasicTexCoord2D(dst, cellNdx);
228
229         // Rotate based on cell index.
230         float           angle           = 2.0f*DE_PI * ((float)cellNdx / 16.0f);
231         tcu::Mat2       rotMatrix       = tcu::rotationMatrix(angle);
232
233         // Second and third row are sheared.
234         float           shearX          = de::inRange(cellNdx, 4, 11) ? (float)(15-cellNdx) / 16.0f : 0.0f;
235         tcu::Mat2       shearMatrix     = tcu::shearMatrix(tcu::Vec2(shearX, 0.0f));
236
237         tcu::Mat2       transform       = rotMatrix * shearMatrix;
238         Vec2            p0                      = transform * Vec2(dst[0], dst[1]);
239         Vec2            p1                      = transform * Vec2(dst[2], dst[3]);
240         Vec2            p2                      = transform * Vec2(dst[4], dst[5]);
241         Vec2            p3                      = transform * Vec2(dst[6], dst[7]);
242
243         dst[0] = p0.x();        dst[1] = p0.y();
244         dst[2] = p1.x();        dst[3] = p1.y();
245         dst[4] = p2.x();        dst[5] = p2.y();
246         dst[6] = p3.x();        dst[7] = p3.y();
247 }
248
249 Texture2DMipmapCase::IterateResult Texture2DMipmapCase::iterate (void)
250 {
251         const glw::Functions&           gl                                      = m_renderCtx.getFunctions();
252
253         const tcu::Texture2D&           refTexture                      = m_texture->getRefTexture();
254
255         const deUint32                          magFilter                       = GL_NEAREST;
256         const int                                       texWidth                        = refTexture.getWidth();
257         const int                                       texHeight                       = refTexture.getHeight();
258         const int                                       defViewportWidth        = texWidth*4;
259         const int                                       defViewportHeight       = texHeight*4;
260
261         const RandomViewport            viewport                        (m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
262         ReferenceParams                         sampleParams            (TEXTURETYPE_2D);
263         vector<float>                           texCoord;
264
265         const bool                                      isProjected                     = m_coordType == COORDTYPE_PROJECTED;
266         const bool                                      useLodBias                      = m_coordType == COORDTYPE_BASIC_BIAS;
267
268         tcu::Surface                            renderedFrame           (viewport.width, viewport.height);
269
270         // Viewport is divided into 4x4 grid.
271         int                                                     gridWidth                       = 4;
272         int                                                     gridHeight                      = 4;
273         int                                                     cellWidth                       = viewport.width / gridWidth;
274         int                                                     cellHeight                      = viewport.height / gridHeight;
275
276         // Bail out if rendertarget is too small.
277         if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
278                 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
279
280         // Sampling parameters.
281         sampleParams.sampler            = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
282         sampleParams.samplerType        = glu::TextureTestUtil::getSamplerType(m_texture->getRefTexture().getFormat());
283         sampleParams.flags                      = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
284         sampleParams.lodMode            = LODMODE_EXACT; // Use ideal lod.
285
286         // Upload texture data.
287         m_texture->upload();
288
289         // Bind gradient texture and setup sampler parameters.
290         gl.bindTexture  (GL_TEXTURE_2D, m_texture->getGLTexture());
291         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,              m_wrapS);
292         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,              m_wrapT);
293         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,  m_minFilter);
294         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,  magFilter);
295
296         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
297
298         // Bias values.
299         static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
300
301         // Projection values.
302         static const Vec4 s_projections[] =
303         {
304                 Vec4(1.2f, 1.0f, 0.7f, 1.0f),
305                 Vec4(1.3f, 0.8f, 0.6f, 2.0f),
306                 Vec4(0.8f, 1.0f, 1.7f, 0.6f),
307                 Vec4(1.2f, 1.0f, 1.7f, 1.5f)
308         };
309
310         // Render cells.
311         for (int gridY = 0; gridY < gridHeight; gridY++)
312         {
313                 for (int gridX = 0; gridX < gridWidth; gridX++)
314                 {
315                         const int               curX            = cellWidth*gridX;
316                         const int               curY            = cellHeight*gridY;
317                         const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
318                         const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
319                         const int               cellNdx         = gridY*gridWidth + gridX;
320
321                         // Compute texcoord.
322                         switch (m_coordType)
323                         {
324                                 case COORDTYPE_BASIC_BIAS:      // Fall-through.
325                                 case COORDTYPE_PROJECTED:
326                                 case COORDTYPE_BASIC:           getBasicTexCoord2D      (texCoord, cellNdx);    break;
327                                 case COORDTYPE_AFFINE:          getAffineTexCoord2D     (texCoord, cellNdx);    break;
328                                 default:                                        DE_ASSERT(DE_FALSE);
329                         }
330
331                         if (isProjected)
332                                 sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
333
334                         if (useLodBias)
335                                 sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
336
337                         // Render with GL.
338                         gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
339                         m_renderer.renderQuad(0, &texCoord[0], sampleParams);
340                 }
341         }
342
343         // Read result.
344         glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
345
346         // Compare and log.
347         {
348                 const tcu::PixelFormat& pixelFormat             = m_renderCtx.getRenderTarget().getPixelFormat();
349                 const bool                              isTrilinear             = m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
350                 tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
351                 tcu::Surface                    errorMask               (viewport.width, viewport.height);
352                 tcu::LookupPrecision    lookupPrec;
353                 tcu::LodPrecision               lodPrec                 (tcu::LodPrecision::RULE_OPENGL);
354                 int                                             numFailedPixels = 0;
355
356                 lookupPrec.coordBits            = tcu::IVec3(20, 20, 0);
357                 lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
358                 lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
359                 lookupPrec.colorMask            = getCompareMask(pixelFormat);
360                 lodPrec.derivateBits            = 10;
361                 lodPrec.lodBits                         = isProjected ? 6 : 8;
362
363                 for (int gridY = 0; gridY < gridHeight; gridY++)
364                 {
365                         for (int gridX = 0; gridX < gridWidth; gridX++)
366                         {
367                                 const int               curX            = cellWidth*gridX;
368                                 const int               curY            = cellHeight*gridY;
369                                 const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
370                                 const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
371                                 const int               cellNdx         = gridY*gridWidth + gridX;
372
373                                 // Compute texcoord.
374                                 switch (m_coordType)
375                                 {
376                                         case COORDTYPE_BASIC_BIAS:      // Fall-through.
377                                         case COORDTYPE_PROJECTED:
378                                         case COORDTYPE_BASIC:           getBasicTexCoord2D      (texCoord, cellNdx);    break;
379                                         case COORDTYPE_AFFINE:          getAffineTexCoord2D     (texCoord, cellNdx);    break;
380                                         default:                                        DE_ASSERT(DE_FALSE);
381                                 }
382
383                                 if (isProjected)
384                                         sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
385
386                                 if (useLodBias)
387                                         sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
388
389                                 // Render ideal result
390                                 sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
391                                                           refTexture, &texCoord[0], sampleParams);
392
393                                 // Compare this cell
394                                 numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
395                                                                                                                         tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
396                                                                                                                         tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
397                                                                                                                         m_texture->getRefTexture(), &texCoord[0], sampleParams,
398                                                                                                                         lookupPrec, lodPrec, m_testCtx.getWatchDog());
399                         }
400                 }
401
402                 if (numFailedPixels > 0)
403                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
404
405                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
406                                                         << TestLog::Image("Rendered", "Rendered image", renderedFrame);
407
408                 if (numFailedPixels > 0)
409                 {
410                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
411                                                                 << TestLog::Image("ErrorMask", "Error mask", errorMask);
412                 }
413
414                 m_testCtx.getLog() << TestLog::EndImageSet;
415
416                 {
417                         const bool isOk = numFailedPixels == 0;
418                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
419                                                                         isOk ? "Pass"                           : "Image verification failed");
420                 }
421         }
422
423         return STOP;
424 }
425
426 // TextureCubeMipmapCase
427
428 class TextureCubeMipmapCase : public tcu::TestCase
429 {
430 public:
431
432                                                                 TextureCubeMipmapCase           (tcu::TestContext&                      testCtx,
433                                                                                                                          glu::RenderContext&            renderCtx,
434                                                                                                                          const glu::ContextInfo&        renderCtxInfo,
435                                                                                                                          const char*                            name,
436                                                                                                                          const char*                            desc,
437                                                                                                                          CoordType                                      coordType,
438                                                                                                                          deUint32                                       minFilter,
439                                                                                                                          deUint32                                       wrapS,
440                                                                                                                          deUint32                                       wrapT,
441                                                                                                                          deUint32                                       format,
442                                                                                                                          deUint32                                       dataType,
443                                                                                                                          int                                            size);
444                                                                 ~TextureCubeMipmapCase          (void);
445
446         void                                            init                                            (void);
447         void                                            deinit                                          (void);
448         IterateResult                           iterate                                         (void);
449
450 private:
451                                                                 TextureCubeMipmapCase           (const TextureCubeMipmapCase& other);
452         TextureCubeMipmapCase&          operator=                                       (const TextureCubeMipmapCase& other);
453
454         glu::RenderContext&                     m_renderCtx;
455         const glu::ContextInfo&         m_renderCtxInfo;
456
457         CoordType                                       m_coordType;
458         deUint32                                        m_minFilter;
459         deUint32                                        m_wrapS;
460         deUint32                                        m_wrapT;
461         deUint32                                        m_format;
462         deUint32                                        m_dataType;
463         int                                                     m_size;
464
465         glu::TextureCube*                       m_texture;
466         TextureRenderer                         m_renderer;
467 };
468
469 TextureCubeMipmapCase::TextureCubeMipmapCase (tcu::TestContext&                 testCtx,
470                                                                                           glu::RenderContext&           renderCtx,
471                                                                                           const glu::ContextInfo&       renderCtxInfo,
472                                                                                           const char*                           name,
473                                                                                           const char*                           desc,
474                                                                                           CoordType                                     coordType,
475                                                                                           deUint32                                      minFilter,
476                                                                                           deUint32                                      wrapS,
477                                                                                           deUint32                                      wrapT,
478                                                                                           deUint32                                      format,
479                                                                                           deUint32                                      dataType,
480                                                                                           int                                           size)
481         : TestCase                      (testCtx, name, desc)
482         , m_renderCtx           (renderCtx)
483         , m_renderCtxInfo       (renderCtxInfo)
484         , m_coordType           (coordType)
485         , m_minFilter           (minFilter)
486         , m_wrapS                       (wrapS)
487         , m_wrapT                       (wrapT)
488         , m_format                      (format)
489         , m_dataType            (dataType)
490         , m_size                        (size)
491         , m_texture                     (DE_NULL)
492         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES,
493                                                  renderCtxInfo.isFragmentHighPrecisionSupported() ? glu::PRECISION_HIGHP // Use highp if available.
494                                                                                                                                                   : glu::PRECISION_MEDIUMP)
495 {
496 }
497
498 TextureCubeMipmapCase::~TextureCubeMipmapCase (void)
499 {
500         deinit();
501 }
502
503 void TextureCubeMipmapCase::init (void)
504 {
505         if (!m_renderCtxInfo.isFragmentHighPrecisionSupported())
506                 m_testCtx.getLog() << TestLog::Message << "Warning: High precision not supported in fragment shaders." << TestLog::EndMessage;
507
508         if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
509                 throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
510
511         m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_size);
512
513         int numLevels = deLog2Floor32(m_size)+1;
514
515         // Fill texture with colored grid.
516         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
517         {
518                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
519                 {
520                         deUint32        step            = 0xff / (numLevels-1);
521                         deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
522                         deUint32        dec                     = 0xff - inc;
523                         deUint32        rgb                     = 0;
524
525                         switch (faceNdx)
526                         {
527                                 case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
528                                 case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
529                                 case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
530                                 case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
531                                 case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
532                                 case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
533                         }
534
535                         deUint32        color           = 0xff000000 | rgb;
536
537                         m_texture->getRefTexture().allocLevel((tcu::CubeFace)faceNdx, levelNdx);
538                         tcu::clear(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
539                 }
540         }
541 }
542
543 void TextureCubeMipmapCase::deinit (void)
544 {
545         delete m_texture;
546         m_texture = DE_NULL;
547
548         m_renderer.clear();
549 }
550
551 static void randomPartition (vector<IVec4>& dst, de::Random& rnd, int x, int y, int width, int height)
552 {
553         const int minWidth      = 8;
554         const int minHeight     = 8;
555
556         bool    partition               = rnd.getFloat() > 0.4f;
557         bool    partitionX              = partition && width > minWidth && rnd.getBool();
558         bool    partitionY              = partition && height > minHeight && !partitionX;
559
560         if (partitionX)
561         {
562                 int split = width/2 + rnd.getInt(-width/4, +width/4);
563                 randomPartition(dst, rnd, x, y, split, height);
564                 randomPartition(dst, rnd, x+split, y, width-split, height);
565         }
566         else if (partitionY)
567         {
568                 int split = height/2 + rnd.getInt(-height/4, +height/4);
569                 randomPartition(dst, rnd, x, y, width, split);
570                 randomPartition(dst, rnd, x, y+split, width, height-split);
571         }
572         else
573                 dst.push_back(IVec4(x, y, width, height));
574 }
575
576 static void computeGridLayout (vector<IVec4>& dst, int width, int height)
577 {
578         de::Random rnd(7);
579         randomPartition(dst, rnd, 0, 0, width, height);
580 }
581
582 TextureCubeMipmapCase::IterateResult TextureCubeMipmapCase::iterate (void)
583 {
584         const deUint32                  magFilter                       = GL_NEAREST;
585         const int                               texWidth                        = m_texture->getRefTexture().getSize();
586         const int                               texHeight                       = m_texture->getRefTexture().getSize();
587         const int                               defViewportWidth        = texWidth*2;
588         const int                               defViewportHeight       = texHeight*2;
589
590         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
591         const RandomViewport    viewport                        (m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
592
593         const bool                              isProjected                     = m_coordType == COORDTYPE_PROJECTED;
594         const bool                              useLodBias                      = m_coordType == COORDTYPE_BASIC_BIAS;
595
596         vector<float>                   texCoord;
597         tcu::Surface                    renderedFrame           (viewport.width, viewport.height);
598
599         // Bail out if rendertarget is too small.
600         if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
601                 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
602
603         // Upload texture data.
604         m_texture->upload();
605
606         // Bind gradient texture and setup sampler parameters.
607         gl.bindTexture  (GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
608         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,                m_wrapS);
609         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,                m_wrapT);
610         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,    m_minFilter);
611         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,    magFilter);
612
613         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
614
615         // Compute grid.
616         vector<IVec4> gridLayout;
617         computeGridLayout(gridLayout, viewport.width, viewport.height);
618
619         // Bias values.
620         static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
621
622         // Projection values \note Less agressive than in 2D case due to smaller quads.
623         static const Vec4 s_projections[] =
624         {
625                 Vec4(1.2f, 1.0f, 0.7f, 1.0f),
626                 Vec4(1.3f, 0.8f, 0.6f, 1.1f),
627                 Vec4(0.8f, 1.0f, 1.2f, 0.8f),
628                 Vec4(1.2f, 1.0f, 1.3f, 0.9f)
629         };
630
631         // Render with GL
632         for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
633         {
634                 const int                       curX            = gridLayout[cellNdx].x();
635                 const int                       curY            = gridLayout[cellNdx].y();
636                 const int                       curW            = gridLayout[cellNdx].z();
637                 const int                       curH            = gridLayout[cellNdx].w();
638                 const tcu::CubeFace     cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
639                 RenderParams            params          (TEXTURETYPE_CUBE);
640
641                 DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
642                 computeQuadTexCoordCube(texCoord, cubeFace);
643
644                 if (isProjected)
645                 {
646                         params.flags    |= ReferenceParams::PROJECTED;
647                         params.w                 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
648                 }
649
650                 if (useLodBias)
651                 {
652                         params.flags    |= ReferenceParams::USE_BIAS;
653                         params.bias              = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
654                 }
655
656                 // Render with GL.
657                 gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
658                 m_renderer.renderQuad(0, &texCoord[0], params);
659         }
660         GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
661
662         // Read result.
663         glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
664         GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
665
666         // Render reference and compare
667         {
668                 tcu::Surface                    referenceFrame          (viewport.width, viewport.height);
669                 tcu::Surface                    errorMask                       (viewport.width, viewport.height);
670                 int                                             numFailedPixels         = 0;
671                 ReferenceParams                 params                          (TEXTURETYPE_CUBE);
672                 tcu::LookupPrecision    lookupPrec;
673                 tcu::LodPrecision               lodPrec                         (tcu::LodPrecision::RULE_OPENGL);
674
675                 // Params for rendering reference
676                 params.sampler                                  = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
677                 params.sampler.seamlessCubeMap  = false;
678                 params.lodMode                                  = LODMODE_EXACT;
679
680                 // Comparison parameters
681                 lookupPrec.colorMask                    = getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
682                 lookupPrec.colorThreshold               = tcu::computeFixedPointThreshold(max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0)));
683                 lookupPrec.coordBits                    = isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
684                 lookupPrec.uvwBits                              = tcu::IVec3(5,5,0);
685                 lodPrec.derivateBits                    = 10;
686                 lodPrec.lodBits                                 = isProjected ? 4 : 6;
687
688                 for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
689                 {
690                         const int                               curX            = gridLayout[cellNdx].x();
691                         const int                               curY            = gridLayout[cellNdx].y();
692                         const int                               curW            = gridLayout[cellNdx].z();
693                         const int                               curH            = gridLayout[cellNdx].w();
694                         const tcu::CubeFace             cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
695
696                         DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
697                         computeQuadTexCoordCube(texCoord, cubeFace);
698
699                         if (isProjected)
700                         {
701                                 params.flags    |= ReferenceParams::PROJECTED;
702                                 params.w                 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
703                         }
704
705                         if (useLodBias)
706                         {
707                                 params.flags    |= ReferenceParams::USE_BIAS;
708                                 params.bias              = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
709                         }
710
711                         // Render ideal reference.
712                         {
713                                 tcu::SurfaceAccess idealDst(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), curX, curY, curW, curH);
714                                 sampleTexture(idealDst, m_texture->getRefTexture(), &texCoord[0], params);
715                         }
716
717                         // Compare this cell
718                         numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
719                                                                                                                 tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
720                                                                                                                 tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
721                                                                                                                 m_texture->getRefTexture(), &texCoord[0], params,
722                                                                                                                 lookupPrec, lodPrec, m_testCtx.getWatchDog());
723                 }
724
725                 if (numFailedPixels > 0)
726                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
727
728                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
729                                                    << TestLog::Image("Rendered", "Rendered image", renderedFrame);
730
731                 if (numFailedPixels > 0)
732                 {
733                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
734                                                            << TestLog::Image("ErrorMask", "Error mask", errorMask);
735                 }
736
737                 m_testCtx.getLog() << TestLog::EndImageSet;
738
739                 {
740                         const bool isOk = numFailedPixels == 0;
741                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
742                                                                         isOk ? "Pass"                           : "Image verification failed");
743                 }
744         }
745
746         return STOP;
747 }
748
749 // Texture2DGenMipmapCase
750
751 class Texture2DGenMipmapCase : public tcu::TestCase
752 {
753 public:
754
755                                                                 Texture2DGenMipmapCase          (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height);
756                                                                 ~Texture2DGenMipmapCase         (void);
757
758         void                                            init                                            (void);
759         void                                            deinit                                          (void);
760         IterateResult                           iterate                                         (void);
761
762 private:
763                                                                 Texture2DGenMipmapCase          (const Texture2DGenMipmapCase& other);
764         Texture2DGenMipmapCase&         operator=                                       (const Texture2DGenMipmapCase& other);
765
766         glu::RenderContext&                     m_renderCtx;
767
768         deUint32                                        m_format;
769         deUint32                                        m_dataType;
770         deUint32                                        m_hint;
771         int                                                     m_width;
772         int                                                     m_height;
773
774         glu::Texture2D*                         m_texture;
775         TextureRenderer                         m_renderer;
776 };
777
778 Texture2DGenMipmapCase::Texture2DGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height)
779         : TestCase                      (testCtx, name, desc)
780         , m_renderCtx           (renderCtx)
781         , m_format                      (format)
782         , m_dataType            (dataType)
783         , m_hint                        (hint)
784         , m_width                       (width)
785         , m_height                      (height)
786         , m_texture                     (DE_NULL)
787         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
788 {
789 }
790
791 Texture2DGenMipmapCase::~Texture2DGenMipmapCase (void)
792 {
793         deinit();
794 }
795
796 void Texture2DGenMipmapCase::init (void)
797 {
798         DE_ASSERT(!m_texture);
799         m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
800 }
801
802 void Texture2DGenMipmapCase::deinit (void)
803 {
804         delete m_texture;
805         m_texture = DE_NULL;
806
807         m_renderer.clear();
808 }
809
810 Texture2DGenMipmapCase::IterateResult Texture2DGenMipmapCase::iterate (void)
811 {
812         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
813
814         const deUint32                  minFilter                       = GL_NEAREST_MIPMAP_NEAREST;
815         const deUint32                  magFilter                       = GL_NEAREST;
816         const deUint32                  wrapS                           = GL_CLAMP_TO_EDGE;
817         const deUint32                  wrapT                           = GL_CLAMP_TO_EDGE;
818
819         const int                               numLevels                       = deLog2Floor32(de::max(m_width, m_height))+1;
820
821         tcu::Texture2D                  resultTexture           (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight());
822
823         vector<float>                   texCoord;
824
825         // Initialize texture level 0 with colored grid.
826         m_texture->getRefTexture().allocLevel(0);
827         tcu::fillWithGrid(m_texture->getRefTexture().getLevel(0), 8, tcu::Vec4(1.0f, 0.5f, 0.0f, 0.5f), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
828
829         // Upload data and setup params.
830         m_texture->upload();
831
832         gl.bindTexture  (GL_TEXTURE_2D, m_texture->getGLTexture());
833         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,              wrapS);
834         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,              wrapT);
835         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,  minFilter);
836         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,  magFilter);
837         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
838
839         // Generate mipmap.
840         gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
841         gl.generateMipmap(GL_TEXTURE_2D);
842         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
843
844         // Use (0, 0) -> (1, 1) texture coordinates.
845         computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
846
847         // Fetch resulting texture by rendering.
848         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
849         {
850                 const int                               levelWidth              = de::max(1, m_width >> levelNdx);
851                 const int                               levelHeight             = de::max(1, m_height >> levelNdx);
852                 const RandomViewport    viewport                (m_renderCtx.getRenderTarget(), levelWidth, levelHeight, deStringHash(getName()) + levelNdx);
853
854                 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
855                 m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
856
857                 resultTexture.allocLevel(levelNdx);
858                 glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevel(levelNdx));
859         }
860
861         // Compare results
862         {
863
864                 const IVec4                     framebufferBits         = max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
865                 const IVec4                     formatBits                      = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
866                 const tcu::BVec4        formatMask                      = greaterThan(formatBits, IVec4(0));
867                 const IVec4                     cmpBits                         = select(min(framebufferBits, formatBits), framebufferBits, formatMask);
868                 GenMipmapPrecision      comparePrec;
869
870                 comparePrec.colorMask           = getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
871                 comparePrec.colorThreshold      = tcu::computeFixedPointThreshold(cmpBits);
872                 comparePrec.filterBits          = tcu::IVec3(4, 4, 0);
873
874                 const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
875
876                 m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS                             ? "Pass" :
877                                                                                            compareResult == QP_TEST_RESULT_QUALITY_WARNING      ? "Low-quality method used"     :
878                                                                                            compareResult == QP_TEST_RESULT_FAIL                         ? "Image comparison failed"     : "");
879         }
880
881         return STOP;
882 }
883
884 // TextureCubeGenMipmapCase
885
886 class TextureCubeGenMipmapCase : public tcu::TestCase
887 {
888 public:
889
890                                                                 TextureCubeGenMipmapCase                (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size);
891                                                                 ~TextureCubeGenMipmapCase               (void);
892
893         void                                            init                                                    (void);
894         void                                            deinit                                                  (void);
895         IterateResult                           iterate                                                 (void);
896
897 private:
898                                                                 TextureCubeGenMipmapCase                (const TextureCubeGenMipmapCase& other);
899         TextureCubeGenMipmapCase&       operator=                                               (const TextureCubeGenMipmapCase& other);
900
901         glu::RenderContext&                     m_renderCtx;
902
903         deUint32                                        m_format;
904         deUint32                                        m_dataType;
905         deUint32                                        m_hint;
906         int                                                     m_size;
907
908         glu::TextureCube*                       m_texture;
909         TextureRenderer                         m_renderer;
910 };
911
912 TextureCubeGenMipmapCase::TextureCubeGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size)
913         : TestCase                      (testCtx, name, desc)
914         , m_renderCtx           (renderCtx)
915         , m_format                      (format)
916         , m_dataType            (dataType)
917         , m_hint                        (hint)
918         , m_size                        (size)
919         , m_texture                     (DE_NULL)
920         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
921 {
922 }
923
924 TextureCubeGenMipmapCase::~TextureCubeGenMipmapCase (void)
925 {
926         deinit();
927 }
928
929 void TextureCubeGenMipmapCase::init (void)
930 {
931         if (m_renderCtx.getRenderTarget().getWidth() < 3*m_size || m_renderCtx.getRenderTarget().getHeight() < 2*m_size)
932                 throw tcu::NotSupportedError("Render target size must be at least (" + de::toString(3*m_size) + ", " + de::toString(2*m_size) + ")");
933
934         DE_ASSERT(!m_texture);
935         m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_size);
936 }
937
938 void TextureCubeGenMipmapCase::deinit (void)
939 {
940         delete m_texture;
941         m_texture = DE_NULL;
942
943         m_renderer.clear();
944 }
945
946 TextureCubeGenMipmapCase::IterateResult TextureCubeGenMipmapCase::iterate (void)
947 {
948         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
949
950         const deUint32                  minFilter                       = GL_NEAREST_MIPMAP_NEAREST;
951         const deUint32                  magFilter                       = GL_NEAREST;
952         const deUint32                  wrapS                           = GL_CLAMP_TO_EDGE;
953         const deUint32                  wrapT                           = GL_CLAMP_TO_EDGE;
954
955         tcu::TextureCube                resultTexture           (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_size);
956
957         const int                               numLevels                       = deLog2Floor32(m_size)+1;
958         vector<float>                   texCoord;
959
960         // Initialize texture level 0 with colored grid.
961         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
962         {
963                 Vec4 ca, cb; // Grid colors.
964
965                 switch (face)
966                 {
967                         case 0: ca = Vec4(1.0f, 0.3f, 0.0f, 0.7f); cb = Vec4(0.0f, 0.0f, 1.0f, 1.0f); break;
968                         case 1: ca = Vec4(0.0f, 1.0f, 0.5f, 0.5f); cb = Vec4(1.0f, 0.0f, 0.0f, 1.0f); break;
969                         case 2: ca = Vec4(0.7f, 0.0f, 1.0f, 0.3f); cb = Vec4(0.0f, 1.0f, 0.0f, 1.0f); break;
970                         case 3: ca = Vec4(0.0f, 0.3f, 1.0f, 1.0f); cb = Vec4(1.0f, 0.0f, 0.0f, 0.7f); break;
971                         case 4: ca = Vec4(1.0f, 0.0f, 0.5f, 1.0f); cb = Vec4(0.0f, 1.0f, 0.0f, 0.5f); break;
972                         case 5: ca = Vec4(0.7f, 1.0f, 0.0f, 1.0f); cb = Vec4(0.0f, 0.0f, 1.0f, 0.3f); break;
973                 }
974
975                 m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
976                 fillWithGrid(m_texture->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), 8, ca, cb);
977         }
978
979         // Upload data and setup params.
980         m_texture->upload();
981
982         gl.bindTexture  (GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
983         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,                wrapS);
984         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,                wrapT);
985         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,    minFilter);
986         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,    magFilter);
987         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
988
989         // Generate mipmap.
990         gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
991         gl.generateMipmap(GL_TEXTURE_CUBE_MAP);
992         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
993
994         // Render all levels.
995         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
996         {
997                 const int       levelWidth      = de::max(1, m_size >> levelNdx);
998                 const int       levelHeight     = de::max(1, m_size >> levelNdx);
999
1000                 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1001                 {
1002                         const RandomViewport    viewport        (m_renderCtx.getRenderTarget(), levelWidth*3, levelHeight*2, deStringHash(getName()) ^ deInt32Hash(levelNdx + faceNdx));
1003                         const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
1004
1005                         computeQuadTexCoordCube(texCoord, face);
1006
1007                         gl.viewport(viewport.x, viewport.y, levelWidth, levelHeight);
1008                         m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
1009
1010                         resultTexture.allocLevel(face, levelNdx);
1011                         glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevelFace(levelNdx, face));
1012                 }
1013         }
1014
1015         // Compare results
1016         {
1017                 const IVec4                     framebufferBits         = max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
1018                 const IVec4                     formatBits                      = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
1019                 const tcu::BVec4        formatMask                      = greaterThan(formatBits, IVec4(0));
1020                 const IVec4                     cmpBits                         = select(min(framebufferBits, formatBits), framebufferBits, formatMask);
1021                 GenMipmapPrecision      comparePrec;
1022
1023                 comparePrec.colorMask           = getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
1024                 comparePrec.colorThreshold      = tcu::computeFixedPointThreshold(cmpBits);
1025                 comparePrec.filterBits          = tcu::IVec3(4, 4, 0);
1026
1027                 const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
1028
1029                 m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS                             ? "Pass" :
1030                                                                                            compareResult == QP_TEST_RESULT_QUALITY_WARNING      ? "Low-quality method used"     :
1031                                                                                            compareResult == QP_TEST_RESULT_FAIL                         ? "Image comparison failed"     : "");
1032         }
1033
1034         return STOP;
1035 }
1036
1037 TextureMipmapTests::TextureMipmapTests (Context& context)
1038         : TestCaseGroup(context, "mipmap", "Mipmapping tests")
1039 {
1040 }
1041
1042 TextureMipmapTests::~TextureMipmapTests (void)
1043 {
1044 }
1045
1046 void TextureMipmapTests::init (void)
1047 {
1048         tcu::TestCaseGroup* group2D             = new tcu::TestCaseGroup(m_testCtx, "2d",       "2D Texture Mipmapping");
1049         tcu::TestCaseGroup*     groupCube       = new tcu::TestCaseGroup(m_testCtx, "cube",     "Cube Map Filtering");
1050         addChild(group2D);
1051         addChild(groupCube);
1052
1053         static const struct
1054         {
1055                 const char*             name;
1056                 deUint32                mode;
1057         } wrapModes[] =
1058         {
1059                 { "clamp",              GL_CLAMP_TO_EDGE },
1060                 { "repeat",             GL_REPEAT },
1061                 { "mirror",             GL_MIRRORED_REPEAT }
1062         };
1063
1064         static const struct
1065         {
1066                 const char*             name;
1067                 deUint32                mode;
1068         } minFilterModes[] =
1069         {
1070                 { "nearest_nearest",    GL_NEAREST_MIPMAP_NEAREST       },
1071                 { "linear_nearest",             GL_LINEAR_MIPMAP_NEAREST        },
1072                 { "nearest_linear",             GL_NEAREST_MIPMAP_LINEAR        },
1073                 { "linear_linear",              GL_LINEAR_MIPMAP_LINEAR         }
1074         };
1075
1076         static const struct
1077         {
1078                 CoordType               type;
1079                 const char*             name;
1080                 const char*             desc;
1081         } coordTypes[] =
1082         {
1083                 { COORDTYPE_BASIC,              "basic",                "Mipmapping with translated and scaled coordinates" },
1084                 { COORDTYPE_AFFINE,             "affine",               "Mipmapping with affine coordinate transform"           },
1085                 { COORDTYPE_PROJECTED,  "projected",    "Mipmapping with perspective projection"                        }
1086         };
1087
1088         static const struct
1089         {
1090                 const char*             name;
1091                 deUint32                format;
1092                 deUint32                dataType;
1093         } formats[] =
1094         {
1095                 { "a8",                 GL_ALPHA,                       GL_UNSIGNED_BYTE },
1096                 { "l8",                 GL_LUMINANCE,           GL_UNSIGNED_BYTE },
1097                 { "la88",               GL_LUMINANCE_ALPHA,     GL_UNSIGNED_BYTE },
1098                 { "rgb565",             GL_RGB,                         GL_UNSIGNED_SHORT_5_6_5 },
1099                 { "rgb888",             GL_RGB,                         GL_UNSIGNED_BYTE },
1100                 { "rgba4444",   GL_RGBA,                        GL_UNSIGNED_SHORT_4_4_4_4 },
1101                 { "rgba5551",   GL_RGBA,                        GL_UNSIGNED_SHORT_5_5_5_1 },
1102                 { "rgba8888",   GL_RGBA,                        GL_UNSIGNED_BYTE }
1103         };
1104
1105         static const struct
1106         {
1107                 const char*             name;
1108                 deUint32                hint;
1109         } genHints[] =
1110         {
1111                 { "fastest",    GL_FASTEST },
1112                 { "nicest",             GL_NICEST }
1113         };
1114
1115         static const struct
1116         {
1117                 const char*             name;
1118                 int                             width;
1119                 int                             height;
1120         } tex2DSizes[] =
1121         {
1122                 { DE_NULL,              64, 64 }, // Default.
1123                 { "non_square", 32, 64 }
1124         };
1125
1126         // 2D cases.
1127         for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
1128         {
1129                 tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
1130                 group2D->addChild(coordTypeGroup);
1131
1132                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1133                 {
1134                         for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
1135                         {
1136                                 // Add non_square variants to basic cases only.
1137                                 int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
1138
1139                                 for (int size = 0; size < sizeEnd; size++)
1140                                 {
1141                                         std::ostringstream name;
1142                                         name << minFilterModes[minFilter].name
1143                                                  << "_" << wrapModes[wrapMode].name;
1144
1145                                         if (tex2DSizes[size].name)
1146                                                 name << "_" << tex2DSizes[size].name;
1147
1148                                         coordTypeGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1149                                                                                                                                          name.str().c_str(), "",
1150                                                                                                                                          coordTypes[coordType].type,
1151                                                                                                                                          minFilterModes[minFilter].mode,
1152                                                                                                                                          wrapModes[wrapMode].mode,
1153                                                                                                                                          wrapModes[wrapMode].mode,
1154                                                                                                                                          GL_RGBA, GL_UNSIGNED_BYTE,
1155                                                                                                                                          tex2DSizes[size].width, tex2DSizes[size].height));
1156                                 }
1157                         }
1158                 }
1159         }
1160
1161         // 2D bias variants.
1162         {
1163                 tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
1164                 group2D->addChild(biasGroup);
1165
1166                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1167                         biasGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1168                                                                                                                 minFilterModes[minFilter].name, "",
1169                                                                                                                 COORDTYPE_BASIC_BIAS,
1170                                                                                                                 minFilterModes[minFilter].mode,
1171                                                                                                                 GL_REPEAT, GL_REPEAT,
1172                                                                                                                 GL_RGBA, GL_UNSIGNED_BYTE,
1173                                                                                                                 tex2DSizes[0].width, tex2DSizes[0].height));
1174         }
1175
1176         // 2D mipmap generation variants.
1177         {
1178                 tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1179                 group2D->addChild(genMipmapGroup);
1180
1181                 for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1182                 {
1183                         for (int size = 0; size < DE_LENGTH_OF_ARRAY(tex2DSizes); size++)
1184                         {
1185                                 for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1186                                 {
1187                                         std::ostringstream name;
1188                                         name << formats[format].name;
1189
1190                                         if (tex2DSizes[size].name)
1191                                                 name << "_" << tex2DSizes[size].name;
1192
1193                                         name << "_" << genHints[hint].name;
1194
1195                                         genMipmapGroup->addChild(new Texture2DGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
1196                                                                                                                                                 formats[format].format, formats[format].dataType, genHints[hint].hint,
1197                                                                                                                                                 tex2DSizes[size].width, tex2DSizes[size].height));
1198                                 }
1199                         }
1200                 }
1201         }
1202
1203         const int cubeMapSize = 64;
1204
1205         static const struct
1206         {
1207                 CoordType               type;
1208                 const char*             name;
1209                 const char*             desc;
1210         } cubeCoordTypes[] =
1211         {
1212                 { COORDTYPE_BASIC,              "basic",                "Mipmapping with translated and scaled coordinates" },
1213                 { COORDTYPE_PROJECTED,  "projected",    "Mipmapping with perspective projection"                        },
1214                 { COORDTYPE_BASIC_BIAS, "bias",                 "User-supplied bias value"                                                      }
1215         };
1216
1217         // Cubemap cases.
1218         for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
1219         {
1220                 tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc);
1221                 groupCube->addChild(coordTypeGroup);
1222
1223                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
1224                 {
1225                         coordTypeGroup->addChild(new TextureCubeMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
1226                                                                                                                            minFilterModes[minFilter].name, "",
1227                                                                                                                            cubeCoordTypes[coordType].type,
1228                                                                                                                            minFilterModes[minFilter].mode,
1229                                                                                                                            GL_CLAMP_TO_EDGE,
1230                                                                                                                            GL_CLAMP_TO_EDGE,
1231                                                                                                                            GL_RGBA, GL_UNSIGNED_BYTE, cubeMapSize));
1232                 }
1233         }
1234
1235         // Cubemap mipmap generation variants.
1236         {
1237                 tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
1238                 groupCube->addChild(genMipmapGroup);
1239
1240                 for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
1241                 {
1242                         for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
1243                         {
1244                                 std::ostringstream name;
1245                                 name << formats[format].name
1246                                          << "_" << genHints[hint].name;
1247
1248                                 genMipmapGroup->addChild(new TextureCubeGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", formats[format].format, formats[format].dataType, genHints[hint].hint, cubeMapSize));
1249                         }
1250                 }
1251         }
1252 }
1253
1254 } // Functional
1255 } // gles2
1256 } // deqp