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