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