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