4409631058b1997373980c085d3664fe15d13739
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fTextureMipmapTests.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 Mipmapping tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fTextureMipmapTests.hpp"
25
26 #include "glsTextureTestUtil.hpp"
27 #include "gluTexture.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "tcuTextureUtil.hpp"
31 #include "tcuMatrix.hpp"
32 #include "tcuMatrixUtil.hpp"
33 #include "tcuTexLookupVerifier.hpp"
34 #include "tcuVectorUtil.hpp"
35 #include "deStringUtil.hpp"
36 #include "deRandom.hpp"
37 #include "deString.h"
38 #include "glwFunctions.hpp"
39 #include "glwEnums.hpp"
40
41 using std::vector;
42 using std::string;
43 using namespace deqp::gls;
44
45 namespace deqp
46 {
47 namespace gles3
48 {
49 namespace Functional
50 {
51
52 using std::string;
53 using std::vector;
54 using tcu::TestLog;
55 using tcu::Vec2;
56 using tcu::Vec3;
57 using tcu::Vec4;
58 using tcu::IVec4;
59 using namespace gls::TextureTestUtil;
60 using namespace glu::TextureTestUtil;
61
62 static float getMinLodForCell (int cellNdx)
63 {
64         static const float s_values[] =
65         {
66                 1.0f,
67                 3.5f,
68                 2.0f,
69                 -2.0f,
70                 0.0f,
71                 3.0f,
72                 10.0f,
73                 4.8f,
74                 5.8f,
75                 5.7f,
76                 -1.9f,
77                 4.0f,
78                 6.5f,
79                 7.1f,
80                 -1e10,
81                 1000.f
82         };
83         return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
84 }
85
86 static float getMaxLodForCell (int cellNdx)
87 {
88         static const float s_values[] =
89         {
90                 0.0f,
91                 0.2f,
92                 0.7f,
93                 0.4f,
94                 1.3f,
95                 0.0f,
96                 0.5f,
97                 1.2f,
98                 -2.0f,
99                 1.0f,
100                 0.1f,
101                 0.3f,
102                 2.7f,
103                 1.2f,
104                 10.0f,
105                 -1000.f,
106                 1e10f
107         };
108         return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
109 }
110
111 enum CoordType
112 {
113         COORDTYPE_BASIC,                //!< texCoord = translateScale(position).
114         COORDTYPE_BASIC_BIAS,   //!< Like basic, but with bias values.
115         COORDTYPE_AFFINE,               //!< texCoord = translateScaleRotateShear(position).
116         COORDTYPE_PROJECTED,    //!< Projected coordinates, w != 1
117
118         COORDTYPE_LAST
119 };
120
121 // Texture2DMipmapCase
122
123 class Texture2DMipmapCase : public tcu::TestCase
124 {
125 public:
126
127                                                                 Texture2DMipmapCase                     (tcu::TestContext&                      testCtx,
128                                                                                                                          glu::RenderContext&            renderCtx,
129                                                                                                                          const glu::ContextInfo&        renderCtxInfo,
130                                                                                                                          const char*                            name,
131                                                                                                                          const char*                            desc,
132                                                                                                                          CoordType                                      coordType,
133                                                                                                                          deUint32                                       minFilter,
134                                                                                                                          deUint32                                       wrapS,
135                                                                                                                          deUint32                                       wrapT,
136                                                                                                                          deUint32                                       format,
137                                                                                                                          deUint32                                       dataType,
138                                                                                                                          int                                            width,
139                                                                                                                          int                                            height);
140                                                                 ~Texture2DMipmapCase            (void);
141
142         void                                            init                                            (void);
143         void                                            deinit                                          (void);
144         IterateResult                           iterate                                         (void);
145
146 private:
147                                                                 Texture2DMipmapCase                     (const Texture2DMipmapCase& other);
148         Texture2DMipmapCase&            operator=                                       (const Texture2DMipmapCase& other);
149
150         glu::RenderContext&                     m_renderCtx;
151         const glu::ContextInfo&         m_renderCtxInfo;
152
153         CoordType                                       m_coordType;
154         deUint32                                        m_minFilter;
155         deUint32                                        m_wrapS;
156         deUint32                                        m_wrapT;
157         deUint32                                        m_format;
158         deUint32                                        m_dataType;
159         int                                                     m_width;
160         int                                                     m_height;
161
162         glu::Texture2D*                         m_texture;
163         TextureRenderer                         m_renderer;
164 };
165
166 Texture2DMipmapCase::Texture2DMipmapCase (tcu::TestContext&                     testCtx,
167                                                                                   glu::RenderContext&           renderCtx,
168                                                                                   const glu::ContextInfo&       renderCtxInfo,
169                                                                                   const char*                           name,
170                                                                                   const char*                           desc,
171                                                                                   CoordType                                     coordType,
172                                                                                   deUint32                                      minFilter,
173                                                                                   deUint32                                      wrapS,
174                                                                                   deUint32                                      wrapT,
175                                                                                   deUint32                                      format,
176                                                                                   deUint32                                      dataType,
177                                                                                   int                                           width,
178                                                                                   int                                           height)
179         : TestCase                      (testCtx, name, desc)
180         , m_renderCtx           (renderCtx)
181         , m_renderCtxInfo       (renderCtxInfo)
182         , m_coordType           (coordType)
183         , m_minFilter           (minFilter)
184         , m_wrapS                       (wrapS)
185         , m_wrapT                       (wrapT)
186         , m_format                      (format)
187         , m_dataType            (dataType)
188         , m_width                       (width)
189         , m_height                      (height)
190         , m_texture                     (DE_NULL)
191         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
192 {
193 }
194
195 Texture2DMipmapCase::~Texture2DMipmapCase (void)
196 {
197         deinit();
198 }
199
200 void Texture2DMipmapCase::init (void)
201 {
202         if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
203                 throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
204
205         m_texture = new glu::Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
206
207         int numLevels = deLog2Floor32(de::max(m_width, m_height))+1;
208
209         // Fill texture with colored grid.
210         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
211         {
212                 deUint32        step            = 0xff / (numLevels-1);
213                 deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
214                 deUint32        dec                     = 0xff - inc;
215                 deUint32        rgb                     = (inc << 16) | (dec << 8) | 0xff;
216                 deUint32        color           = 0xff000000 | rgb;
217
218                 m_texture->getRefTexture().allocLevel(levelNdx);
219                 tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec());
220         }
221 }
222
223 void Texture2DMipmapCase::deinit (void)
224 {
225         delete m_texture;
226         m_texture = DE_NULL;
227
228         m_renderer.clear();
229 }
230
231 static void getBasicTexCoord2D (std::vector<float>& dst, int cellNdx)
232 {
233         static const struct
234         {
235                 Vec2 bottomLeft;
236                 Vec2 topRight;
237         } s_basicCoords[] =
238         {
239                 { Vec2(-0.1f,  0.1f), Vec2( 0.8f,  1.0f) },
240                 { Vec2(-0.3f, -0.6f), Vec2( 0.7f,  0.4f) },
241                 { Vec2(-0.3f,  0.6f), Vec2( 0.7f, -0.9f) },
242                 { Vec2(-0.8f,  0.6f), Vec2( 0.7f, -0.9f) },
243
244                 { Vec2(-0.5f, -0.5f), Vec2( 1.5f,  1.5f) },
245                 { Vec2( 1.0f, -1.0f), Vec2(-1.3f,  1.0f) },
246                 { Vec2( 1.2f, -1.0f), Vec2(-1.3f,  1.6f) },
247                 { Vec2( 2.2f, -1.1f), Vec2(-1.3f,  0.8f) },
248
249                 { Vec2(-1.5f,  1.6f), Vec2( 1.7f, -1.4f) },
250                 { Vec2( 2.0f,  1.6f), Vec2( 2.3f, -1.4f) },
251                 { Vec2( 1.3f, -2.6f), Vec2(-2.7f,  2.9f) },
252                 { Vec2(-0.8f, -6.6f), Vec2( 6.0f, -0.9f) },
253
254                 { Vec2( -8.0f,   9.0f), Vec2(  8.3f,  -7.0f) },
255                 { Vec2(-16.0f,  10.0f), Vec2( 18.3f,  24.0f) },
256                 { Vec2( 30.2f,  55.0f), Vec2(-24.3f,  -1.6f) },
257                 { Vec2(-33.2f,  64.1f), Vec2( 32.1f, -64.1f) },
258         };
259
260         DE_ASSERT(de::inBounds(cellNdx, 0, DE_LENGTH_OF_ARRAY(s_basicCoords)));
261
262         const Vec2& bottomLeft  = s_basicCoords[cellNdx].bottomLeft;
263         const Vec2& topRight    = s_basicCoords[cellNdx].topRight;
264
265         computeQuadTexCoord2D(dst, bottomLeft, topRight);
266 }
267
268 static void getAffineTexCoord2D (std::vector<float>& dst, int cellNdx)
269 {
270         // Use basic coords as base.
271         getBasicTexCoord2D(dst, cellNdx);
272
273         // Rotate based on cell index.
274         float           angle           = 2.0f*DE_PI * ((float)cellNdx / 16.0f);
275         tcu::Mat2       rotMatrix       = tcu::rotationMatrix(angle);
276
277         // Second and third row are sheared.
278         float           shearX          = de::inRange(cellNdx, 4, 11) ? (float)(15-cellNdx) / 16.0f : 0.0f;
279         tcu::Mat2       shearMatrix     = tcu::shearMatrix(tcu::Vec2(shearX, 0.0f));
280
281         tcu::Mat2       transform       = rotMatrix * shearMatrix;
282         Vec2            p0                      = transform * Vec2(dst[0], dst[1]);
283         Vec2            p1                      = transform * Vec2(dst[2], dst[3]);
284         Vec2            p2                      = transform * Vec2(dst[4], dst[5]);
285         Vec2            p3                      = transform * Vec2(dst[6], dst[7]);
286
287         dst[0] = p0.x();        dst[1] = p0.y();
288         dst[2] = p1.x();        dst[3] = p1.y();
289         dst[4] = p2.x();        dst[5] = p2.y();
290         dst[6] = p3.x();        dst[7] = p3.y();
291 }
292
293 Texture2DMipmapCase::IterateResult Texture2DMipmapCase::iterate (void)
294 {
295         const glw::Functions&           gl                                      = m_renderCtx.getFunctions();
296
297         const tcu::Texture2D&           refTexture                      = m_texture->getRefTexture();
298
299         const deUint32                          magFilter                       = GL_NEAREST;
300         const int                                       texWidth                        = refTexture.getWidth();
301         const int                                       texHeight                       = refTexture.getHeight();
302         const int                                       defViewportWidth        = texWidth*4;
303         const int                                       defViewportHeight       = texHeight*4;
304
305         const RandomViewport            viewport                        (m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
306         ReferenceParams                         sampleParams            (TEXTURETYPE_2D);
307         vector<float>                           texCoord;
308
309         const bool                                      isProjected                     = m_coordType == COORDTYPE_PROJECTED;
310         const bool                                      useLodBias                      = m_coordType == COORDTYPE_BASIC_BIAS;
311
312         tcu::Surface                            renderedFrame           (viewport.width, viewport.height);
313
314         // Viewport is divided into 4x4 grid.
315         int                                                     gridWidth                       = 4;
316         int                                                     gridHeight                      = 4;
317         int                                                     cellWidth                       = viewport.width / gridWidth;
318         int                                                     cellHeight                      = viewport.height / gridHeight;
319
320         // Bail out if rendertarget is too small.
321         if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
322                 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
323
324         // Sampling parameters.
325         sampleParams.sampler            = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
326         sampleParams.samplerType        = glu::TextureTestUtil::getSamplerType(m_texture->getRefTexture().getFormat());
327         sampleParams.flags                      = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
328         sampleParams.lodMode            = LODMODE_EXACT; // Use ideal lod.
329
330         // Upload texture data.
331         m_texture->upload();
332
333         // Bind gradient texture and setup sampler parameters.
334         gl.bindTexture  (GL_TEXTURE_2D, m_texture->getGLTexture());
335         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,              m_wrapS);
336         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,              m_wrapT);
337         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,  m_minFilter);
338         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,  magFilter);
339
340         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
341
342         // Bias values.
343         static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
344
345         // Projection values.
346         static const Vec4 s_projections[] =
347         {
348                 Vec4(1.2f, 1.0f, 0.7f, 1.0f),
349                 Vec4(1.3f, 0.8f, 0.6f, 2.0f),
350                 Vec4(0.8f, 1.0f, 1.7f, 0.6f),
351                 Vec4(1.2f, 1.0f, 1.7f, 1.5f)
352         };
353
354         // Render cells.
355         for (int gridY = 0; gridY < gridHeight; gridY++)
356         {
357                 for (int gridX = 0; gridX < gridWidth; gridX++)
358                 {
359                         const int               curX            = cellWidth*gridX;
360                         const int               curY            = cellHeight*gridY;
361                         const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
362                         const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
363                         const int               cellNdx         = gridY*gridWidth + gridX;
364
365                         // Compute texcoord.
366                         switch (m_coordType)
367                         {
368                                 case COORDTYPE_BASIC_BIAS:      // Fall-through.
369                                 case COORDTYPE_PROJECTED:
370                                 case COORDTYPE_BASIC:           getBasicTexCoord2D      (texCoord, cellNdx);    break;
371                                 case COORDTYPE_AFFINE:          getAffineTexCoord2D     (texCoord, cellNdx);    break;
372                                 default:                                        DE_ASSERT(DE_FALSE);
373                         }
374
375                         if (isProjected)
376                                 sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
377
378                         if (useLodBias)
379                                 sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
380
381                         // Render with GL.
382                         gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
383                         m_renderer.renderQuad(0, &texCoord[0], sampleParams);
384                 }
385         }
386
387         // Read result.
388         glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
389
390         // Compare and log.
391         {
392                 const tcu::PixelFormat& pixelFormat             = m_renderCtx.getRenderTarget().getPixelFormat();
393                 const bool                              isTrilinear             = m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
394                 tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
395                 tcu::Surface                    errorMask               (viewport.width, viewport.height);
396                 tcu::LookupPrecision    lookupPrec;
397                 tcu::LodPrecision               lodPrec                 (tcu::LodPrecision::RULE_OPENGL);
398                 int                                             numFailedPixels = 0;
399
400                 lookupPrec.coordBits            = tcu::IVec3(20, 20, 0);
401                 lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
402                 lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
403                 lookupPrec.colorMask            = getCompareMask(pixelFormat);
404                 lodPrec.derivateBits            = 10;
405                 lodPrec.lodBits                         = isProjected ? 6 : 8;
406
407                 for (int gridY = 0; gridY < gridHeight; gridY++)
408                 {
409                         for (int gridX = 0; gridX < gridWidth; gridX++)
410                         {
411                                 const int               curX            = cellWidth*gridX;
412                                 const int               curY            = cellHeight*gridY;
413                                 const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
414                                 const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
415                                 const int               cellNdx         = gridY*gridWidth + gridX;
416
417                                 // Compute texcoord.
418                                 switch (m_coordType)
419                                 {
420                                         case COORDTYPE_BASIC_BIAS:      // Fall-through.
421                                         case COORDTYPE_PROJECTED:
422                                         case COORDTYPE_BASIC:           getBasicTexCoord2D      (texCoord, cellNdx);    break;
423                                         case COORDTYPE_AFFINE:          getAffineTexCoord2D     (texCoord, cellNdx);    break;
424                                         default:                                        DE_ASSERT(DE_FALSE);
425                                 }
426
427                                 if (isProjected)
428                                         sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
429
430                                 if (useLodBias)
431                                         sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
432
433                                 // Render ideal result
434                                 sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
435                                                           refTexture, &texCoord[0], sampleParams);
436
437                                 // Compare this cell
438                                 numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
439                                                                                                                         tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
440                                                                                                                         tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
441                                                                                                                         m_texture->getRefTexture(), &texCoord[0], sampleParams,
442                                                                                                                         lookupPrec, lodPrec, m_testCtx.getWatchDog());
443                         }
444                 }
445
446                 if (numFailedPixels > 0)
447                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
448
449                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
450                                                         << TestLog::Image("Rendered", "Rendered image", renderedFrame);
451
452                 if (numFailedPixels > 0)
453                 {
454                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
455                                                                 << TestLog::Image("ErrorMask", "Error mask", errorMask);
456                 }
457
458                 m_testCtx.getLog() << TestLog::EndImageSet;
459
460                 {
461                         const bool isOk = numFailedPixels == 0;
462                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
463                                                                         isOk ? "Pass"                           : "Image verification failed");
464                 }
465         }
466
467         return STOP;
468 }
469
470 // TextureCubeMipmapCase
471
472 class TextureCubeMipmapCase : public tcu::TestCase
473 {
474 public:
475
476                                                                 TextureCubeMipmapCase           (tcu::TestContext&                      testCtx,
477                                                                                                                          glu::RenderContext&            renderCtx,
478                                                                                                                          const glu::ContextInfo&        renderCtxInfo,
479                                                                                                                          const char*                            name,
480                                                                                                                          const char*                            desc,
481                                                                                                                          CoordType                                      coordType,
482                                                                                                                          deUint32                                       minFilter,
483                                                                                                                          deUint32                                       wrapS,
484                                                                                                                          deUint32                                       wrapT,
485                                                                                                                          deUint32                                       format,
486                                                                                                                          deUint32                                       dataType,
487                                                                                                                          int                                            size);
488                                                                 ~TextureCubeMipmapCase          (void);
489
490         void                                            init                                            (void);
491         void                                            deinit                                          (void);
492         IterateResult                           iterate                                         (void);
493
494 private:
495                                                                 TextureCubeMipmapCase           (const TextureCubeMipmapCase& other);
496         TextureCubeMipmapCase&          operator=                                       (const TextureCubeMipmapCase& other);
497
498         glu::RenderContext&                     m_renderCtx;
499         const glu::ContextInfo&         m_renderCtxInfo;
500
501         CoordType                                       m_coordType;
502         deUint32                                        m_minFilter;
503         deUint32                                        m_wrapS;
504         deUint32                                        m_wrapT;
505         deUint32                                        m_format;
506         deUint32                                        m_dataType;
507         int                                                     m_size;
508
509         glu::TextureCube*                       m_texture;
510         TextureRenderer                         m_renderer;
511 };
512
513 TextureCubeMipmapCase::TextureCubeMipmapCase (tcu::TestContext&                 testCtx,
514                                                                                           glu::RenderContext&           renderCtx,
515                                                                                           const glu::ContextInfo&       renderCtxInfo,
516                                                                                           const char*                           name,
517                                                                                           const char*                           desc,
518                                                                                           CoordType                                     coordType,
519                                                                                           deUint32                                      minFilter,
520                                                                                           deUint32                                      wrapS,
521                                                                                           deUint32                                      wrapT,
522                                                                                           deUint32                                      format,
523                                                                                           deUint32                                      dataType,
524                                                                                           int                                           size)
525         : TestCase                      (testCtx, name, desc)
526         , m_renderCtx           (renderCtx)
527         , m_renderCtxInfo       (renderCtxInfo)
528         , m_coordType           (coordType)
529         , m_minFilter           (minFilter)
530         , m_wrapS                       (wrapS)
531         , m_wrapT                       (wrapT)
532         , m_format                      (format)
533         , m_dataType            (dataType)
534         , m_size                        (size)
535         , m_texture                     (DE_NULL)
536         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
537 {
538 }
539
540 TextureCubeMipmapCase::~TextureCubeMipmapCase (void)
541 {
542         deinit();
543 }
544
545 void TextureCubeMipmapCase::init (void)
546 {
547         if (m_coordType == COORDTYPE_PROJECTED && m_renderCtx.getRenderTarget().getNumSamples() > 0)
548                 throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
549
550         m_texture = new glu::TextureCube(m_renderCtx, m_format, m_dataType, m_size);
551
552         int numLevels = deLog2Floor32(m_size)+1;
553
554         // Fill texture with colored grid.
555         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
556         {
557                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
558                 {
559                         deUint32        step            = 0xff / (numLevels-1);
560                         deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
561                         deUint32        dec                     = 0xff - inc;
562                         deUint32        rgb                     = 0;
563
564                         switch (faceNdx)
565                         {
566                                 case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
567                                 case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
568                                 case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
569                                 case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
570                                 case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
571                                 case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
572                         }
573
574                         deUint32        color           = 0xff000000 | rgb;
575
576                         m_texture->getRefTexture().allocLevel((tcu::CubeFace)faceNdx, levelNdx);
577                         tcu::clear(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
578                 }
579         }
580 }
581
582 void TextureCubeMipmapCase::deinit (void)
583 {
584         delete m_texture;
585         m_texture = DE_NULL;
586
587         m_renderer.clear();
588 }
589
590 static void randomPartition (vector<IVec4>& dst, de::Random& rnd, int x, int y, int width, int height)
591 {
592         const int minWidth      = 8;
593         const int minHeight     = 8;
594
595         bool    partition               = rnd.getFloat() > 0.4f;
596         bool    partitionX              = partition && width > minWidth && rnd.getBool();
597         bool    partitionY              = partition && height > minHeight && !partitionX;
598
599         if (partitionX)
600         {
601                 int split = width/2 + rnd.getInt(-width/4, +width/4);
602                 randomPartition(dst, rnd, x, y, split, height);
603                 randomPartition(dst, rnd, x+split, y, width-split, height);
604         }
605         else if (partitionY)
606         {
607                 int split = height/2 + rnd.getInt(-height/4, +height/4);
608                 randomPartition(dst, rnd, x, y, width, split);
609                 randomPartition(dst, rnd, x, y+split, width, height-split);
610         }
611         else
612                 dst.push_back(IVec4(x, y, width, height));
613 }
614
615 static void computeGridLayout (vector<IVec4>& dst, int width, int height)
616 {
617         de::Random rnd(7);
618         randomPartition(dst, rnd, 0, 0, width, height);
619 }
620
621 TextureCubeMipmapCase::IterateResult TextureCubeMipmapCase::iterate (void)
622 {
623         const deUint32                  magFilter                       = GL_NEAREST;
624         const int                               texWidth                        = m_texture->getRefTexture().getSize();
625         const int                               texHeight                       = m_texture->getRefTexture().getSize();
626         const int                               defViewportWidth        = texWidth*2;
627         const int                               defViewportHeight       = texHeight*2;
628
629         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
630         const RandomViewport    viewport                        (m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
631
632         const bool                              isProjected                     = m_coordType == COORDTYPE_PROJECTED;
633         const bool                              useLodBias                      = m_coordType == COORDTYPE_BASIC_BIAS;
634
635         vector<float>                   texCoord;
636         tcu::Surface                    renderedFrame           (viewport.width, viewport.height);
637
638         // Bail out if rendertarget is too small.
639         if (viewport.width < defViewportWidth/2 || viewport.height < defViewportHeight/2)
640                 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
641
642         // Upload texture data.
643         m_texture->upload();
644
645         // Bind gradient texture and setup sampler parameters.
646         gl.bindTexture  (GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
647         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,                m_wrapS);
648         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,                m_wrapT);
649         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,    m_minFilter);
650         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,    magFilter);
651
652         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
653
654         // Compute grid.
655         vector<IVec4> gridLayout;
656         computeGridLayout(gridLayout, viewport.width, viewport.height);
657
658         // Bias values.
659         static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
660
661         // Projection values \note Less agressive than in 2D case due to smaller quads.
662         static const Vec4 s_projections[] =
663         {
664                 Vec4(1.2f, 1.0f, 0.7f, 1.0f),
665                 Vec4(1.3f, 0.8f, 0.6f, 1.1f),
666                 Vec4(0.8f, 1.0f, 1.2f, 0.8f),
667                 Vec4(1.2f, 1.0f, 1.3f, 0.9f)
668         };
669
670         // Render with GL
671         for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
672         {
673                 const int                       curX            = gridLayout[cellNdx].x();
674                 const int                       curY            = gridLayout[cellNdx].y();
675                 const int                       curW            = gridLayout[cellNdx].z();
676                 const int                       curH            = gridLayout[cellNdx].w();
677                 const tcu::CubeFace     cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
678                 RenderParams            params          (TEXTURETYPE_CUBE);
679
680                 DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
681                 computeQuadTexCoordCube(texCoord, cubeFace);
682
683                 if (isProjected)
684                 {
685                         params.flags    |= ReferenceParams::PROJECTED;
686                         params.w                 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
687                 }
688
689                 if (useLodBias)
690                 {
691                         params.flags    |= ReferenceParams::USE_BIAS;
692                         params.bias              = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
693                 }
694
695                 // Render with GL.
696                 gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
697                 m_renderer.renderQuad(0, &texCoord[0], params);
698         }
699         GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
700
701         // Read result.
702         glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
703         GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
704
705         // Render reference and compare
706         {
707                 tcu::Surface                    referenceFrame          (viewport.width, viewport.height);
708                 tcu::Surface                    errorMask                       (viewport.width, viewport.height);
709                 int                                             numFailedPixels         = 0;
710                 ReferenceParams                 params                          (TEXTURETYPE_CUBE);
711                 tcu::LookupPrecision    lookupPrec;
712                 tcu::LodPrecision               lodPrec                         (tcu::LodPrecision::RULE_OPENGL);
713
714                 // Params for rendering reference
715                 params.sampler                                  = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, magFilter);
716                 params.sampler.seamlessCubeMap  = true;
717                 params.lodMode                                  = LODMODE_EXACT;
718
719                 // Comparison parameters
720                 lookupPrec.colorMask                    = getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
721                 lookupPrec.colorThreshold               = tcu::computeFixedPointThreshold(max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0)));
722                 lookupPrec.coordBits                    = isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
723                 lookupPrec.uvwBits                              = tcu::IVec3(5,5,0);
724                 lodPrec.derivateBits                    = 10;
725                 lodPrec.lodBits                                 = isProjected ? 3 : 6;
726
727                 for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
728                 {
729                         const int                               curX            = gridLayout[cellNdx].x();
730                         const int                               curY            = gridLayout[cellNdx].y();
731                         const int                               curW            = gridLayout[cellNdx].z();
732                         const int                               curH            = gridLayout[cellNdx].w();
733                         const tcu::CubeFace             cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
734
735                         DE_ASSERT(m_coordType != COORDTYPE_AFFINE); // Not supported.
736                         computeQuadTexCoordCube(texCoord, cubeFace);
737
738                         if (isProjected)
739                         {
740                                 params.flags    |= ReferenceParams::PROJECTED;
741                                 params.w                 = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
742                         }
743
744                         if (useLodBias)
745                         {
746                                 params.flags    |= ReferenceParams::USE_BIAS;
747                                 params.bias              = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
748                         }
749
750                         // Render ideal reference.
751                         {
752                                 tcu::SurfaceAccess idealDst(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), curX, curY, curW, curH);
753                                 sampleTexture(idealDst, m_texture->getRefTexture(), &texCoord[0], params);
754                         }
755
756                         // Compare this cell
757                         numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
758                                                                                                                 tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
759                                                                                                                 tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
760                                                                                                                 m_texture->getRefTexture(), &texCoord[0], params,
761                                                                                                                 lookupPrec, lodPrec, m_testCtx.getWatchDog());
762                 }
763
764                 if (numFailedPixels > 0)
765                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
766
767                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
768                                                    << TestLog::Image("Rendered", "Rendered image", renderedFrame);
769
770                 if (numFailedPixels > 0)
771                 {
772                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
773                                                            << TestLog::Image("ErrorMask", "Error mask", errorMask);
774                 }
775
776                 m_testCtx.getLog() << TestLog::EndImageSet;
777
778                 {
779                         const bool isOk = numFailedPixels == 0;
780                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
781                                                                         isOk ? "Pass"                           : "Image verification failed");
782                 }
783         }
784
785         return STOP;
786 }
787
788 // Texture2DGenMipmapCase
789
790 class Texture2DGenMipmapCase : public tcu::TestCase
791 {
792 public:
793
794                                                                 Texture2DGenMipmapCase          (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height);
795                                                                 ~Texture2DGenMipmapCase         (void);
796
797         void                                            init                                            (void);
798         void                                            deinit                                          (void);
799         IterateResult                           iterate                                         (void);
800
801 private:
802                                                                 Texture2DGenMipmapCase          (const Texture2DGenMipmapCase& other);
803         Texture2DGenMipmapCase&         operator=                                       (const Texture2DGenMipmapCase& other);
804
805         glu::RenderContext&                     m_renderCtx;
806
807         deUint32                                        m_format;
808         deUint32                                        m_dataType;
809         deUint32                                        m_hint;
810         int                                                     m_width;
811         int                                                     m_height;
812
813         glu::Texture2D*                         m_texture;
814         TextureRenderer                         m_renderer;
815 };
816
817 Texture2DGenMipmapCase::Texture2DGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int width, int height)
818         : TestCase                      (testCtx, name, desc)
819         , m_renderCtx           (renderCtx)
820         , m_format                      (format)
821         , m_dataType            (dataType)
822         , m_hint                        (hint)
823         , m_width                       (width)
824         , m_height                      (height)
825         , m_texture                     (DE_NULL)
826         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
827 {
828 }
829
830 Texture2DGenMipmapCase::~Texture2DGenMipmapCase (void)
831 {
832         deinit();
833 }
834
835 void Texture2DGenMipmapCase::init (void)
836 {
837         DE_ASSERT(!m_texture);
838         m_texture = new glu::Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
839 }
840
841 void Texture2DGenMipmapCase::deinit (void)
842 {
843         delete m_texture;
844         m_texture = DE_NULL;
845
846         m_renderer.clear();
847 }
848
849 Texture2DGenMipmapCase::IterateResult Texture2DGenMipmapCase::iterate (void)
850 {
851         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
852
853         const deUint32                  minFilter                       = GL_NEAREST_MIPMAP_NEAREST;
854         const deUint32                  magFilter                       = GL_NEAREST;
855         const deUint32                  wrapS                           = GL_CLAMP_TO_EDGE;
856         const deUint32                  wrapT                           = GL_CLAMP_TO_EDGE;
857
858         const int                               numLevels                       = deLog2Floor32(de::max(m_width, m_height))+1;
859
860         tcu::Texture2D                  resultTexture           (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_texture->getRefTexture().getWidth(), m_texture->getRefTexture().getHeight());
861
862         vector<float>                   texCoord;
863
864         // Initialize texture level 0 with colored grid.
865         m_texture->getRefTexture().allocLevel(0);
866         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));
867
868         // Upload data and setup params.
869         m_texture->upload();
870
871         gl.bindTexture  (GL_TEXTURE_2D, m_texture->getGLTexture());
872         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,              wrapS);
873         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,              wrapT);
874         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,  minFilter);
875         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,  magFilter);
876         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
877
878         // Generate mipmap.
879         gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
880         gl.generateMipmap(GL_TEXTURE_2D);
881         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
882
883         // Use (0, 0) -> (1, 1) texture coordinates.
884         computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
885
886         // Fetch resulting texture by rendering.
887         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
888         {
889                 const int                               levelWidth              = de::max(1, m_width >> levelNdx);
890                 const int                               levelHeight             = de::max(1, m_height >> levelNdx);
891                 const RandomViewport    viewport                (m_renderCtx.getRenderTarget(), levelWidth, levelHeight, deStringHash(getName()) + levelNdx);
892
893                 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
894                 m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
895
896                 resultTexture.allocLevel(levelNdx);
897                 glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevel(levelNdx));
898         }
899
900         // Compare results
901         {
902                 const IVec4                     framebufferBits         = max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
903                 const IVec4                     formatBits                      = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
904                 const tcu::BVec4        formatMask                      = greaterThan(formatBits, IVec4(0));
905                 const IVec4                     cmpBits                         = select(min(framebufferBits, formatBits), framebufferBits, formatMask);
906                 GenMipmapPrecision      comparePrec;
907
908                 comparePrec.colorMask           = getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
909                 comparePrec.colorThreshold      = tcu::computeFixedPointThreshold(cmpBits);
910                 comparePrec.filterBits          = tcu::IVec3(4, 4, 0);
911
912                 const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
913
914                 m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS                             ? "Pass" :
915                                                                                            compareResult == QP_TEST_RESULT_QUALITY_WARNING      ? "Low-quality method used"     :
916                                                                                            compareResult == QP_TEST_RESULT_FAIL                         ? "Image comparison failed"     : "");
917         }
918
919         return STOP;
920 }
921
922 // TextureCubeGenMipmapCase
923
924 class TextureCubeGenMipmapCase : public tcu::TestCase
925 {
926 public:
927
928                                                                 TextureCubeGenMipmapCase                (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size);
929                                                                 ~TextureCubeGenMipmapCase               (void);
930
931         void                                            init                                                    (void);
932         void                                            deinit                                                  (void);
933         IterateResult                           iterate                                                 (void);
934
935 private:
936                                                                 TextureCubeGenMipmapCase                (const TextureCubeGenMipmapCase& other);
937         TextureCubeGenMipmapCase&       operator=                                               (const TextureCubeGenMipmapCase& other);
938
939         glu::RenderContext&                     m_renderCtx;
940
941         deUint32                                        m_format;
942         deUint32                                        m_dataType;
943         deUint32                                        m_hint;
944         int                                                     m_size;
945
946         glu::TextureCube*                       m_texture;
947         TextureRenderer                         m_renderer;
948 };
949
950 TextureCubeGenMipmapCase::TextureCubeGenMipmapCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, deUint32 format, deUint32 dataType, deUint32 hint, int size)
951         : TestCase                      (testCtx, name, desc)
952         , m_renderCtx           (renderCtx)
953         , m_format                      (format)
954         , m_dataType            (dataType)
955         , m_hint                        (hint)
956         , m_size                        (size)
957         , m_texture                     (DE_NULL)
958         , m_renderer            (renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
959 {
960 }
961
962 TextureCubeGenMipmapCase::~TextureCubeGenMipmapCase (void)
963 {
964         deinit();
965 }
966
967 void TextureCubeGenMipmapCase::init (void)
968 {
969         if (m_renderCtx.getRenderTarget().getWidth() < 3*m_size || m_renderCtx.getRenderTarget().getHeight() < 2*m_size)
970                 throw tcu::NotSupportedError("Render target size must be at least (" + de::toString(3*m_size) + ", " + de::toString(2*m_size) + ")");
971
972         DE_ASSERT(!m_texture);
973         m_texture = new glu::TextureCube(m_renderCtx, m_format, m_dataType, m_size);
974 }
975
976 void TextureCubeGenMipmapCase::deinit (void)
977 {
978         delete m_texture;
979         m_texture = DE_NULL;
980
981         m_renderer.clear();
982 }
983
984 TextureCubeGenMipmapCase::IterateResult TextureCubeGenMipmapCase::iterate (void)
985 {
986         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
987
988         const deUint32                  minFilter                       = GL_NEAREST_MIPMAP_NEAREST;
989         const deUint32                  magFilter                       = GL_NEAREST;
990         const deUint32                  wrapS                           = GL_CLAMP_TO_EDGE;
991         const deUint32                  wrapT                           = GL_CLAMP_TO_EDGE;
992
993         tcu::TextureCube                resultTexture           (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), m_size);
994
995         const int                               numLevels                       = deLog2Floor32(m_size)+1;
996         vector<float>                   texCoord;
997
998         // Initialize texture level 0 with colored grid.
999         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1000         {
1001                 Vec4 ca, cb; // Grid colors.
1002
1003                 switch (face)
1004                 {
1005                         case 0: ca = Vec4(1.0f, 0.3f, 0.0f, 0.7f); cb = Vec4(0.0f, 0.0f, 1.0f, 1.0f); break;
1006                         case 1: ca = Vec4(0.0f, 1.0f, 0.5f, 0.5f); cb = Vec4(1.0f, 0.0f, 0.0f, 1.0f); break;
1007                         case 2: ca = Vec4(0.7f, 0.0f, 1.0f, 0.3f); cb = Vec4(0.0f, 1.0f, 0.0f, 1.0f); break;
1008                         case 3: ca = Vec4(0.0f, 0.3f, 1.0f, 1.0f); cb = Vec4(1.0f, 0.0f, 0.0f, 0.7f); break;
1009                         case 4: ca = Vec4(1.0f, 0.0f, 0.5f, 1.0f); cb = Vec4(0.0f, 1.0f, 0.0f, 0.5f); break;
1010                         case 5: ca = Vec4(0.7f, 1.0f, 0.0f, 1.0f); cb = Vec4(0.0f, 0.0f, 1.0f, 0.3f); break;
1011                 }
1012
1013                 m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
1014                 fillWithGrid(m_texture->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), 8, ca, cb);
1015         }
1016
1017         // Upload data and setup params.
1018         m_texture->upload();
1019
1020         gl.bindTexture  (GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
1021         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,                wrapS);
1022         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,                wrapT);
1023         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,    minFilter);
1024         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,    magFilter);
1025         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1026
1027         // Generate mipmap.
1028         gl.hint(GL_GENERATE_MIPMAP_HINT, m_hint);
1029         gl.generateMipmap(GL_TEXTURE_CUBE_MAP);
1030         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenerateMipmap()");
1031
1032         // Render all levels.
1033         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1034         {
1035                 const int       levelWidth      = de::max(1, m_size >> levelNdx);
1036                 const int       levelHeight     = de::max(1, m_size >> levelNdx);
1037
1038                 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1039                 {
1040                         const RandomViewport    viewport        (m_renderCtx.getRenderTarget(), levelWidth*3, levelHeight*2, deStringHash(getName()) ^ deInt32Hash(levelNdx + faceNdx));
1041                         const tcu::CubeFace             face            = tcu::CubeFace(faceNdx);
1042
1043                         computeQuadTexCoordCube(texCoord, face);
1044
1045                         gl.viewport(viewport.x, viewport.y, levelWidth, levelHeight);
1046                         m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
1047
1048                         resultTexture.allocLevel(face, levelNdx);
1049                         glu::readPixels(m_renderCtx, viewport.x, viewport.y, resultTexture.getLevelFace(levelNdx, face));
1050                 }
1051         }
1052
1053         // Compare results
1054         {
1055                 const IVec4                     framebufferBits         = max(getBitsVec(m_renderCtx.getRenderTarget().getPixelFormat())-2, IVec4(0));
1056                 const IVec4                     formatBits                      = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
1057                 const tcu::BVec4        formatMask                      = greaterThan(formatBits, IVec4(0));
1058                 const IVec4                     cmpBits                         = select(min(framebufferBits, formatBits), framebufferBits, formatMask);
1059                 GenMipmapPrecision      comparePrec;
1060
1061                 comparePrec.colorMask           = getCompareMask(m_renderCtx.getRenderTarget().getPixelFormat());
1062                 comparePrec.colorThreshold      = tcu::computeFixedPointThreshold(cmpBits);
1063                 comparePrec.filterBits          = tcu::IVec3(4, 4, 0);
1064
1065                 const qpTestResult compareResult = compareGenMipmapResult(m_testCtx.getLog(), resultTexture, m_texture->getRefTexture(), comparePrec);
1066
1067                 m_testCtx.setTestResult(compareResult, compareResult == QP_TEST_RESULT_PASS                             ? "Pass" :
1068                                                                                            compareResult == QP_TEST_RESULT_QUALITY_WARNING      ? "Low-quality method used"     :
1069                                                                                            compareResult == QP_TEST_RESULT_FAIL                         ? "Image comparison failed"     : "");
1070         }
1071
1072         return STOP;
1073 }
1074
1075 // Texture3DMipmapCase
1076
1077 class Texture3DMipmapCase : public TestCase
1078 {
1079 public:
1080
1081                                                                 Texture3DMipmapCase                     (Context&                                       context,
1082                                                                                                                          const char*                            name,
1083                                                                                                                          const char*                            desc,
1084                                                                                                                          CoordType                                      coordType,
1085                                                                                                                          deUint32                                       minFilter,
1086                                                                                                                          deUint32                                       wrapS,
1087                                                                                                                          deUint32                                       wrapT,
1088                                                                                                                          deUint32                                       wrapR,
1089                                                                                                                          deUint32                                       format,
1090                                                                                                                          int                                            width,
1091                                                                                                                          int                                            height,
1092                                                                                                                          int                                            depth);
1093                                                                 ~Texture3DMipmapCase            (void);
1094
1095         void                                            init                                            (void);
1096         void                                            deinit                                          (void);
1097         IterateResult                           iterate                                         (void);
1098
1099 private:
1100                                                                 Texture3DMipmapCase                     (const Texture3DMipmapCase& other);
1101         Texture3DMipmapCase&            operator=                                       (const Texture3DMipmapCase& other);
1102
1103         CoordType                                       m_coordType;
1104         deUint32                                        m_minFilter;
1105         deUint32                                        m_wrapS;
1106         deUint32                                        m_wrapT;
1107         deUint32                                        m_wrapR;
1108         deUint32                                        m_internalFormat;
1109         int                                                     m_width;
1110         int                                                     m_height;
1111         int                                                     m_depth;
1112
1113         glu::Texture3D*                                         m_texture;
1114         TextureTestUtil::TextureRenderer        m_renderer;
1115 };
1116
1117 Texture3DMipmapCase::Texture3DMipmapCase (Context& context, const char* name, const char* desc, CoordType coordType, deUint32 minFilter, deUint32 wrapS, deUint32 wrapT, deUint32 wrapR, deUint32 format, int width, int height, int depth)
1118         : TestCase                      (context, name, desc)
1119         , m_coordType           (coordType)
1120         , m_minFilter           (minFilter)
1121         , m_wrapS                       (wrapS)
1122         , m_wrapT                       (wrapT)
1123         , m_wrapR                       (wrapR)
1124         , m_internalFormat      (format)
1125         , m_width                       (width)
1126         , m_height                      (height)
1127         , m_depth                       (depth)
1128         , m_texture                     (DE_NULL)
1129         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1130 {
1131 }
1132
1133 Texture3DMipmapCase::~Texture3DMipmapCase (void)
1134 {
1135         Texture3DMipmapCase::deinit();
1136 }
1137
1138 void Texture3DMipmapCase::init (void)
1139 {
1140         const tcu::TextureFormat&               texFmt                  = glu::mapGLInternalFormat(m_internalFormat);
1141         tcu::TextureFormatInfo                  fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
1142         const tcu::Vec4&                                cScale                  = fmtInfo.lookupScale;
1143         const tcu::Vec4&                                cBias                   = fmtInfo.lookupBias;
1144         int                                                             numLevels               = deLog2Floor32(de::max(de::max(m_width, m_height), m_depth))+1;
1145
1146         if (m_coordType == COORDTYPE_PROJECTED && m_context.getRenderTarget().getNumSamples() > 0)
1147                 throw tcu::NotSupportedError("Projected lookup validation not supported in multisample config");
1148
1149         m_texture = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1150
1151         // Fill texture with colored grid.
1152         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1153         {
1154                 deUint32        step            = 0xff / (numLevels-1);
1155                 deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
1156                 deUint32        dec                     = 0xff - inc;
1157                 deUint32        rgb                     = (0xff << 16) | (dec << 8) | inc;
1158                 deUint32        color           = 0xff000000 | rgb;
1159
1160                 m_texture->getRefTexture().allocLevel(levelNdx);
1161                 tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec()*cScale + cBias);
1162         }
1163
1164         m_texture->upload();
1165 }
1166
1167 void Texture3DMipmapCase::deinit (void)
1168 {
1169         delete m_texture;
1170         m_texture = DE_NULL;
1171
1172         m_renderer.clear();
1173 }
1174
1175 static void getBasicTexCoord3D (std::vector<float>& dst, int cellNdx)
1176 {
1177         static const struct
1178         {
1179                 float sScale;
1180                 float sBias;
1181                 float tScale;
1182                 float tBias;
1183                 float rScale;
1184                 float rBias;
1185         } s_params[] =
1186         {
1187         //              sScale  sBias   tScale  tBias   rScale  rBias
1188                 {        0.9f,  -0.1f,   0.7f,   0.3f,   0.8f,   0.9f   },
1189                 {        1.2f,  -0.1f,   1.1f,   0.3f,   1.0f,   0.9f   },
1190                 {        1.5f,   0.7f,   0.9f,  -0.3f,   1.1f,   0.1f   },
1191                 {        1.2f,   0.7f,  -2.3f,  -0.3f,   1.1f,   0.2f   },
1192                 {        1.1f,   0.8f,  -1.3f,  -0.3f,   2.9f,   0.9f   },
1193                 {        3.4f,   0.8f,   4.0f,   0.0f,  -3.3f,  -1.0f   },
1194                 {       -3.4f,  -0.1f,  -4.0f,   0.0f,  -5.1f,   1.0f   },
1195                 {       -4.0f,  -0.1f,   3.4f,   0.1f,   5.7f,   0.0f   },
1196                 {       -5.6f,   0.0f,   0.5f,   1.2f,   3.9f,   4.0f   },
1197                 {        5.0f,  -2.0f,   3.1f,   1.2f,   5.1f,   0.2f   },
1198                 {        2.5f,  -2.0f,   6.3f,   3.0f,   5.1f,   0.2f   },
1199                 {       -8.3f,   0.0f,   7.1f,   3.0f,   2.0f,   0.2f   },
1200                 {    3.8f,       0.0f,   9.7f,   1.0f,   7.0f,   0.7f   },
1201                 {       13.3f,   0.0f,   7.1f,   3.0f,   2.0f,   0.2f   },
1202                 {   16.0f,       8.0f,  12.7f,   1.0f,  17.1f,   0.7f   },
1203                 {       15.3f,   0.0f,  20.1f,   3.0f,  33.0f,   3.2f   }
1204         };
1205
1206         float sScale    = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sScale;
1207         float sBias             = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sBias;
1208         float tScale    = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tScale;
1209         float tBias             = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tBias;
1210         float rScale    = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rScale;
1211         float rBias             = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rBias;
1212
1213         dst.resize(3*4);
1214
1215         dst[0] = sBias;                 dst[ 1] = tBias;                        dst[ 2] = rBias;
1216         dst[3] = sBias;                 dst[ 4] = tBias+tScale;         dst[ 5] = rBias+rScale*0.5f;
1217         dst[6] = sBias+sScale;  dst[ 7] = tBias;                        dst[ 8] = rBias+rScale*0.5f;
1218         dst[9] = sBias+sScale;  dst[10] = tBias+tScale;         dst[11] = rBias+rScale;
1219 }
1220
1221 static void getAffineTexCoord3D (std::vector<float>& dst, int cellNdx)
1222 {
1223         // Use basic coords as base.
1224         getBasicTexCoord3D(dst, cellNdx);
1225
1226         // Rotate based on cell index.
1227         float           angleX          = 0.0f + 2.0f*DE_PI * ((float)cellNdx / 16.0f);
1228         float           angleY          = 1.0f + 2.0f*DE_PI * ((float)cellNdx / 32.0f);
1229         tcu::Mat3       rotMatrix       = tcu::rotationMatrixX(angleX) * tcu::rotationMatrixY(angleY);
1230
1231         Vec3            p0                      = rotMatrix * Vec3(dst[0], dst[ 1], dst[ 2]);
1232         Vec3            p1                      = rotMatrix * Vec3(dst[3], dst[ 4], dst[ 5]);
1233         Vec3            p2                      = rotMatrix * Vec3(dst[6], dst[ 7], dst[ 8]);
1234         Vec3            p3                      = rotMatrix * Vec3(dst[9], dst[10], dst[11]);
1235
1236         dst[0] = p0.x();        dst[ 1] = p0.y();       dst[ 2] = p0.z();
1237         dst[3] = p1.x();        dst[ 4] = p1.y();       dst[ 5] = p1.z();
1238         dst[6] = p2.x();        dst[ 7] = p2.y();       dst[ 8] = p2.z();
1239         dst[9] = p3.x();        dst[10] = p3.y();       dst[11] = p3.z();
1240 }
1241
1242 Texture3DMipmapCase::IterateResult Texture3DMipmapCase::iterate (void)
1243 {
1244         const glw::Functions&                   gl                                      = m_context.getRenderContext().getFunctions();
1245
1246         const tcu::Texture3D&                   refTexture                      = m_texture->getRefTexture();
1247         const tcu::TextureFormat&               texFmt                          = refTexture.getFormat();
1248         const tcu::TextureFormatInfo    fmtInfo                         = tcu::getTextureFormatInfo(texFmt);
1249         const int                                               texWidth                        = refTexture.getWidth();
1250         const int                                               texHeight                       = refTexture.getHeight();
1251         const deUint32                                  magFilter                       = GL_NEAREST;
1252
1253         const tcu::RenderTarget&                renderTarget            = m_context.getRenderContext().getRenderTarget();
1254         const RandomViewport                    viewport                        (renderTarget, texWidth*4, texHeight*4, deStringHash(getName()));
1255
1256         const bool                                              isProjected                     = m_coordType == COORDTYPE_PROJECTED;
1257         const bool                                              useLodBias                      = m_coordType == COORDTYPE_BASIC_BIAS;
1258
1259         // Viewport is divided into 4x4 grid.
1260         const int                                               gridWidth                       = 4;
1261         const int                                               gridHeight                      = 4;
1262         const int                                               cellWidth                       = viewport.width / gridWidth;
1263         const int                                               cellHeight                      = viewport.height / gridHeight;
1264
1265         ReferenceParams                                 sampleParams            (TEXTURETYPE_3D);
1266
1267         tcu::Surface                                    renderedFrame           (viewport.width, viewport.height);
1268         vector<float>                                   texCoord;
1269
1270         // Sampling parameters.
1271         sampleParams.sampler            = glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, magFilter);
1272         sampleParams.samplerType        = getSamplerType(texFmt);
1273         sampleParams.colorBias          = fmtInfo.lookupBias;
1274         sampleParams.colorScale         = fmtInfo.lookupScale;
1275         sampleParams.flags                      = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
1276
1277         // Bind texture and setup sampler parameters.
1278         gl.bindTexture  (GL_TEXTURE_3D, m_texture->getGLTexture());
1279         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,              m_wrapS);
1280         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,              m_wrapT);
1281         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,              m_wrapR);
1282         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,  m_minFilter);
1283         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,  magFilter);
1284
1285         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1286
1287         // Bias values.
1288         static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
1289
1290         // Projection values.
1291         static const Vec4 s_projections[] =
1292         {
1293                 Vec4(1.2f, 1.0f, 0.7f, 1.0f),
1294                 Vec4(1.3f, 0.8f, 0.6f, 2.0f),
1295                 Vec4(0.8f, 1.0f, 1.7f, 0.6f),
1296                 Vec4(1.2f, 1.0f, 1.7f, 1.5f)
1297         };
1298
1299         // Render cells.
1300         for (int gridY = 0; gridY < gridHeight; gridY++)
1301         {
1302                 for (int gridX = 0; gridX < gridWidth; gridX++)
1303                 {
1304                         const int               curX            = cellWidth*gridX;
1305                         const int               curY            = cellHeight*gridY;
1306                         const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1307                         const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1308                         const int               cellNdx         = gridY*gridWidth + gridX;
1309
1310                         // Compute texcoord.
1311                         switch (m_coordType)
1312                         {
1313                                 case COORDTYPE_BASIC_BIAS:      // Fall-through.
1314                                 case COORDTYPE_PROJECTED:
1315                                 case COORDTYPE_BASIC:           getBasicTexCoord3D      (texCoord, cellNdx);    break;
1316                                 case COORDTYPE_AFFINE:          getAffineTexCoord3D     (texCoord, cellNdx);    break;
1317                                 default:                                        DE_ASSERT(DE_FALSE);
1318                         }
1319
1320                         // Set projection.
1321                         if (isProjected)
1322                                 sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
1323
1324                         // Set LOD bias.
1325                         if (useLodBias)
1326                                 sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
1327
1328                         // Render with GL.
1329                         gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
1330                         m_renderer.renderQuad(0, &texCoord[0], sampleParams);
1331                 }
1332         }
1333
1334         // Read result.
1335         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
1336
1337         // Compare and log
1338         {
1339                 const tcu::PixelFormat& pixelFormat             = m_context.getRenderTarget().getPixelFormat();
1340                 const bool                              isTrilinear             = m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
1341                 tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
1342                 tcu::Surface                    errorMask               (viewport.width, viewport.height);
1343                 tcu::LookupPrecision    lookupPrec;
1344                 tcu::LodPrecision               lodPrec                 (tcu::LodPrecision::RULE_OPENGL);
1345                 int                                             numFailedPixels = 0;
1346
1347                 lookupPrec.coordBits            = tcu::IVec3(20, 20, 20);
1348                 lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
1349                 lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
1350                 lookupPrec.colorMask            = getCompareMask(pixelFormat);
1351                 lodPrec.derivateBits            = 10;
1352                 lodPrec.lodBits                         = isProjected ? 6 : 8;
1353
1354                 for (int gridY = 0; gridY < gridHeight; gridY++)
1355                 {
1356                         for (int gridX = 0; gridX < gridWidth; gridX++)
1357                         {
1358                                 const int               curX            = cellWidth*gridX;
1359                                 const int               curY            = cellHeight*gridY;
1360                                 const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1361                                 const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1362                                 const int               cellNdx         = gridY*gridWidth + gridX;
1363
1364                                 switch (m_coordType)
1365                                 {
1366                                         case COORDTYPE_BASIC_BIAS:      // Fall-through.
1367                                         case COORDTYPE_PROJECTED:
1368                                         case COORDTYPE_BASIC:           getBasicTexCoord3D      (texCoord, cellNdx);    break;
1369                                         case COORDTYPE_AFFINE:          getAffineTexCoord3D     (texCoord, cellNdx);    break;
1370                                         default:                                        DE_ASSERT(DE_FALSE);
1371                                 }
1372
1373                                 if (isProjected)
1374                                         sampleParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
1375
1376                                 if (useLodBias)
1377                                         sampleParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
1378
1379                                 // Render ideal result
1380                                 sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
1381                                                           refTexture, &texCoord[0], sampleParams);
1382
1383                                 // Compare this cell
1384                                 numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
1385                                                                                                                         tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
1386                                                                                                                         tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
1387                                                                                                                         m_texture->getRefTexture(), &texCoord[0], sampleParams,
1388                                                                                                                         lookupPrec, lodPrec, m_testCtx.getWatchDog());
1389                         }
1390                 }
1391
1392                 if (numFailedPixels > 0)
1393                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1394
1395                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
1396                                                         << TestLog::Image("Rendered", "Rendered image", renderedFrame);
1397
1398                 if (numFailedPixels > 0)
1399                 {
1400                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
1401                                                                 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1402                 }
1403
1404                 m_testCtx.getLog() << TestLog::EndImageSet;
1405
1406                 {
1407                         const bool isOk = numFailedPixels == 0;
1408                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
1409                                                                         isOk ? "Pass"                           : "Image verification failed");
1410                 }
1411         }
1412
1413         return STOP;
1414 }
1415
1416 // Texture2DLodControlCase + test cases
1417
1418 class Texture2DLodControlCase : public TestCase
1419 {
1420 public:
1421
1422                                                                                 Texture2DLodControlCase         (Context& context, const char* name, const char* desc, deUint32 minFilter);
1423                                                                                 ~Texture2DLodControlCase        (void);
1424
1425         void                                                            init                                            (void);
1426         void                                                            deinit                                          (void);
1427         IterateResult                                           iterate                                         (void);
1428
1429 protected:
1430         virtual void                                            setTextureParams                        (int cellNdx)                                                   = DE_NULL;
1431         virtual void                                            getReferenceParams                      (ReferenceParams& params, int cellNdx)  = DE_NULL;
1432
1433         const int                                                       m_texWidth;
1434         const int                                                       m_texHeight;
1435
1436 private:
1437                                                                                 Texture2DLodControlCase         (const Texture2DLodControlCase& other);
1438         Texture2DLodControlCase&                        operator=                                       (const Texture2DLodControlCase& other);
1439
1440         deUint32                                                        m_minFilter;
1441
1442         glu::Texture2D*                                         m_texture;
1443         TextureTestUtil::TextureRenderer        m_renderer;
1444 };
1445
1446 Texture2DLodControlCase::Texture2DLodControlCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1447         : TestCase              (context, name, desc)
1448         , m_texWidth    (64)
1449         , m_texHeight   (64)
1450         , m_minFilter   (minFilter)
1451         , m_texture             (DE_NULL)
1452         , m_renderer    (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1453 {
1454 }
1455
1456 Texture2DLodControlCase::~Texture2DLodControlCase (void)
1457 {
1458         Texture2DLodControlCase::deinit();
1459 }
1460
1461 void Texture2DLodControlCase::init (void)
1462 {
1463         const deUint32  format          = GL_RGBA8;
1464         int                             numLevels       = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
1465
1466         m_texture = new glu::Texture2D(m_context.getRenderContext(), format, m_texWidth, m_texHeight);
1467
1468         // Fill texture with colored grid.
1469         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1470         {
1471                 deUint32        step            = 0xff / (numLevels-1);
1472                 deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
1473                 deUint32        dec                     = 0xff - inc;
1474                 deUint32        rgb                     = (inc << 16) | (dec << 8) | 0xff;
1475                 deUint32        color           = 0xff000000 | rgb;
1476
1477                 m_texture->getRefTexture().allocLevel(levelNdx);
1478                 tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec());
1479         }
1480 }
1481
1482 void Texture2DLodControlCase::deinit (void)
1483 {
1484         delete m_texture;
1485         m_texture = DE_NULL;
1486
1487         m_renderer.clear();
1488 }
1489
1490 Texture2DLodControlCase::IterateResult Texture2DLodControlCase::iterate (void)
1491 {
1492         const glw::Functions&           gl                                      = m_context.getRenderContext().getFunctions();
1493
1494         const deUint32                          wrapS                           = GL_REPEAT;
1495         const deUint32                          wrapT                           = GL_REPEAT;
1496         const deUint32                          magFilter                       = GL_NEAREST;
1497
1498         const tcu::Texture2D&           refTexture                      = m_texture->getRefTexture();
1499         const int                                       texWidth                        = refTexture.getWidth();
1500         const int                                       texHeight                       = refTexture.getHeight();
1501
1502         const tcu::RenderTarget&        renderTarget            = m_context.getRenderContext().getRenderTarget();
1503         const RandomViewport            viewport                        (renderTarget, texWidth*4, texHeight*4, deStringHash(getName()));
1504
1505         ReferenceParams                         sampleParams            (TEXTURETYPE_2D, glu::mapGLSampler(wrapS, wrapT, m_minFilter, magFilter));
1506         vector<float>                           texCoord;
1507         tcu::Surface                            renderedFrame           (viewport.width, viewport.height);
1508
1509         // Viewport is divided into 4x4 grid.
1510         const int                                       gridWidth                       = 4;
1511         const int                                       gridHeight                      = 4;
1512         const int                                       cellWidth                       = viewport.width / gridWidth;
1513         const int                                       cellHeight                      = viewport.height / gridHeight;
1514
1515         // Upload texture data.
1516         m_texture->upload();
1517
1518         // Bind gradient texture and setup sampler parameters.
1519         gl.bindTexture  (GL_TEXTURE_2D, m_texture->getGLTexture());
1520         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,              wrapS);
1521         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,              wrapT);
1522         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,  m_minFilter);
1523         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,  magFilter);
1524
1525         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1526
1527         // Render cells.
1528         for (int gridY = 0; gridY < gridHeight; gridY++)
1529         {
1530                 for (int gridX = 0; gridX < gridWidth; gridX++)
1531                 {
1532                         int                             curX            = cellWidth*gridX;
1533                         int                             curY            = cellHeight*gridY;
1534                         int                             curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1535                         int                             curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1536                         int                             cellNdx         = gridY*gridWidth + gridX;
1537
1538                         // Compute texcoord.
1539                         getBasicTexCoord2D(texCoord, cellNdx);
1540
1541                         // Render with GL.
1542                         setTextureParams(cellNdx);
1543                         gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
1544                         m_renderer.renderQuad(0, &texCoord[0], sampleParams);
1545                 }
1546         }
1547
1548         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
1549         GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
1550
1551         // Compare and log.
1552         {
1553                 const tcu::PixelFormat& pixelFormat             = m_context.getRenderTarget().getPixelFormat();
1554                 const bool                              isTrilinear             = m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
1555                 tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
1556                 tcu::Surface                    errorMask               (viewport.width, viewport.height);
1557                 tcu::LookupPrecision    lookupPrec;
1558                 tcu::LodPrecision               lodPrec                 (tcu::LodPrecision::RULE_OPENGL);
1559                 int                                             numFailedPixels = 0;
1560
1561                 lookupPrec.coordBits            = tcu::IVec3(20, 20, 0);
1562                 lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
1563                 lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
1564                 lookupPrec.colorMask            = getCompareMask(pixelFormat);
1565                 lodPrec.derivateBits            = 10;
1566                 lodPrec.lodBits                         = 8;
1567
1568                 for (int gridY = 0; gridY < gridHeight; gridY++)
1569                 {
1570                         for (int gridX = 0; gridX < gridWidth; gridX++)
1571                         {
1572                                 const int               curX            = cellWidth*gridX;
1573                                 const int               curY            = cellHeight*gridY;
1574                                 const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
1575                                 const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
1576                                 const int               cellNdx         = gridY*gridWidth + gridX;
1577
1578                                 getBasicTexCoord2D(texCoord, cellNdx);
1579                                 getReferenceParams(sampleParams, cellNdx);
1580
1581                                 // Render ideal result
1582                                 sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
1583                                                           refTexture, &texCoord[0], sampleParams);
1584
1585                                 // Compare this cell
1586                                 numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
1587                                                                                                                         tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
1588                                                                                                                         tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
1589                                                                                                                         m_texture->getRefTexture(), &texCoord[0], sampleParams,
1590                                                                                                                         lookupPrec, lodPrec, m_testCtx.getWatchDog());
1591                         }
1592                 }
1593
1594                 if (numFailedPixels > 0)
1595                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1596
1597                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
1598                                                         << TestLog::Image("Rendered", "Rendered image", renderedFrame);
1599
1600                 if (numFailedPixels > 0)
1601                 {
1602                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
1603                                                                 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1604                 }
1605
1606                 m_testCtx.getLog() << TestLog::EndImageSet;
1607
1608                 {
1609                         const bool isOk = numFailedPixels == 0;
1610                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
1611                                                                         isOk ? "Pass"                           : "Image verification failed");
1612                 }
1613         }
1614
1615         return STOP;
1616 }
1617
1618 class Texture2DMinLodCase : public Texture2DLodControlCase
1619 {
1620 public:
1621         Texture2DMinLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1622                 : Texture2DLodControlCase(context, name, desc, minFilter)
1623         {
1624         }
1625
1626 protected:
1627         void setTextureParams (int cellNdx)
1628         {
1629                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1630                 gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, getMinLodForCell(cellNdx));
1631         }
1632
1633         void getReferenceParams (ReferenceParams& params, int cellNdx)
1634         {
1635                 params.minLod = getMinLodForCell(cellNdx);
1636         }
1637 };
1638
1639 class Texture2DMaxLodCase : public Texture2DLodControlCase
1640 {
1641 public:
1642         Texture2DMaxLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1643                 : Texture2DLodControlCase(context, name, desc, minFilter)
1644         {
1645         }
1646
1647 protected:
1648         void setTextureParams (int cellNdx)
1649         {
1650                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1651                 gl.texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, getMaxLodForCell(cellNdx));
1652         }
1653
1654         void getReferenceParams (ReferenceParams& params, int cellNdx)
1655         {
1656                 params.maxLod = getMaxLodForCell(cellNdx);
1657         }
1658 };
1659
1660 class Texture2DBaseLevelCase : public Texture2DLodControlCase
1661 {
1662 public:
1663         Texture2DBaseLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1664                 : Texture2DLodControlCase(context, name, desc, minFilter)
1665         {
1666         }
1667
1668 protected:
1669         int getBaseLevel (int cellNdx) const
1670         {
1671                 const int       numLevels       = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
1672                 const int       baseLevel       = (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0xac2f274a) % numLevels;
1673
1674                 return baseLevel;
1675         }
1676
1677         void setTextureParams (int cellNdx)
1678         {
1679                 const glw::Functions&   gl      = m_context.getRenderContext().getFunctions();
1680                 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, getBaseLevel(cellNdx));
1681         }
1682
1683         void getReferenceParams (ReferenceParams& params, int cellNdx)
1684         {
1685                 params.baseLevel = getBaseLevel(cellNdx);
1686         }
1687 };
1688
1689 class Texture2DMaxLevelCase : public Texture2DLodControlCase
1690 {
1691 public:
1692         Texture2DMaxLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1693                 : Texture2DLodControlCase(context, name, desc, minFilter)
1694         {
1695         }
1696
1697 protected:
1698         int getMaxLevel (int cellNdx) const
1699         {
1700                 const int               numLevels       = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
1701                 const int               maxLevel        = (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x82cfa4e) % numLevels;
1702
1703                 return maxLevel;
1704         }
1705
1706         void setTextureParams (int cellNdx)
1707         {
1708                 const glw::Functions&   gl      = m_context.getRenderContext().getFunctions();
1709                 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, getMaxLevel(cellNdx));
1710         }
1711
1712         void getReferenceParams (ReferenceParams& params, int cellNdx)
1713         {
1714                 params.maxLevel = getMaxLevel(cellNdx);
1715         }
1716 };
1717
1718 // TextureCubeLodControlCase + test cases
1719
1720 class TextureCubeLodControlCase : public TestCase
1721 {
1722 public:
1723
1724                                                                                 TextureCubeLodControlCase       (Context& context, const char* name, const char* desc, deUint32 minFilter);
1725                                                                                 ~TextureCubeLodControlCase      (void);
1726
1727         void                                                            init                                            (void);
1728         void                                                            deinit                                          (void);
1729         IterateResult                                           iterate                                         (void);
1730
1731 protected:
1732         virtual void                                            setTextureParams                        (int cellNdx)                                                   = DE_NULL;
1733         virtual void                                            getReferenceParams                      (ReferenceParams& params, int cellNdx)  = DE_NULL;
1734
1735         const int                                                       m_texSize;
1736
1737 private:
1738                                                                                 TextureCubeLodControlCase       (const TextureCubeLodControlCase& other);
1739         TextureCubeLodControlCase&                      operator=                                       (const TextureCubeLodControlCase& other);
1740
1741         deUint32                                                        m_minFilter;
1742
1743         glu::TextureCube*                                       m_texture;
1744         TextureTestUtil::TextureRenderer        m_renderer;
1745 };
1746
1747 TextureCubeLodControlCase::TextureCubeLodControlCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1748         : TestCase                      (context, name, desc)
1749         , m_texSize                     (64)
1750         , m_minFilter           (minFilter)
1751         , m_texture                     (DE_NULL)
1752         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1753 {
1754 }
1755
1756 TextureCubeLodControlCase::~TextureCubeLodControlCase (void)
1757 {
1758         deinit();
1759 }
1760
1761 void TextureCubeLodControlCase::init (void)
1762 {
1763         const deUint32  format          = GL_RGBA8;
1764         const int               numLevels       = deLog2Floor32(m_texSize)+1;
1765
1766         m_texture = new glu::TextureCube(m_context.getRenderContext(), format, m_texSize);
1767
1768         // Fill texture with colored grid.
1769         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
1770         {
1771                 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1772                 {
1773                         deUint32        step            = 0xff / (numLevels-1);
1774                         deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
1775                         deUint32        dec                     = 0xff - inc;
1776                         deUint32        rgb                     = 0;
1777
1778                         switch (faceNdx)
1779                         {
1780                                 case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
1781                                 case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
1782                                 case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
1783                                 case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
1784                                 case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
1785                                 case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
1786                         }
1787
1788                         deUint32        color           = 0xff000000 | rgb;
1789
1790                         m_texture->getRefTexture().allocLevel((tcu::CubeFace)faceNdx, levelNdx);
1791                         tcu::clear(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
1792                 }
1793         }
1794 }
1795
1796 void TextureCubeLodControlCase::deinit (void)
1797 {
1798         delete m_texture;
1799         m_texture = DE_NULL;
1800
1801         m_renderer.clear();
1802 }
1803
1804 TextureCubeLodControlCase::IterateResult TextureCubeLodControlCase::iterate (void)
1805 {
1806         const deUint32                  wrapS                           = GL_CLAMP_TO_EDGE;
1807         const deUint32                  wrapT                           = GL_CLAMP_TO_EDGE;
1808         const deUint32                  magFilter                       = GL_NEAREST;
1809
1810         const int                               texWidth                        = m_texture->getRefTexture().getSize();
1811         const int                               texHeight                       = m_texture->getRefTexture().getSize();
1812
1813         const int                               defViewportWidth        = texWidth*2;
1814         const int                               defViewportHeight       = texHeight*2;
1815
1816         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
1817         const RandomViewport    viewport                        (m_context.getRenderTarget(), defViewportWidth, defViewportHeight, deStringHash(getName()));
1818
1819         vector<float>                   texCoord;
1820
1821         tcu::Surface                    renderedFrame           (viewport.width, viewport.height);
1822
1823         // Upload texture data.
1824         m_texture->upload();
1825
1826         // Bind gradient texture and setup sampler parameters.
1827         gl.bindTexture  (GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
1828         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,                wrapS);
1829         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,                wrapT);
1830         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,    m_minFilter);
1831         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,    magFilter);
1832
1833         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
1834
1835         // Compute grid.
1836         vector<tcu::IVec4> gridLayout;
1837         computeGridLayout(gridLayout, viewport.width, viewport.height);
1838
1839         for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
1840         {
1841                 const int                       curX            = gridLayout[cellNdx].x();
1842                 const int                       curY            = gridLayout[cellNdx].y();
1843                 const int                       curW            = gridLayout[cellNdx].z();
1844                 const int                       curH            = gridLayout[cellNdx].w();
1845                 const tcu::CubeFace     cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
1846                 RenderParams            params          (TEXTURETYPE_CUBE);
1847
1848                 computeQuadTexCoordCube(texCoord, cubeFace);
1849
1850                 setTextureParams(cellNdx);
1851
1852                 // Render with GL.
1853                 gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
1854                 m_renderer.renderQuad(0, &texCoord[0], params);
1855                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1856         }
1857
1858         // Read result.
1859         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
1860         GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
1861
1862         // Render reference and compare
1863         {
1864                 tcu::Surface                    referenceFrame          (viewport.width, viewport.height);
1865                 tcu::Surface                    errorMask                       (viewport.width, viewport.height);
1866                 int                                             numFailedPixels         = 0;
1867                 ReferenceParams                 params                          (TEXTURETYPE_CUBE);
1868                 tcu::LookupPrecision    lookupPrec;
1869                 tcu::LodPrecision               lodPrec                         (tcu::LodPrecision::RULE_OPENGL);
1870
1871                 // Params for rendering reference
1872                 params.sampler                                  = glu::mapGLSampler(wrapS, wrapT, m_minFilter, magFilter);
1873                 params.sampler.seamlessCubeMap  = true;
1874                 params.lodMode                                  = LODMODE_EXACT;
1875
1876                 // Comparison parameters
1877                 lookupPrec.colorMask                    = getCompareMask(m_context.getRenderTarget().getPixelFormat());
1878                 lookupPrec.colorThreshold               = tcu::computeFixedPointThreshold(max(getBitsVec(m_context.getRenderTarget().getPixelFormat())-2, IVec4(0)));
1879                 lookupPrec.coordBits                    = tcu::IVec3(10);
1880                 lookupPrec.uvwBits                              = tcu::IVec3(5,5,0);
1881                 lodPrec.derivateBits                    = 10;
1882                 lodPrec.lodBits                                 = 6;
1883
1884                 for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
1885                 {
1886                         const int                               curX            = gridLayout[cellNdx].x();
1887                         const int                               curY            = gridLayout[cellNdx].y();
1888                         const int                               curW            = gridLayout[cellNdx].z();
1889                         const int                               curH            = gridLayout[cellNdx].w();
1890                         const tcu::CubeFace             cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
1891
1892                         computeQuadTexCoordCube(texCoord, cubeFace);
1893                         getReferenceParams(params, cellNdx);
1894
1895                         // Render ideal reference.
1896                         {
1897                                 tcu::SurfaceAccess idealDst(referenceFrame, m_context.getRenderTarget().getPixelFormat(), curX, curY, curW, curH);
1898                                 sampleTexture(idealDst, m_texture->getRefTexture(), &texCoord[0], params);
1899                         }
1900
1901                         // Compare this cell
1902                         numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
1903                                                                                                                 tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
1904                                                                                                                 tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
1905                                                                                                                 m_texture->getRefTexture(), &texCoord[0], params,
1906                                                                                                                 lookupPrec, lodPrec, m_testCtx.getWatchDog());
1907                 }
1908
1909                 if (numFailedPixels > 0)
1910                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1911
1912                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
1913                                                    << TestLog::Image("Rendered", "Rendered image", renderedFrame);
1914
1915                 if (numFailedPixels > 0)
1916                 {
1917                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
1918                                                            << TestLog::Image("ErrorMask", "Error mask", errorMask);
1919                 }
1920
1921                 m_testCtx.getLog() << TestLog::EndImageSet;
1922
1923                 {
1924                         const bool isOk = numFailedPixels == 0;
1925                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
1926                                                                         isOk ? "Pass"                           : "Image verification failed");
1927                 }
1928         }
1929
1930         return STOP;
1931 }
1932
1933 class TextureCubeMinLodCase : public TextureCubeLodControlCase
1934 {
1935 public:
1936         TextureCubeMinLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1937                 : TextureCubeLodControlCase(context, name, desc, minFilter)
1938         {
1939         }
1940
1941 protected:
1942         void setTextureParams (int cellNdx)
1943         {
1944                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1945                 gl.texParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_LOD, getMinLodForCell(cellNdx));
1946         }
1947
1948         void getReferenceParams (ReferenceParams& params, int cellNdx)
1949         {
1950                 params.minLod = getMinLodForCell(cellNdx);
1951         }
1952 };
1953
1954 class TextureCubeMaxLodCase : public TextureCubeLodControlCase
1955 {
1956 public:
1957         TextureCubeMaxLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1958                 : TextureCubeLodControlCase(context, name, desc, minFilter)
1959         {
1960         }
1961
1962 protected:
1963         void setTextureParams (int cellNdx)
1964         {
1965                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1966                 gl.texParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LOD, getMaxLodForCell(cellNdx));
1967         }
1968
1969         void getReferenceParams (ReferenceParams& params, int cellNdx)
1970         {
1971                 params.maxLod = getMaxLodForCell(cellNdx);
1972         }
1973 };
1974
1975 class TextureCubeBaseLevelCase : public TextureCubeLodControlCase
1976 {
1977 public:
1978         TextureCubeBaseLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
1979                 : TextureCubeLodControlCase(context, name, desc, minFilter)
1980         {
1981         }
1982
1983 protected:
1984         int getBaseLevel (int cellNdx) const
1985         {
1986                 const int       numLevels       = deLog2Floor32(m_texSize)+1;
1987                 const int       baseLevel       = (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x23fae13) % numLevels;
1988
1989                 return baseLevel;
1990         }
1991
1992         void setTextureParams (int cellNdx)
1993         {
1994                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1995                 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, getBaseLevel(cellNdx));
1996         }
1997
1998         void getReferenceParams (ReferenceParams& params, int cellNdx)
1999         {
2000                 params.baseLevel = getBaseLevel(cellNdx);
2001         }
2002 };
2003
2004 class TextureCubeMaxLevelCase : public TextureCubeLodControlCase
2005 {
2006 public:
2007         TextureCubeMaxLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2008                 : TextureCubeLodControlCase(context, name, desc, minFilter)
2009         {
2010         }
2011
2012 protected:
2013         int getMaxLevel (int cellNdx) const
2014         {
2015                 const int       numLevels       = deLog2Floor32(m_texSize)+1;
2016                 const int       maxLevel        = (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x974e21) % numLevels;
2017
2018                 return maxLevel;
2019         }
2020
2021         void setTextureParams (int cellNdx)
2022         {
2023                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2024                 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, getMaxLevel(cellNdx));
2025         }
2026
2027         void getReferenceParams (ReferenceParams& params, int cellNdx)
2028         {
2029                 params.maxLevel = getMaxLevel(cellNdx);
2030         }
2031 };
2032
2033 // Texture3DLodControlCase + test cases
2034
2035 class Texture3DLodControlCase : public TestCase
2036 {
2037 public:
2038
2039                                                                                 Texture3DLodControlCase         (Context& context, const char* name, const char* desc, deUint32 minFilter);
2040                                                                                 ~Texture3DLodControlCase        (void);
2041
2042         void                                                            init                                            (void);
2043         void                                                            deinit                                          (void);
2044         IterateResult                                           iterate                                         (void);
2045
2046 protected:
2047         virtual void                                            setTextureParams                        (int cellNdx)                                           = DE_NULL;
2048         virtual void                                            getReferenceParams                      (ReferenceParams& params, int cellNdx)  = DE_NULL;
2049
2050         const int                                                       m_texWidth;
2051         const int                                                       m_texHeight;
2052         const int                                                       m_texDepth;
2053
2054 private:
2055                                                                                 Texture3DLodControlCase         (const Texture3DLodControlCase& other);
2056         Texture3DLodControlCase&                        operator=                                       (const Texture3DLodControlCase& other);
2057
2058         deUint32                                                        m_minFilter;
2059
2060         glu::Texture3D*                                         m_texture;
2061         TextureTestUtil::TextureRenderer        m_renderer;
2062 };
2063
2064 Texture3DLodControlCase::Texture3DLodControlCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2065         : TestCase                      (context, name, desc)
2066         , m_texWidth            (32)
2067         , m_texHeight           (32)
2068         , m_texDepth            (32)
2069         , m_minFilter           (minFilter)
2070         , m_texture                     (DE_NULL)
2071         , m_renderer            (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
2072 {
2073 }
2074
2075 Texture3DLodControlCase::~Texture3DLodControlCase (void)
2076 {
2077         Texture3DLodControlCase::deinit();
2078 }
2079
2080 void Texture3DLodControlCase::init (void)
2081 {
2082         const deUint32                                  format                  = GL_RGBA8;
2083         const tcu::TextureFormat&               texFmt                  = glu::mapGLInternalFormat(format);
2084         tcu::TextureFormatInfo                  fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
2085         const tcu::Vec4&                                cScale                  = fmtInfo.lookupScale;
2086         const tcu::Vec4&                                cBias                   = fmtInfo.lookupBias;
2087         int                                                             numLevels               = deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth))+1;
2088
2089         m_texture = new glu::Texture3D(m_context.getRenderContext(), format, m_texWidth, m_texHeight, m_texDepth);
2090
2091         // Fill texture with colored grid.
2092         for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
2093         {
2094                 deUint32        step            = 0xff / (numLevels-1);
2095                 deUint32        inc                     = deClamp32(step*levelNdx, 0x00, 0xff);
2096                 deUint32        dec                     = 0xff - inc;
2097                 deUint32        rgb                     = (inc << 16) | (dec << 8) | 0xff;
2098                 deUint32        color           = 0xff000000 | rgb;
2099
2100                 m_texture->getRefTexture().allocLevel(levelNdx);
2101                 tcu::clear(m_texture->getRefTexture().getLevel(levelNdx), tcu::RGBA(color).toVec()*cScale + cBias);
2102         }
2103
2104         m_texture->upload();
2105 }
2106
2107 void Texture3DLodControlCase::deinit (void)
2108 {
2109         delete m_texture;
2110         m_texture = DE_NULL;
2111
2112         m_renderer.clear();
2113 }
2114
2115 Texture3DLodControlCase::IterateResult Texture3DLodControlCase::iterate (void)
2116 {
2117         const glw::Functions&                   gl                                      = m_context.getRenderContext().getFunctions();
2118
2119         const deUint32                                  wrapS                           = GL_CLAMP_TO_EDGE;
2120         const deUint32                                  wrapT                           = GL_CLAMP_TO_EDGE;
2121         const deUint32                                  wrapR                           = GL_CLAMP_TO_EDGE;
2122         const deUint32                                  magFilter                       = GL_NEAREST;
2123         const tcu::Texture3D&                   refTexture                      = m_texture->getRefTexture();
2124         const tcu::TextureFormat&               texFmt                          = refTexture.getFormat();
2125         const tcu::TextureFormatInfo    fmtInfo                         = tcu::getTextureFormatInfo(texFmt);
2126         const int                                               texWidth                        = refTexture.getWidth();
2127         const int                                               texHeight                       = refTexture.getHeight();
2128
2129         const tcu::RenderTarget&                renderTarget            = m_context.getRenderContext().getRenderTarget();
2130         const RandomViewport                    viewport                        (renderTarget, texWidth*4, texHeight*4, deStringHash(getName()));
2131
2132         // Viewport is divided into 4x4 grid.
2133         const int                                               gridWidth                       = 4;
2134         const int                                               gridHeight                      = 4;
2135         const int                                               cellWidth                       = viewport.width / gridWidth;
2136         const int                                               cellHeight                      = viewport.height / gridHeight;
2137
2138         tcu::Surface                                    renderedFrame           (viewport.width, viewport.height);
2139         vector<float>                                   texCoord;
2140         ReferenceParams                                 sampleParams            (TEXTURETYPE_3D);
2141
2142         // Sampling parameters.
2143         sampleParams.sampler            = glu::mapGLSampler(wrapS, wrapT, wrapR, m_minFilter, magFilter);
2144         sampleParams.samplerType        = getSamplerType(texFmt);
2145         sampleParams.colorBias          = fmtInfo.lookupBias;
2146         sampleParams.colorScale         = fmtInfo.lookupScale;
2147
2148         // Bind texture and setup sampler parameters.
2149         gl.bindTexture  (GL_TEXTURE_3D, m_texture->getGLTexture());
2150         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,              wrapS);
2151         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,              wrapT);
2152         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,              wrapR);
2153         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,  m_minFilter);
2154         gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,  magFilter);
2155
2156         GLU_EXPECT_NO_ERROR(gl.getError(), "After texture setup");
2157
2158         // Render cells.
2159         for (int gridY = 0; gridY < gridHeight; gridY++)
2160         {
2161                 for (int gridX = 0; gridX < gridWidth; gridX++)
2162                 {
2163                         int             curX            = cellWidth*gridX;
2164                         int             curY            = cellHeight*gridY;
2165                         int             curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
2166                         int             curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
2167                         int             cellNdx         = gridY*gridWidth + gridX;
2168
2169                         // Compute texcoord.
2170                         getBasicTexCoord3D(texCoord, cellNdx);
2171
2172                         setTextureParams(cellNdx);
2173
2174                         // Render with GL.
2175                         gl.viewport(viewport.x+curX, viewport.y+curY, curW, curH);
2176                         m_renderer.renderQuad(0, &texCoord[0], sampleParams);
2177                 }
2178         }
2179
2180         // Read result.
2181         glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, renderedFrame.getAccess());
2182
2183         // Compare and log
2184         {
2185                 const tcu::PixelFormat& pixelFormat             = m_context.getRenderTarget().getPixelFormat();
2186                 const bool                              isTrilinear             = m_minFilter == GL_NEAREST_MIPMAP_LINEAR || m_minFilter == GL_LINEAR_MIPMAP_LINEAR;
2187                 tcu::Surface                    referenceFrame  (viewport.width, viewport.height);
2188                 tcu::Surface                    errorMask               (viewport.width, viewport.height);
2189                 tcu::LookupPrecision    lookupPrec;
2190                 tcu::LodPrecision               lodPrec                 (tcu::LodPrecision::RULE_OPENGL);
2191                 int                                             numFailedPixels = 0;
2192
2193                 lookupPrec.coordBits            = tcu::IVec3(20, 20, 20);
2194                 lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
2195                 lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
2196                 lookupPrec.colorMask            = getCompareMask(pixelFormat);
2197                 lodPrec.derivateBits            = 10;
2198                 lodPrec.lodBits                         = 8;
2199
2200                 for (int gridY = 0; gridY < gridHeight; gridY++)
2201                 {
2202                         for (int gridX = 0; gridX < gridWidth; gridX++)
2203                         {
2204                                 const int               curX            = cellWidth*gridX;
2205                                 const int               curY            = cellHeight*gridY;
2206                                 const int               curW            = gridX+1 == gridWidth ? (viewport.width-curX) : cellWidth;
2207                                 const int               curH            = gridY+1 == gridHeight ? (viewport.height-curY) : cellHeight;
2208                                 const int               cellNdx         = gridY*gridWidth + gridX;
2209
2210                                 getBasicTexCoord3D(texCoord, cellNdx);
2211                                 getReferenceParams(sampleParams, cellNdx);
2212
2213                                 // Render ideal result
2214                                 sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
2215                                                           refTexture, &texCoord[0], sampleParams);
2216
2217                                 // Compare this cell
2218                                 numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
2219                                                                                                                         tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
2220                                                                                                                         tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
2221                                                                                                                         m_texture->getRefTexture(), &texCoord[0], sampleParams,
2222                                                                                                                         lookupPrec, lodPrec, m_testCtx.getWatchDog());
2223                         }
2224                 }
2225
2226                 if (numFailedPixels > 0)
2227                         m_testCtx.getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2228
2229                 m_testCtx.getLog() << TestLog::ImageSet("Result", "Verification result")
2230                                                         << TestLog::Image("Rendered", "Rendered image", renderedFrame);
2231
2232                 if (numFailedPixels > 0)
2233                 {
2234                         m_testCtx.getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
2235                                                                 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2236                 }
2237
2238                 m_testCtx.getLog() << TestLog::EndImageSet;
2239
2240                 {
2241                         const bool isOk = numFailedPixels == 0;
2242                         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
2243                                                                         isOk ? "Pass"                           : "Image verification failed");
2244                 }
2245         }
2246
2247         return STOP;
2248 }
2249
2250 class Texture3DMinLodCase : public Texture3DLodControlCase
2251 {
2252 public:
2253         Texture3DMinLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2254                 : Texture3DLodControlCase(context, name, desc, minFilter)
2255         {
2256         }
2257
2258 protected:
2259         void setTextureParams (int cellNdx)
2260         {
2261                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2262                 gl.texParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_LOD, getMinLodForCell(cellNdx));
2263         }
2264
2265         void getReferenceParams (ReferenceParams& params, int cellNdx)
2266         {
2267                 params.minLod = getMinLodForCell(cellNdx);
2268         }
2269 };
2270
2271 class Texture3DMaxLodCase : public Texture3DLodControlCase
2272 {
2273 public:
2274         Texture3DMaxLodCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2275                 : Texture3DLodControlCase(context, name, desc, minFilter)
2276         {
2277         }
2278
2279 protected:
2280         void setTextureParams (int cellNdx)
2281         {
2282                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2283                 gl.texParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAX_LOD, getMaxLodForCell(cellNdx));
2284         }
2285
2286         void getReferenceParams (ReferenceParams& params, int cellNdx)
2287         {
2288                 params.maxLod = getMaxLodForCell(cellNdx);
2289         }
2290 };
2291
2292 class Texture3DBaseLevelCase : public Texture3DLodControlCase
2293 {
2294 public:
2295         Texture3DBaseLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2296                 : Texture3DLodControlCase(context, name, desc, minFilter)
2297         {
2298         }
2299
2300 protected:
2301         int getBaseLevel (int cellNdx) const
2302         {
2303                 const int       numLevels       = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
2304                 const int       baseLevel       = (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x7347e9) % numLevels;
2305
2306                 return baseLevel;
2307         }
2308
2309         void setTextureParams (int cellNdx)
2310         {
2311                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2312                 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, getBaseLevel(cellNdx));
2313         }
2314
2315         void getReferenceParams (ReferenceParams& params, int cellNdx)
2316         {
2317                 params.baseLevel = getBaseLevel(cellNdx);
2318         }
2319 };
2320
2321 class Texture3DMaxLevelCase : public Texture3DLodControlCase
2322 {
2323 public:
2324         Texture3DMaxLevelCase (Context& context, const char* name, const char* desc, deUint32 minFilter)
2325                 : Texture3DLodControlCase(context, name, desc, minFilter)
2326         {
2327         }
2328
2329 protected:
2330         int getMaxLevel (int cellNdx) const
2331         {
2332                 const int       numLevels       = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
2333                 const int       maxLevel        = (deInt32Hash(cellNdx) ^ deStringHash(getName()) ^ 0x9111e7) % numLevels;
2334
2335                 return maxLevel;
2336         }
2337
2338         void setTextureParams (int cellNdx)
2339         {
2340                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2341                 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, getMaxLevel(cellNdx));
2342         }
2343
2344         void getReferenceParams (ReferenceParams& params, int cellNdx)
2345         {
2346                 params.maxLevel = getMaxLevel(cellNdx);
2347         }
2348 };
2349
2350 TextureMipmapTests::TextureMipmapTests (Context& context)
2351         : TestCaseGroup(context, "mipmap", "Mipmapping tests")
2352 {
2353 }
2354
2355 TextureMipmapTests::~TextureMipmapTests (void)
2356 {
2357 }
2358
2359 void TextureMipmapTests::init (void)
2360 {
2361         tcu::TestCaseGroup* group2D             = new tcu::TestCaseGroup(m_testCtx, "2d",       "2D Texture Mipmapping");
2362         tcu::TestCaseGroup*     groupCube       = new tcu::TestCaseGroup(m_testCtx, "cube",     "Cube Map Mipmapping");
2363         tcu::TestCaseGroup*     group3D         = new tcu::TestCaseGroup(m_testCtx, "3d",       "3D Texture Mipmapping");
2364         addChild(group2D);
2365         addChild(groupCube);
2366         addChild(group3D);
2367
2368         static const struct
2369         {
2370                 const char*             name;
2371                 deUint32                mode;
2372         } wrapModes[] =
2373         {
2374                 { "clamp",              GL_CLAMP_TO_EDGE },
2375                 { "repeat",             GL_REPEAT },
2376                 { "mirror",             GL_MIRRORED_REPEAT }
2377         };
2378
2379         static const struct
2380         {
2381                 const char*             name;
2382                 deUint32                mode;
2383         } minFilterModes[] =
2384         {
2385                 { "nearest_nearest",    GL_NEAREST_MIPMAP_NEAREST       },
2386                 { "linear_nearest",             GL_LINEAR_MIPMAP_NEAREST        },
2387                 { "nearest_linear",             GL_NEAREST_MIPMAP_LINEAR        },
2388                 { "linear_linear",              GL_LINEAR_MIPMAP_LINEAR         }
2389         };
2390
2391         static const struct
2392         {
2393                 CoordType               type;
2394                 const char*             name;
2395                 const char*             desc;
2396         } coordTypes[] =
2397         {
2398                 { COORDTYPE_BASIC,              "basic",                "Mipmapping with translated and scaled coordinates" },
2399                 { COORDTYPE_AFFINE,             "affine",               "Mipmapping with affine coordinate transform"           },
2400                 { COORDTYPE_PROJECTED,  "projected",    "Mipmapping with perspective projection"                        }
2401         };
2402
2403         static const struct
2404         {
2405                 const char*             name;
2406                 deUint32                format;
2407                 deUint32                dataType;
2408         } formats[] =
2409         {
2410                 { "a8",                 GL_ALPHA,                       GL_UNSIGNED_BYTE },
2411                 { "l8",                 GL_LUMINANCE,           GL_UNSIGNED_BYTE },
2412                 { "la88",               GL_LUMINANCE_ALPHA,     GL_UNSIGNED_BYTE },
2413                 { "rgb565",             GL_RGB,                         GL_UNSIGNED_SHORT_5_6_5 },
2414                 { "rgb888",             GL_RGB,                         GL_UNSIGNED_BYTE },
2415                 { "rgba4444",   GL_RGBA,                        GL_UNSIGNED_SHORT_4_4_4_4 },
2416                 { "rgba5551",   GL_RGBA,                        GL_UNSIGNED_SHORT_5_5_5_1 },
2417                 { "rgba8888",   GL_RGBA,                        GL_UNSIGNED_BYTE }
2418         };
2419
2420         static const struct
2421         {
2422                 const char*             name;
2423                 deUint32                hint;
2424         } genHints[] =
2425         {
2426                 { "fastest",    GL_FASTEST },
2427                 { "nicest",             GL_NICEST }
2428         };
2429
2430         static const struct
2431         {
2432                 const char*             name;
2433                 int                             width;
2434                 int                             height;
2435         } tex2DSizes[] =
2436         {
2437                 { DE_NULL,              64, 64 }, // Default.
2438                 { "npot",               63, 57 },
2439                 { "non_square", 32, 64 }
2440         };
2441
2442         static const struct
2443         {
2444                 const char*             name;
2445                 int                             width;
2446                 int                             height;
2447                 int                             depth;
2448         } tex3DSizes[] =
2449         {
2450                 { DE_NULL,              32, 32, 32 }, // Default.
2451                 { "npot",               33, 29, 27 }
2452         };
2453
2454         const int cubeMapSize = 64;
2455
2456         static const struct
2457         {
2458                 CoordType               type;
2459                 const char*             name;
2460                 const char*             desc;
2461         } cubeCoordTypes[] =
2462         {
2463                 { COORDTYPE_BASIC,              "basic",                "Mipmapping with translated and scaled coordinates" },
2464                 { COORDTYPE_PROJECTED,  "projected",    "Mipmapping with perspective projection"                        },
2465                 { COORDTYPE_BASIC_BIAS, "bias",                 "User-supplied bias value"                                                      }
2466         };
2467
2468         // 2D cases.
2469         for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
2470         {
2471                 tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
2472                 group2D->addChild(coordTypeGroup);
2473
2474                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2475                 {
2476                         for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
2477                         {
2478                                 // Add non_square variants to basic cases only.
2479                                 int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
2480
2481                                 for (int size = 0; size < sizeEnd; size++)
2482                                 {
2483                                         std::ostringstream name;
2484                                         name << minFilterModes[minFilter].name
2485                                                  << "_" << wrapModes[wrapMode].name;
2486
2487                                         if (tex2DSizes[size].name)
2488                                                 name << "_" << tex2DSizes[size].name;
2489
2490                                         coordTypeGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
2491                                                                                                                                          name.str().c_str(), "",
2492                                                                                                                                          coordTypes[coordType].type,
2493                                                                                                                                          minFilterModes[minFilter].mode,
2494                                                                                                                                          wrapModes[wrapMode].mode,
2495                                                                                                                                          wrapModes[wrapMode].mode,
2496                                                                                                                                          GL_RGBA, GL_UNSIGNED_BYTE,
2497                                                                                                                                          tex2DSizes[size].width, tex2DSizes[size].height));
2498                                 }
2499                         }
2500                 }
2501         }
2502
2503         // 2D bias variants.
2504         {
2505                 tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
2506                 group2D->addChild(biasGroup);
2507
2508                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2509                         biasGroup->addChild(new Texture2DMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
2510                                                                                                                 minFilterModes[minFilter].name, "",
2511                                                                                                                 COORDTYPE_BASIC_BIAS,
2512                                                                                                                 minFilterModes[minFilter].mode,
2513                                                                                                                 GL_REPEAT, GL_REPEAT,
2514                                                                                                                 GL_RGBA, GL_UNSIGNED_BYTE,
2515                                                                                                                 tex2DSizes[0].width, tex2DSizes[0].height));
2516         }
2517
2518         // 2D mipmap generation variants.
2519         {
2520                 tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
2521                 group2D->addChild(genMipmapGroup);
2522
2523                 for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
2524                 {
2525                         for (int size = 0; size < DE_LENGTH_OF_ARRAY(tex2DSizes); size++)
2526                         {
2527                                 for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
2528                                 {
2529                                         std::ostringstream name;
2530                                         name << formats[format].name;
2531
2532                                         if (tex2DSizes[size].name)
2533                                                 name << "_" << tex2DSizes[size].name;
2534
2535                                         name << "_" << genHints[hint].name;
2536
2537                                         genMipmapGroup->addChild(new Texture2DGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
2538                                                                                                                                                 formats[format].format, formats[format].dataType, genHints[hint].hint,
2539                                                                                                                                                 tex2DSizes[size].width, tex2DSizes[size].height));
2540                                 }
2541                         }
2542                 }
2543         }
2544
2545         // 2D LOD controls.
2546         {
2547                 // MIN_LOD
2548                 tcu::TestCaseGroup* minLodGroup = new tcu::TestCaseGroup(m_testCtx, "min_lod", "Lod control: min lod");
2549                 group2D->addChild(minLodGroup);
2550
2551                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2552                         minLodGroup->addChild(new Texture2DMinLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2553
2554                 // MAX_LOD
2555                 tcu::TestCaseGroup* maxLodGroup = new tcu::TestCaseGroup(m_testCtx, "max_lod", "Lod control: max lod");
2556                 group2D->addChild(maxLodGroup);
2557
2558                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2559                         maxLodGroup->addChild(new Texture2DMaxLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2560
2561                 // BASE_LEVEL
2562                 tcu::TestCaseGroup* baseLevelGroup = new tcu::TestCaseGroup(m_testCtx, "base_level", "Base level");
2563                 group2D->addChild(baseLevelGroup);
2564
2565                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2566                         baseLevelGroup->addChild(new Texture2DBaseLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2567
2568                 // MAX_LEVEL
2569                 tcu::TestCaseGroup* maxLevelGroup = new tcu::TestCaseGroup(m_testCtx, "max_level", "Max level");
2570                 group2D->addChild(maxLevelGroup);
2571
2572                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2573                         maxLevelGroup->addChild(new Texture2DMaxLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2574         }
2575
2576         // Cubemap cases.
2577         for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
2578         {
2579                 tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc);
2580                 groupCube->addChild(coordTypeGroup);
2581
2582                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2583                 {
2584                         coordTypeGroup->addChild(new TextureCubeMipmapCase(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
2585                                                                                                                            minFilterModes[minFilter].name, "",
2586                                                                                                                            cubeCoordTypes[coordType].type,
2587                                                                                                                            minFilterModes[minFilter].mode,
2588                                                                                                                            GL_CLAMP_TO_EDGE,
2589                                                                                                                            GL_CLAMP_TO_EDGE,
2590                                                                                                                            GL_RGBA, GL_UNSIGNED_BYTE, cubeMapSize));
2591                 }
2592         }
2593
2594         // Cubemap mipmap generation variants.
2595         {
2596                 tcu::TestCaseGroup* genMipmapGroup = new tcu::TestCaseGroup(m_testCtx, "generate", "Mipmap generation tests");
2597                 groupCube->addChild(genMipmapGroup);
2598
2599                 for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); format++)
2600                 {
2601                         for (int hint = 0; hint < DE_LENGTH_OF_ARRAY(genHints); hint++)
2602                         {
2603                                 std::ostringstream name;
2604                                 name << formats[format].name
2605                                          << "_" << genHints[hint].name;
2606
2607                                 genMipmapGroup->addChild(new TextureCubeGenMipmapCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "", formats[format].format, formats[format].dataType, genHints[hint].hint, cubeMapSize));
2608                         }
2609                 }
2610         }
2611
2612         // Cubemap LOD controls.
2613         {
2614                 // MIN_LOD
2615                 tcu::TestCaseGroup* minLodGroup = new tcu::TestCaseGroup(m_testCtx, "min_lod", "Lod control: min lod");
2616                 groupCube->addChild(minLodGroup);
2617
2618                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2619                         minLodGroup->addChild(new TextureCubeMinLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2620
2621                 // MAX_LOD
2622                 tcu::TestCaseGroup* maxLodGroup = new tcu::TestCaseGroup(m_testCtx, "max_lod", "Lod control: max lod");
2623                 groupCube->addChild(maxLodGroup);
2624
2625                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2626                         maxLodGroup->addChild(new TextureCubeMaxLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2627
2628                 // BASE_LEVEL
2629                 tcu::TestCaseGroup* baseLevelGroup = new tcu::TestCaseGroup(m_testCtx, "base_level", "Base level");
2630                 groupCube->addChild(baseLevelGroup);
2631
2632                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2633                         baseLevelGroup->addChild(new TextureCubeBaseLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2634
2635                 // MAX_LEVEL
2636                 tcu::TestCaseGroup* maxLevelGroup = new tcu::TestCaseGroup(m_testCtx, "max_level", "Max level");
2637                 groupCube->addChild(maxLevelGroup);
2638
2639                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2640                         maxLevelGroup->addChild(new TextureCubeMaxLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2641         }
2642
2643         // 3D cases.
2644         for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
2645         {
2646                 tcu::TestCaseGroup* coordTypeGroup = new tcu::TestCaseGroup(m_testCtx, coordTypes[coordType].name, coordTypes[coordType].desc);
2647                 group3D->addChild(coordTypeGroup);
2648
2649                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2650                 {
2651                         for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
2652                         {
2653                                 // Add other size variants to basic cases only.
2654                                 int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex3DSizes) : 1;
2655
2656                                 for (int size = 0; size < sizeEnd; size++)
2657                                 {
2658                                         std::ostringstream name;
2659                                         name << minFilterModes[minFilter].name
2660                                                  << "_" << wrapModes[wrapMode].name;
2661
2662                                         if (tex3DSizes[size].name)
2663                                                 name << "_" << tex3DSizes[size].name;
2664
2665                                         coordTypeGroup->addChild(new Texture3DMipmapCase(m_context,
2666                                                                                                                                          name.str().c_str(), "",
2667                                                                                                                                          coordTypes[coordType].type,
2668                                                                                                                                          minFilterModes[minFilter].mode,
2669                                                                                                                                          wrapModes[wrapMode].mode,
2670                                                                                                                                          wrapModes[wrapMode].mode,
2671                                                                                                                                          wrapModes[wrapMode].mode,
2672                                                                                                                                          GL_RGBA8,
2673                                                                                                                                          tex3DSizes[size].width, tex3DSizes[size].height, tex3DSizes[size].depth));
2674                                 }
2675                         }
2676                 }
2677         }
2678
2679         // 3D bias variants.
2680         {
2681                 tcu::TestCaseGroup* biasGroup = new tcu::TestCaseGroup(m_testCtx, "bias", "User-supplied bias value");
2682                 group3D->addChild(biasGroup);
2683
2684                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2685                         biasGroup->addChild(new Texture3DMipmapCase(m_context,
2686                                                                                                                 minFilterModes[minFilter].name, "",
2687                                                                                                                 COORDTYPE_BASIC_BIAS,
2688                                                                                                                 minFilterModes[minFilter].mode,
2689                                                                                                                 GL_REPEAT, GL_REPEAT, GL_REPEAT,
2690                                                                                                                 GL_RGBA8,
2691                                                                                                                 tex3DSizes[0].width, tex3DSizes[0].height, tex3DSizes[0].depth));
2692         }
2693
2694         // 3D LOD controls.
2695         {
2696                 // MIN_LOD
2697                 tcu::TestCaseGroup* minLodGroup = new tcu::TestCaseGroup(m_testCtx, "min_lod", "Lod control: min lod");
2698                 group3D->addChild(minLodGroup);
2699
2700                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2701                         minLodGroup->addChild(new Texture3DMinLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2702
2703                 // MAX_LOD
2704                 tcu::TestCaseGroup* maxLodGroup = new tcu::TestCaseGroup(m_testCtx, "max_lod", "Lod control: max lod");
2705                 group3D->addChild(maxLodGroup);
2706
2707                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2708                         maxLodGroup->addChild(new Texture3DMaxLodCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2709
2710                 // BASE_LEVEL
2711                 tcu::TestCaseGroup* baseLevelGroup = new tcu::TestCaseGroup(m_testCtx, "base_level", "Base level");
2712                 group3D->addChild(baseLevelGroup);
2713
2714                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2715                         baseLevelGroup->addChild(new Texture3DBaseLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2716
2717                 // MAX_LEVEL
2718                 tcu::TestCaseGroup* maxLevelGroup = new tcu::TestCaseGroup(m_testCtx, "max_level", "Max level");
2719                 group3D->addChild(maxLevelGroup);
2720
2721                 for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
2722                         maxLevelGroup->addChild(new Texture3DMaxLevelCase(m_context, minFilterModes[minFilter].name, "", minFilterModes[minFilter].mode));
2723         }
2724 }
2725
2726 } // Functional
2727 } // gles3
2728 } // deqp