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