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