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 Texture filtering accuracy tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es2aTextureFilteringTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluTexture.hpp"
27 #include "gluStrUtil.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "tcuSurfaceAccess.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "deStringUtil.hpp"
34
35 #include "glwFunctions.hpp"
36 #include "glwEnums.hpp"
37
38 using std::string;
39
40 namespace deqp
41 {
42 namespace gles2
43 {
44 namespace Accuracy
45 {
46
47 using std::string;
48 using std::vector;
49 using tcu::Sampler;
50 using tcu::TestLog;
51 using namespace glu;
52 using namespace gls::TextureTestUtil;
53 using namespace glu::TextureTestUtil;
54
55 class Texture2DFilteringCase : public tcu::TestCase
56 {
57 public:
58 Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
59 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
60 uint32_t wrapT, uint32_t format, uint32_t dataType, int width, int height);
61 Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
62 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
63 uint32_t wrapT, const std::vector<std::string> &filenames);
64 ~Texture2DFilteringCase(void);
65
66 void init(void);
67 void deinit(void);
68 IterateResult iterate(void);
69
70 private:
71 Texture2DFilteringCase(const Texture2DFilteringCase &other);
72 Texture2DFilteringCase &operator=(const Texture2DFilteringCase &other);
73
74 glu::RenderContext &m_renderCtx;
75 const glu::ContextInfo &m_renderCtxInfo;
76
77 uint32_t m_minFilter;
78 uint32_t m_magFilter;
79 uint32_t m_wrapS;
80 uint32_t m_wrapT;
81
82 uint32_t m_format;
83 uint32_t m_dataType;
84 int m_width;
85 int m_height;
86
87 std::vector<std::string> m_filenames;
88
89 std::vector<glu::Texture2D *> m_textures;
90 TextureRenderer m_renderer;
91 };
92
Texture2DFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,uint32_t format,uint32_t dataType,int width,int height)93 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
94 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
95 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
96 uint32_t format, uint32_t dataType, int width, int height)
97 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
98 , m_renderCtx(renderCtx)
99 , m_renderCtxInfo(ctxInfo)
100 , m_minFilter(minFilter)
101 , m_magFilter(magFilter)
102 , m_wrapS(wrapS)
103 , m_wrapT(wrapT)
104 , m_format(format)
105 , m_dataType(dataType)
106 , m_width(width)
107 , m_height(height)
108 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
109 {
110 }
111
Texture2DFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,const std::vector<std::string> & filenames)112 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
113 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
114 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
115 const std::vector<std::string> &filenames)
116 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
117 , m_renderCtx(renderCtx)
118 , m_renderCtxInfo(ctxInfo)
119 , m_minFilter(minFilter)
120 , m_magFilter(magFilter)
121 , m_wrapS(wrapS)
122 , m_wrapT(wrapT)
123 , m_format(GL_NONE)
124 , m_dataType(GL_NONE)
125 , m_width(0)
126 , m_height(0)
127 , m_filenames(filenames)
128 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
129 {
130 }
131
~Texture2DFilteringCase(void)132 Texture2DFilteringCase::~Texture2DFilteringCase(void)
133 {
134 deinit();
135 }
136
init(void)137 void Texture2DFilteringCase::init(void)
138 {
139 try
140 {
141 if (!m_filenames.empty())
142 {
143 m_textures.reserve(1);
144 m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
145 (int)m_filenames.size(), m_filenames));
146 }
147 else
148 {
149 // Create 2 textures.
150 m_textures.reserve(2);
151 for (int ndx = 0; ndx < 2; ndx++)
152 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_format, m_dataType, m_width, m_height));
153
154 const bool mipmaps = deIsPowerOfTwo32(m_width) && deIsPowerOfTwo32(m_height);
155 const int numLevels = mipmaps ? deLog2Floor32(de::max(m_width, m_height)) + 1 : 1;
156 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
157 tcu::Vec4 cBias = fmtInfo.valueMin;
158 tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
159
160 // Fill first gradient texture.
161 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
162 {
163 tcu::Vec4 gMin = tcu::Vec4(-0.5f, -0.5f, -0.5f, 2.0f) * cScale + cBias;
164 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
165
166 m_textures[0]->getRefTexture().allocLevel(levelNdx);
167 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
168 }
169
170 // Fill second with grid texture.
171 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
172 {
173 uint32_t step = 0x00ffffff / numLevels;
174 uint32_t rgb = step * levelNdx;
175 uint32_t colorA = 0xff000000 | rgb;
176 uint32_t colorB = 0xff000000 | ~rgb;
177
178 m_textures[1]->getRefTexture().allocLevel(levelNdx);
179 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4,
180 tcu::RGBA(colorA).toVec() * cScale + cBias,
181 tcu::RGBA(colorB).toVec() * cScale + cBias);
182 }
183
184 // Upload.
185 for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
186 (*i)->upload();
187 }
188 }
189 catch (...)
190 {
191 // Clean up to save memory.
192 Texture2DFilteringCase::deinit();
193 throw;
194 }
195 }
196
deinit(void)197 void Texture2DFilteringCase::deinit(void)
198 {
199 for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
200 delete *i;
201 m_textures.clear();
202
203 m_renderer.clear();
204 }
205
iterate(void)206 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate(void)
207 {
208 const glw::Functions &gl = m_renderCtx.getFunctions();
209 TestLog &log = m_testCtx.getLog();
210 const int defViewportWidth = 256;
211 const int defViewportHeight = 256;
212 RandomViewport viewport(m_renderCtx.getRenderTarget(), defViewportWidth, defViewportHeight,
213 deStringHash(getName()));
214 tcu::Surface renderedFrame(viewport.width, viewport.height);
215 tcu::Surface referenceFrame(viewport.width, viewport.height);
216 const tcu::TextureFormat &texFmt = m_textures[0]->getRefTexture().getFormat();
217 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
218 ReferenceParams refParams(TEXTURETYPE_2D);
219 vector<float> texCoord;
220
221 // Accuracy measurements are off unless viewport size is 256x256
222 if (viewport.width < defViewportWidth || viewport.height < defViewportHeight)
223 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
224
225 // Viewport is divided into 4 sections.
226 int leftWidth = viewport.width / 2;
227 int rightWidth = viewport.width - leftWidth;
228 int bottomHeight = viewport.height / 2;
229 int topHeight = viewport.height - bottomHeight;
230
231 int curTexNdx = 0;
232
233 // Use unit 0.
234 gl.activeTexture(GL_TEXTURE0);
235
236 // Bind gradient texture and setup sampler parameters.
237 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
238 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
239 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
240 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
241 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
242
243 // Setup params for reference.
244 refParams.sampler = mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
245 refParams.samplerType = getSamplerType(texFmt);
246 refParams.lodMode = LODMODE_EXACT;
247 refParams.colorBias = fmtInfo.lookupBias;
248 refParams.colorScale = fmtInfo.lookupScale;
249
250 // Bottom left: Minification
251 {
252 gl.viewport(viewport.x, viewport.y, leftWidth, bottomHeight);
253
254 computeQuadTexCoord2D(texCoord, tcu::Vec2(-4.0f, -4.5f), tcu::Vec2(4.0f, 2.5f));
255
256 m_renderer.renderQuad(0, &texCoord[0], refParams);
257 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0,
258 leftWidth, bottomHeight),
259 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
260 }
261
262 // Bottom right: Magnification
263 {
264 gl.viewport(viewport.x + leftWidth, viewport.y, rightWidth, bottomHeight);
265
266 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
267
268 m_renderer.renderQuad(0, &texCoord[0], refParams);
269 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0,
270 rightWidth, bottomHeight),
271 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
272 }
273
274 if (m_textures.size() >= 2)
275 {
276 curTexNdx += 1;
277
278 // Setup second texture.
279 gl.bindTexture(GL_TEXTURE_2D, m_textures[curTexNdx]->getGLTexture());
280 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
281 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
282 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
283 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
284 }
285
286 // Top left: Minification
287 // \note Minification is chosen so that 0.0 < lod <= 0.5. This way special minification threshold rule will be triggered.
288 {
289 gl.viewport(viewport.x, viewport.y + bottomHeight, leftWidth, topHeight);
290
291 float sMin = -0.5f;
292 float tMin = -0.2f;
293 float sRange = ((float)leftWidth * 1.2f) / (float)m_textures[curTexNdx]->getRefTexture().getWidth();
294 float tRange = ((float)topHeight * 1.1f) / (float)m_textures[curTexNdx]->getRefTexture().getHeight();
295
296 computeQuadTexCoord2D(texCoord, tcu::Vec2(sMin, tMin), tcu::Vec2(sMin + sRange, tMin + tRange));
297
298 m_renderer.renderQuad(0, &texCoord[0], refParams);
299 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0,
300 bottomHeight, leftWidth, topHeight),
301 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
302 }
303
304 // Top right: Magnification
305 {
306 gl.viewport(viewport.x + leftWidth, viewport.y + bottomHeight, rightWidth, topHeight);
307
308 computeQuadTexCoord2D(texCoord, tcu::Vec2(-0.5f, 0.75f), tcu::Vec2(0.25f, 1.25f));
309
310 m_renderer.renderQuad(0, &texCoord[0], refParams);
311 sampleTexture(tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth,
312 bottomHeight, rightWidth, topHeight),
313 m_textures[curTexNdx]->getRefTexture(), &texCoord[0], refParams);
314 }
315
316 // Read result.
317 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
318
319 // Compare and log.
320 {
321 DE_ASSERT(getNodeType() == tcu::NODETYPE_ACCURACY);
322
323 const int bestScoreDiff = 16;
324 const int worstScoreDiff = 3200;
325
326 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
327 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
328 }
329
330 return STOP;
331 }
332
333 class TextureCubeFilteringCase : public tcu::TestCase
334 {
335 public:
336 TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
337 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
338 uint32_t wrapT, uint32_t format, uint32_t dataType, int width, int height);
339 TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
340 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
341 uint32_t wrapT, const std::vector<std::string> &filenames);
342 ~TextureCubeFilteringCase(void);
343
344 void init(void);
345 void deinit(void);
346 IterateResult iterate(void);
347
348 private:
349 TextureCubeFilteringCase(const TextureCubeFilteringCase &other);
350 TextureCubeFilteringCase &operator=(const TextureCubeFilteringCase &other);
351
352 glu::RenderContext &m_renderCtx;
353 const glu::ContextInfo &m_renderCtxInfo;
354
355 uint32_t m_minFilter;
356 uint32_t m_magFilter;
357 uint32_t m_wrapS;
358 uint32_t m_wrapT;
359
360 uint32_t m_format;
361 uint32_t m_dataType;
362 int m_width;
363 int m_height;
364
365 std::vector<std::string> m_filenames;
366
367 std::vector<glu::TextureCube *> m_textures;
368 TextureRenderer m_renderer;
369 };
370
TextureCubeFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,uint32_t format,uint32_t dataType,int width,int height)371 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
372 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
373 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
374 uint32_t wrapT, uint32_t format, uint32_t dataType, int width,
375 int height)
376 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
377 , m_renderCtx(renderCtx)
378 , m_renderCtxInfo(ctxInfo)
379 , m_minFilter(minFilter)
380 , m_magFilter(magFilter)
381 , m_wrapS(wrapS)
382 , m_wrapT(wrapT)
383 , m_format(format)
384 , m_dataType(dataType)
385 , m_width(width)
386 , m_height(height)
387 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
388 {
389 }
390
TextureCubeFilteringCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const glu::ContextInfo & ctxInfo,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,const std::vector<std::string> & filenames)391 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
392 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
393 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
394 uint32_t wrapT, const std::vector<std::string> &filenames)
395 : TestCase(testCtx, tcu::NODETYPE_ACCURACY, name, desc)
396 , m_renderCtx(renderCtx)
397 , m_renderCtxInfo(ctxInfo)
398 , m_minFilter(minFilter)
399 , m_magFilter(magFilter)
400 , m_wrapS(wrapS)
401 , m_wrapT(wrapT)
402 , m_format(GL_NONE)
403 , m_dataType(GL_NONE)
404 , m_width(0)
405 , m_height(0)
406 , m_filenames(filenames)
407 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_100_ES, glu::PRECISION_MEDIUMP)
408 {
409 }
410
~TextureCubeFilteringCase(void)411 TextureCubeFilteringCase::~TextureCubeFilteringCase(void)
412 {
413 deinit();
414 }
415
init(void)416 void TextureCubeFilteringCase::init(void)
417 {
418 try
419 {
420 if (!m_filenames.empty())
421 {
422 m_textures.reserve(1);
423 m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
424 (int)m_filenames.size() / 6, m_filenames));
425 }
426 else
427 {
428 m_textures.reserve(2);
429 DE_ASSERT(m_width == m_height);
430 for (int ndx = 0; ndx < 2; ndx++)
431 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_format, m_dataType, m_width));
432
433 const bool mipmaps = deIsPowerOfTwo32(m_width) && deIsPowerOfTwo32(m_height);
434 const int numLevels = mipmaps ? deLog2Floor32(de::max(m_width, m_height)) + 1 : 1;
435 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
436 tcu::Vec4 cBias = fmtInfo.valueMin;
437 tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
438
439 // Fill first with gradient texture.
440 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = {
441 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative x
442 {tcu::Vec4(0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive x
443 {tcu::Vec4(-1.0f, 0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative y
444 {tcu::Vec4(-1.0f, -1.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive y
445 {tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)}, // negative z
446 {tcu::Vec4(0.0f, 0.0f, 0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)} // positive z
447 };
448 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
449 {
450 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
451 {
452 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
453 tcu::fillWithComponentGradients(
454 m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face),
455 gradients[face][0] * cScale + cBias, gradients[face][1] * cScale + cBias);
456 }
457 }
458
459 // Fill second with grid texture.
460 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
461 {
462 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
463 {
464 uint32_t step = 0x00ffffff / (numLevels * tcu::CUBEFACE_LAST);
465 uint32_t rgb = step * levelNdx * face;
466 uint32_t colorA = 0xff000000 | rgb;
467 uint32_t colorB = 0xff000000 | ~rgb;
468
469 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
470 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4,
471 tcu::RGBA(colorA).toVec() * cScale + cBias,
472 tcu::RGBA(colorB).toVec() * cScale + cBias);
473 }
474 }
475
476 // Upload.
477 for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
478 (*i)->upload();
479 }
480 }
481 catch (const std::exception &)
482 {
483 // Clean up to save memory.
484 TextureCubeFilteringCase::deinit();
485 throw;
486 }
487 }
488
deinit(void)489 void TextureCubeFilteringCase::deinit(void)
490 {
491 for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
492 delete *i;
493 m_textures.clear();
494
495 m_renderer.clear();
496 }
497
renderFaces(const glw::Functions & gl,const tcu::SurfaceAccess & dstRef,const tcu::TextureCube & refTexture,const ReferenceParams & params,TextureRenderer & renderer,int x,int y,int width,int height,const tcu::Vec2 & bottomLeft,const tcu::Vec2 & topRight,const tcu::Vec2 & texCoordTopRightFactor)498 static void renderFaces(const glw::Functions &gl, const tcu::SurfaceAccess &dstRef, const tcu::TextureCube &refTexture,
499 const ReferenceParams ¶ms, TextureRenderer &renderer, int x, int y, int width, int height,
500 const tcu::Vec2 &bottomLeft, const tcu::Vec2 &topRight, const tcu::Vec2 &texCoordTopRightFactor)
501 {
502 DE_ASSERT(width == dstRef.getWidth() && height == dstRef.getHeight());
503
504 vector<float> texCoord;
505
506 DE_STATIC_ASSERT(tcu::CUBEFACE_LAST == 6);
507 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
508 {
509 bool isRightmost = (face == 2) || (face == 5);
510 bool isTop = face >= 3;
511 int curX = (face % 3) * (width / 3);
512 int curY = (face / 3) * (height / 2);
513 int curW = isRightmost ? (width - curX) : (width / 3);
514 int curH = isTop ? (height - curY) : (height / 2);
515
516 computeQuadTexCoordCube(texCoord, (tcu::CubeFace)face, bottomLeft, topRight);
517
518 {
519 // Move the top and right edges of the texture coord quad. This is useful when we want a cube edge visible.
520 int texCoordSRow = face == tcu::CUBEFACE_NEGATIVE_X || face == tcu::CUBEFACE_POSITIVE_X ? 2 : 0;
521 int texCoordTRow = face == tcu::CUBEFACE_NEGATIVE_Y || face == tcu::CUBEFACE_POSITIVE_Y ? 2 : 1;
522 texCoord[6 + texCoordSRow] *= texCoordTopRightFactor.x();
523 texCoord[9 + texCoordSRow] *= texCoordTopRightFactor.x();
524 texCoord[3 + texCoordTRow] *= texCoordTopRightFactor.y();
525 texCoord[9 + texCoordTRow] *= texCoordTopRightFactor.y();
526 }
527
528 gl.viewport(x + curX, y + curY, curW, curH);
529
530 renderer.renderQuad(0, &texCoord[0], params);
531
532 sampleTexture(tcu::SurfaceAccess(dstRef, curX, curY, curW, curH), refTexture, &texCoord[0], params);
533 }
534
535 GLU_EXPECT_NO_ERROR(gl.getError(), "Post render");
536 }
537
iterate(void)538 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate(void)
539 {
540 const glw::Functions &gl = m_renderCtx.getFunctions();
541 TestLog &log = m_testCtx.getLog();
542 const int cellSize = 28;
543 const int defViewportWidth = cellSize * 6;
544 const int defViewportHeight = cellSize * 4;
545 RandomViewport viewport(m_renderCtx.getRenderTarget(), cellSize * 6, cellSize * 4, deStringHash(getName()));
546 tcu::Surface renderedFrame(viewport.width, viewport.height);
547 tcu::Surface referenceFrame(viewport.width, viewport.height);
548 ReferenceParams sampleParams(TEXTURETYPE_CUBE);
549 const tcu::TextureFormat &texFmt = m_textures[0]->getRefTexture().getFormat();
550 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
551
552 // Accuracy measurements are off unless viewport size is exactly as expected.
553 if (viewport.width < defViewportWidth || viewport.height < defViewportHeight)
554 throw tcu::NotSupportedError("Too small viewport", "", __FILE__, __LINE__);
555
556 // Viewport is divided into 4 sections.
557 int leftWidth = viewport.width / 2;
558 int rightWidth = viewport.width - leftWidth;
559 int bottomHeight = viewport.height / 2;
560 int topHeight = viewport.height - bottomHeight;
561
562 int curTexNdx = 0;
563
564 // Sampling parameters.
565 sampleParams.sampler = mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
566 sampleParams.sampler.seamlessCubeMap = false;
567 sampleParams.samplerType = getSamplerType(texFmt);
568 sampleParams.colorBias = fmtInfo.lookupBias;
569 sampleParams.colorScale = fmtInfo.lookupScale;
570 sampleParams.lodMode = LODMODE_EXACT;
571
572 // Use unit 0.
573 gl.activeTexture(GL_TEXTURE0);
574
575 // Setup gradient texture.
576 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
577 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
578 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
579 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
580 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
581
582 // Bottom left: Minification
583 renderFaces(gl,
584 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, leftWidth,
585 bottomHeight),
586 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x, viewport.y, leftWidth,
587 bottomHeight, tcu::Vec2(-0.81f, -0.81f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.0f, 1.0f));
588
589 // Bottom right: Magnification
590 renderFaces(gl,
591 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth, 0,
592 rightWidth, bottomHeight),
593 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x + leftWidth, viewport.y,
594 rightWidth, bottomHeight, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.0f, 1.0f));
595
596 if (m_textures.size() >= 2)
597 {
598 curTexNdx += 1;
599
600 // Setup second texture.
601 gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textures[curTexNdx]->getGLTexture());
602 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
603 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
604 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
605 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
606 }
607
608 // Top left: Minification
609 renderFaces(gl,
610 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), 0, bottomHeight,
611 leftWidth, topHeight),
612 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x, viewport.y + bottomHeight,
613 leftWidth, topHeight, tcu::Vec2(-0.81f, -0.81f), tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.0f, 1.0f));
614
615 // Top right: Magnification
616 renderFaces(gl,
617 tcu::SurfaceAccess(referenceFrame, m_renderCtx.getRenderTarget().getPixelFormat(), leftWidth,
618 bottomHeight, rightWidth, topHeight),
619 m_textures[curTexNdx]->getRefTexture(), sampleParams, m_renderer, viewport.x + leftWidth,
620 viewport.y + bottomHeight, rightWidth, topHeight, tcu::Vec2(0.5f, -0.65f), tcu::Vec2(0.8f, -0.8f),
621 tcu::Vec2(1.0f, 1.0f));
622
623 // Read result.
624 glu::readPixels(m_renderCtx, viewport.x, viewport.y, renderedFrame.getAccess());
625
626 // Compare and log.
627 {
628 DE_ASSERT(getNodeType() == tcu::NODETYPE_ACCURACY);
629
630 const int bestScoreDiff = 16;
631 const int worstScoreDiff = 10000;
632
633 int score = measureAccuracy(log, referenceFrame, renderedFrame, bestScoreDiff, worstScoreDiff);
634 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(score).c_str());
635 }
636
637 return STOP;
638 }
639
TextureFilteringTests(Context & context)640 TextureFilteringTests::TextureFilteringTests(Context &context)
641 : TestCaseGroup(context, "filter", "Texture Filtering Accuracy Tests")
642 {
643 }
644
~TextureFilteringTests(void)645 TextureFilteringTests::~TextureFilteringTests(void)
646 {
647 }
648
init(void)649 void TextureFilteringTests::init(void)
650 {
651 tcu::TestCaseGroup *group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering");
652 tcu::TestCaseGroup *groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Filtering");
653 addChild(group2D);
654 addChild(groupCube);
655
656 static const struct
657 {
658 const char *name;
659 uint32_t mode;
660 } wrapModes[] = {{"clamp", GL_CLAMP_TO_EDGE}, {"repeat", GL_REPEAT}, {"mirror", GL_MIRRORED_REPEAT}};
661
662 static const struct
663 {
664 const char *name;
665 uint32_t mode;
666 } minFilterModes[] = {{"nearest", GL_NEAREST},
667 {"linear", GL_LINEAR},
668 {"nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST},
669 {"linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST},
670 {"nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR},
671 {"linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR}};
672
673 static const struct
674 {
675 const char *name;
676 uint32_t mode;
677 } magFilterModes[] = {{"nearest", GL_NEAREST}, {"linear", GL_LINEAR}};
678
679 static const struct
680 {
681 const char *name;
682 int width;
683 int height;
684 } sizes2D[] = {{"pot", 32, 64}, {"npot", 31, 55}};
685
686 static const struct
687 {
688 const char *name;
689 int width;
690 int height;
691 } sizesCube[] = {{"pot", 64, 64}, {"npot", 63, 63}};
692
693 static const struct
694 {
695 const char *name;
696 uint32_t format;
697 uint32_t dataType;
698 } formats[] = {{"rgba8888", GL_RGBA, GL_UNSIGNED_BYTE}, {"rgba4444", GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}};
699
700 #define FOR_EACH(ITERATOR, ARRAY, BODY) \
701 for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++) \
702 BODY
703
704 // 2D cases.
705 FOR_EACH(minFilter, minFilterModes,
706 FOR_EACH(magFilter, magFilterModes,
707 FOR_EACH(wrapMode, wrapModes,
708 FOR_EACH(format, formats, FOR_EACH(size, sizes2D, {
709 bool isMipmap = minFilterModes[minFilter].mode != GL_NEAREST &&
710 minFilterModes[minFilter].mode != GL_LINEAR;
711 bool isClamp = wrapModes[wrapMode].mode == GL_CLAMP_TO_EDGE;
712 bool isRepeat = wrapModes[wrapMode].mode == GL_REPEAT;
713 bool isMagNearest = magFilterModes[magFilter].mode == GL_NEAREST;
714 bool isPotSize = deIsPowerOfTwo32(sizes2D[size].width) &&
715 deIsPowerOfTwo32(sizes2D[size].height);
716
717 if ((isMipmap || !isClamp) && !isPotSize)
718 continue; // Not supported.
719
720 if ((format != 0) && !(!isMipmap || (isRepeat && isMagNearest)))
721 continue; // Skip.
722
723 string name = string("") + minFilterModes[minFilter].name + "_" +
724 magFilterModes[magFilter].name + "_" +
725 wrapModes[wrapMode].name + "_" + formats[format].name;
726
727 if (!isMipmap)
728 name += string("_") + sizes2D[size].name;
729
730 group2D->addChild(new Texture2DFilteringCase(
731 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
732 name.c_str(), "", minFilterModes[minFilter].mode,
733 magFilterModes[magFilter].mode, wrapModes[wrapMode].mode,
734 wrapModes[wrapMode].mode, formats[format].format,
735 formats[format].dataType, sizes2D[size].width, sizes2D[size].height));
736 })))))
737
738 // Cubemap cases.
739 FOR_EACH(minFilter, minFilterModes,
740 FOR_EACH(magFilter, magFilterModes,
741 FOR_EACH(wrapMode, wrapModes,
742 FOR_EACH(format, formats, FOR_EACH(size, sizesCube, {
743 bool isMipmap = minFilterModes[minFilter].mode != GL_NEAREST &&
744 minFilterModes[minFilter].mode != GL_LINEAR;
745 bool isClamp = wrapModes[wrapMode].mode == GL_CLAMP_TO_EDGE;
746 bool isRepeat = wrapModes[wrapMode].mode == GL_REPEAT;
747 bool isMagNearest = magFilterModes[magFilter].mode == GL_NEAREST;
748 bool isPotSize = deIsPowerOfTwo32(sizesCube[size].width) &&
749 deIsPowerOfTwo32(sizesCube[size].height);
750
751 if ((isMipmap || !isClamp) && !isPotSize)
752 continue; // Not supported.
753
754 if (format != 0 && !(!isMipmap || (isRepeat && isMagNearest)))
755 continue; // Skip.
756
757 string name = string("") + minFilterModes[minFilter].name + "_" +
758 magFilterModes[magFilter].name + "_" +
759 wrapModes[wrapMode].name + "_" + formats[format].name;
760
761 if (!isMipmap)
762 name += string("_") + sizesCube[size].name;
763
764 groupCube->addChild(new TextureCubeFilteringCase(
765 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(),
766 name.c_str(), "", minFilterModes[minFilter].mode,
767 magFilterModes[magFilter].mode, wrapModes[wrapMode].mode,
768 wrapModes[wrapMode].mode, formats[format].format,
769 formats[format].dataType, sizesCube[size].width,
770 sizesCube[size].height));
771 })))))
772 }
773
774 } // namespace Accuracy
775 } // namespace gles2
776 } // namespace deqp
777