xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fTextureSizeTests.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 Texture size tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fTextureSizeTests.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 
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 
36 namespace deqp
37 {
38 namespace gles3
39 {
40 namespace Functional
41 {
42 
43 using std::string;
44 using std::vector;
45 using tcu::Sampler;
46 using tcu::TestLog;
47 using namespace glu;
48 using namespace gls::TextureTestUtil;
49 using namespace glu::TextureTestUtil;
50 
51 class Texture2DSizeCase : public tcu::TestCase
52 {
53 public:
54     Texture2DSizeCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const char *name,
55                       const char *description, uint32_t format, uint32_t dataType, int width, int height, bool mipmaps);
56     ~Texture2DSizeCase(void);
57 
58     void init(void);
59     void deinit(void);
60     IterateResult iterate(void);
61 
62 private:
63     Texture2DSizeCase(const Texture2DSizeCase &other);
64     Texture2DSizeCase &operator=(const Texture2DSizeCase &other);
65 
66     glu::RenderContext &m_renderCtx;
67 
68     uint32_t m_format;
69     uint32_t m_dataType;
70     int m_width;
71     int m_height;
72     bool m_useMipmaps;
73 
74     glu::Texture2D *m_texture;
75     TextureRenderer m_renderer;
76 };
77 
Texture2DSizeCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,uint32_t format,uint32_t dataType,int width,int height,bool mipmaps)78 Texture2DSizeCase::Texture2DSizeCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const char *name,
79                                      const char *description, uint32_t format, uint32_t dataType, int width, int height,
80                                      bool mipmaps)
81     : TestCase(testCtx, name, description)
82     , m_renderCtx(renderCtx)
83     , m_format(format)
84     , m_dataType(dataType)
85     , m_width(width)
86     , m_height(height)
87     , m_useMipmaps(mipmaps)
88     , m_texture(DE_NULL)
89     , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_MEDIUMP)
90 {
91 }
92 
~Texture2DSizeCase(void)93 Texture2DSizeCase::~Texture2DSizeCase(void)
94 {
95     Texture2DSizeCase::deinit();
96 }
97 
init(void)98 void Texture2DSizeCase::init(void)
99 {
100     DE_ASSERT(!m_texture);
101     m_texture = new Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height);
102 
103     int numLevels = m_useMipmaps ? deLog2Floor32(de::max(m_width, m_height)) + 1 : 1;
104 
105     // Fill levels.
106     for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
107     {
108         m_texture->getRefTexture().allocLevel(levelNdx);
109         tcu::fillWithComponentGradients(m_texture->getRefTexture().getLevel(levelNdx),
110                                         tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
111     }
112 }
113 
deinit(void)114 void Texture2DSizeCase::deinit(void)
115 {
116     delete m_texture;
117     m_texture = DE_NULL;
118 
119     m_renderer.clear();
120 }
121 
iterate(void)122 Texture2DSizeCase::IterateResult Texture2DSizeCase::iterate(void)
123 {
124     const glw::Functions &gl = m_renderCtx.getFunctions();
125     TestLog &log             = m_testCtx.getLog();
126     RandomViewport viewport(m_renderCtx.getRenderTarget(), 128, 128, deStringHash(getName()));
127     tcu::Surface renderedFrame(viewport.width, viewport.height);
128     tcu::Surface referenceFrame(viewport.width, viewport.height);
129     const tcu::IVec4 texBits      = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
130     const tcu::PixelFormat &rtFmt = m_renderCtx.getRenderTarget().getPixelFormat();
131     const tcu::PixelFormat thresholdFormat(de::min(texBits[0], rtFmt.redBits), de::min(texBits[1], rtFmt.greenBits),
132                                            de::min(texBits[2], rtFmt.blueBits), de::min(texBits[3], rtFmt.alphaBits));
133     tcu::RGBA threshold = thresholdFormat.getColorThreshold() + tcu::RGBA(7, 7, 7, 7);
134     uint32_t wrapS      = GL_CLAMP_TO_EDGE;
135     uint32_t wrapT      = GL_CLAMP_TO_EDGE;
136     // Do not minify with GL_NEAREST. A large POT texture with a small POT render target will produce
137     // indeterminate results.
138     uint32_t minFilter = m_useMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR;
139     uint32_t magFilter = GL_NEAREST;
140     vector<float> texCoord;
141 
142     computeQuadTexCoord2D(texCoord, tcu::Vec2(0.0f, 0.0f), tcu::Vec2(1.0f, 1.0f));
143 
144     // Setup base viewport.
145     gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
146 
147     // Upload texture data to GL.
148     m_texture->upload();
149 
150     // Bind to unit 0.
151     gl.activeTexture(GL_TEXTURE0);
152     gl.bindTexture(GL_TEXTURE_2D, m_texture->getGLTexture());
153 
154     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
155     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
156     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
157     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
158     GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
159 
160     // Draw.
161     m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_2D);
162     glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
163 
164     // Compute reference.
165     sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat()),
166                   m_texture->getRefTexture(), &texCoord[0],
167                   ReferenceParams(TEXTURETYPE_2D, mapGLSampler(wrapS, wrapT, minFilter, magFilter)));
168 
169     // Compare and log.
170     bool isOk = compareImages(log, referenceFrame, renderedFrame, threshold);
171 
172     m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
173                             isOk ? "Pass" : "Image comparison failed");
174 
175     return STOP;
176 }
177 
178 class TextureCubeSizeCase : public tcu::TestCase
179 {
180 public:
181     TextureCubeSizeCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const char *name,
182                         const char *description, uint32_t format, uint32_t dataType, int width, int height,
183                         bool mipmaps);
184     ~TextureCubeSizeCase(void);
185 
186     void init(void);
187     void deinit(void);
188     IterateResult iterate(void);
189 
190 private:
191     TextureCubeSizeCase(const TextureCubeSizeCase &other);
192     TextureCubeSizeCase &operator=(const TextureCubeSizeCase &other);
193 
194     bool testFace(tcu::CubeFace face);
195 
196     glu::RenderContext &m_renderCtx;
197 
198     uint32_t m_format;
199     uint32_t m_dataType;
200     int m_width;
201     int m_height;
202     bool m_useMipmaps;
203 
204     glu::TextureCube *m_texture;
205     TextureRenderer m_renderer;
206 
207     int m_curFace;
208     bool m_isOk;
209 };
210 
TextureCubeSizeCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,uint32_t format,uint32_t dataType,int width,int height,bool mipmaps)211 TextureCubeSizeCase::TextureCubeSizeCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const char *name,
212                                          const char *description, uint32_t format, uint32_t dataType, int width,
213                                          int height, bool mipmaps)
214     : TestCase(testCtx, name, description)
215     , m_renderCtx(renderCtx)
216     , m_format(format)
217     , m_dataType(dataType)
218     , m_width(width)
219     , m_height(height)
220     , m_useMipmaps(mipmaps)
221     , m_texture(DE_NULL)
222     , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_MEDIUMP)
223     , m_curFace(0)
224     , m_isOk(false)
225 {
226 }
227 
~TextureCubeSizeCase(void)228 TextureCubeSizeCase::~TextureCubeSizeCase(void)
229 {
230     TextureCubeSizeCase::deinit();
231 }
232 
init(void)233 void TextureCubeSizeCase::init(void)
234 {
235     DE_ASSERT(!m_texture);
236     DE_ASSERT(m_width == m_height);
237     m_texture = new TextureCube(m_renderCtx, m_format, m_dataType, m_width);
238 
239     static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = {
240         {tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative x
241         {tcu::Vec4(0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)},  // positive x
242         {tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)},  // negative y
243         {tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)},  // positive y
244         {tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)}, // negative z
245         {tcu::Vec4(0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}     // positive z
246     };
247 
248     int numLevels = m_useMipmaps ? deLog2Floor32(de::max(m_width, m_height)) + 1 : 1;
249 
250     // Fill levels.
251     for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
252     {
253         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
254         {
255             m_texture->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
256             fillWithComponentGradients(m_texture->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face),
257                                        gradients[face][0], gradients[face][1]);
258         }
259     }
260 
261     // Upload texture data to GL.
262     m_texture->upload();
263 
264     // Initialize iteration state.
265     m_curFace = 0;
266     m_isOk    = true;
267 }
268 
deinit(void)269 void TextureCubeSizeCase::deinit(void)
270 {
271     delete m_texture;
272     m_texture = DE_NULL;
273 
274     m_renderer.clear();
275 }
276 
testFace(tcu::CubeFace face)277 bool TextureCubeSizeCase::testFace(tcu::CubeFace face)
278 {
279     const glw::Functions &gl = m_renderCtx.getFunctions();
280     TestLog &log             = m_testCtx.getLog();
281     RandomViewport viewport(m_renderCtx.getRenderTarget(), 128, 128, deStringHash(getName()) + (uint32_t)face);
282     tcu::Surface renderedFrame(viewport.width, viewport.height);
283     tcu::Surface referenceFrame(viewport.width, viewport.height);
284     const tcu::IVec4 texBits      = tcu::getTextureFormatBitDepth(glu::mapGLTransferFormat(m_format, m_dataType));
285     const tcu::PixelFormat &rtFmt = m_renderCtx.getRenderTarget().getPixelFormat();
286     const tcu::PixelFormat thresholdFormat(de::min(texBits[0], rtFmt.redBits), de::min(texBits[1], rtFmt.greenBits),
287                                            de::min(texBits[2], rtFmt.blueBits), de::min(texBits[3], rtFmt.alphaBits));
288     tcu::RGBA threshold = thresholdFormat.getColorThreshold() + tcu::RGBA(7, 7, 7, 7);
289     uint32_t wrapS      = GL_CLAMP_TO_EDGE;
290     uint32_t wrapT      = GL_CLAMP_TO_EDGE;
291     // Do not minify with GL_NEAREST. A large POT texture with a small POT render target will produce
292     // indeterminate results.
293     uint32_t minFilter = m_useMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR;
294     uint32_t magFilter = GL_NEAREST;
295     vector<float> texCoord;
296 
297     computeQuadTexCoordCube(texCoord, face);
298 
299     // \todo [2011-10-28 pyry] Image set name / section?
300     log << TestLog::Message << face << TestLog::EndMessage;
301 
302     // Setup base viewport.
303     gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
304 
305     // Bind to unit 0.
306     gl.activeTexture(GL_TEXTURE0);
307     gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_texture->getGLTexture());
308 
309     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, wrapS);
310     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, wrapT);
311     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, minFilter);
312     gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, magFilter);
313     GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
314 
315     m_renderer.renderQuad(0, &texCoord[0], TEXTURETYPE_CUBE);
316     glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
317 
318     // Compute reference.
319     Sampler sampler         = mapGLSampler(wrapS, wrapT, minFilter, magFilter);
320     sampler.seamlessCubeMap = true;
321     sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat()),
322                   m_texture->getRefTexture(), &texCoord[0], ReferenceParams(TEXTURETYPE_CUBE, sampler));
323 
324     // Compare and log.
325     return compareImages(log, referenceFrame, renderedFrame, threshold);
326 }
327 
iterate(void)328 TextureCubeSizeCase::IterateResult TextureCubeSizeCase::iterate(void)
329 {
330     // Execute test for all faces.
331     if (!testFace((tcu::CubeFace)m_curFace))
332         m_isOk = false;
333 
334     m_curFace += 1;
335 
336     if (m_curFace == tcu::CUBEFACE_LAST)
337     {
338         m_testCtx.setTestResult(m_isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
339                                 m_isOk ? "Pass" : "Image comparison failed");
340         return STOP;
341     }
342     else
343         return CONTINUE;
344 }
345 
TextureSizeTests(Context & context)346 TextureSizeTests::TextureSizeTests(Context &context) : TestCaseGroup(context, "size", "Texture Size Tests")
347 {
348 }
349 
~TextureSizeTests(void)350 TextureSizeTests::~TextureSizeTests(void)
351 {
352 }
353 
init(void)354 void TextureSizeTests::init(void)
355 {
356     struct
357     {
358         int width;
359         int height;
360     } sizes2D[] = {{64, 64}, // Spec-mandated minimum.
361                    {65, 63},
362                    {512, 512},
363                    {1024, 1024},
364                    {2048, 2048}};
365 
366     struct
367     {
368         int width;
369         int height;
370     } sizesCube[] = {{15, 15}, {16, 16}, // Spec-mandated minimum
371                      {64, 64}, {128, 128}, {256, 256}, {512, 512}};
372 
373     struct
374     {
375         const char *name;
376         uint32_t format;
377         uint32_t dataType;
378     } formats[] = {{"l8", GL_LUMINANCE, GL_UNSIGNED_BYTE},
379                    {"rgba4444", GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},
380                    {"rgb888", GL_RGB, GL_UNSIGNED_BYTE},
381                    {"rgba8888", GL_RGBA, GL_UNSIGNED_BYTE}};
382 
383     // 2D cases.
384     tcu::TestCaseGroup *group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Size Tests");
385     addChild(group2D);
386     for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
387     {
388         int width  = sizes2D[sizeNdx].width;
389         int height = sizes2D[sizeNdx].height;
390         bool isPOT = deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height);
391 
392         for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
393         {
394             for (int mipmap = 0; mipmap < (isPOT ? 2 : 1); mipmap++)
395             {
396                 std::ostringstream name;
397                 name << width << "x" << height << "_" << formats[formatNdx].name << (mipmap ? "_mipmap" : "");
398 
399                 group2D->addChild(new Texture2DSizeCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(), "",
400                                                         formats[formatNdx].format, formats[formatNdx].dataType, width,
401                                                         height, mipmap != 0));
402             }
403         }
404     }
405 
406     // Cubemap cases.
407     tcu::TestCaseGroup *groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cubemap Texture Size Tests");
408     addChild(groupCube);
409     for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++)
410     {
411         int width  = sizesCube[sizeNdx].width;
412         int height = sizesCube[sizeNdx].height;
413         bool isPOT = deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height);
414 
415         for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
416         {
417             for (int mipmap = 0; mipmap < (isPOT ? 2 : 1); mipmap++)
418             {
419                 std::ostringstream name;
420                 name << width << "x" << height << "_" << formats[formatNdx].name << (mipmap ? "_mipmap" : "");
421 
422                 groupCube->addChild(new TextureCubeSizeCase(m_testCtx, m_context.getRenderContext(), name.str().c_str(),
423                                                             "", formats[formatNdx].format, formats[formatNdx].dataType,
424                                                             width, height, mipmap != 0));
425             }
426         }
427     }
428 }
429 
430 } // namespace Functional
431 } // namespace gles3
432 } // namespace deqp
433