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 filtering tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fTextureFilteringTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluTexture.hpp"
28 #include "gluTextureUtil.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuImageCompare.hpp"
31 #include "tcuTexLookupVerifier.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "deStringUtil.hpp"
34 #include "deString.h"
35 #include "glwFunctions.hpp"
36 #include "glwEnums.hpp"
37 #include "gluContextInfo.hpp"
38 #include "deUniquePtr.hpp"
39
40 using de::MovePtr;
41 using glu::ContextInfo;
42
43 namespace deqp
44 {
45 namespace gles3
46 {
47 namespace Functional
48 {
49
50 using std::string;
51 using std::vector;
52 using tcu::TestLog;
53 using namespace gls::TextureTestUtil;
54 using namespace glu::TextureTestUtil;
55
56 enum
57 {
58 TEX2D_VIEWPORT_WIDTH = 64,
59 TEX2D_VIEWPORT_HEIGHT = 64,
60 TEX2D_MIN_VIEWPORT_WIDTH = 64,
61 TEX2D_MIN_VIEWPORT_HEIGHT = 64,
62
63 TEX3D_VIEWPORT_WIDTH = 64,
64 TEX3D_VIEWPORT_HEIGHT = 64,
65 TEX3D_MIN_VIEWPORT_WIDTH = 64,
66 TEX3D_MIN_VIEWPORT_HEIGHT = 64
67 };
68
69 namespace
70 {
71
checkSupport(const glu::ContextInfo & info,uint32_t internalFormat)72 void checkSupport(const glu::ContextInfo &info, uint32_t internalFormat)
73 {
74 if (internalFormat == GL_SR8_EXT && !info.isExtensionSupported("GL_EXT_texture_sRGB_R8"))
75 TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_R8 is not supported.");
76
77 if (internalFormat == GL_SRG8_EXT && !info.isExtensionSupported("GL_EXT_texture_sRGB_RG8"))
78 TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_RG8 is not supported.");
79 }
80
81 } // namespace
82
83 class Texture2DFilteringCase : public tcu::TestCase
84 {
85 public:
86 Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
87 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
88 uint32_t wrapT, uint32_t internalFormat, int width, int height);
89 Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
90 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
91 uint32_t wrapT, const std::vector<std::string> &filenames);
92 ~Texture2DFilteringCase(void);
93
94 void init(void);
95 void deinit(void);
96 IterateResult iterate(void);
97
98 private:
99 Texture2DFilteringCase(const Texture2DFilteringCase &other);
100 Texture2DFilteringCase &operator=(const Texture2DFilteringCase &other);
101
102 glu::RenderContext &m_renderCtx;
103 const glu::ContextInfo &m_renderCtxInfo;
104
105 const uint32_t m_minFilter;
106 const uint32_t m_magFilter;
107 const uint32_t m_wrapS;
108 const uint32_t m_wrapT;
109
110 const uint32_t m_internalFormat;
111 const int m_width;
112 const int m_height;
113
114 const std::vector<std::string> m_filenames;
115
116 struct FilterCase
117 {
118 const glu::Texture2D *texture;
119 tcu::Vec2 minCoord;
120 tcu::Vec2 maxCoord;
121
FilterCasedeqp::gles3::Functional::Texture2DFilteringCase::FilterCase122 FilterCase(void) : texture(DE_NULL)
123 {
124 }
125
FilterCasedeqp::gles3::Functional::Texture2DFilteringCase::FilterCase126 FilterCase(const glu::Texture2D *tex_, const tcu::Vec2 &minCoord_, const tcu::Vec2 &maxCoord_)
127 : texture(tex_)
128 , minCoord(minCoord_)
129 , maxCoord(maxCoord_)
130 {
131 }
132 };
133
134 std::vector<glu::Texture2D *> m_textures;
135 std::vector<FilterCase> m_cases;
136
137 TextureRenderer m_renderer;
138
139 int m_caseNdx;
140 };
141
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 internalFormat,int width,int height)142 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
143 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
144 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
145 uint32_t internalFormat, int width, int height)
146 : TestCase(testCtx, name, desc)
147 , m_renderCtx(renderCtx)
148 , m_renderCtxInfo(ctxInfo)
149 , m_minFilter(minFilter)
150 , m_magFilter(magFilter)
151 , m_wrapS(wrapS)
152 , m_wrapT(wrapT)
153 , m_internalFormat(internalFormat)
154 , m_width(width)
155 , m_height(height)
156 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
157 , m_caseNdx(0)
158 {
159 }
160
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)161 Texture2DFilteringCase::Texture2DFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
162 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
163 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS, uint32_t wrapT,
164 const std::vector<std::string> &filenames)
165 : TestCase(testCtx, name, desc)
166 , m_renderCtx(renderCtx)
167 , m_renderCtxInfo(ctxInfo)
168 , m_minFilter(minFilter)
169 , m_magFilter(magFilter)
170 , m_wrapS(wrapS)
171 , m_wrapT(wrapT)
172 , m_internalFormat(GL_NONE)
173 , m_width(0)
174 , m_height(0)
175 , m_filenames(filenames)
176 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
177 , m_caseNdx(0)
178 {
179 }
180
~Texture2DFilteringCase(void)181 Texture2DFilteringCase::~Texture2DFilteringCase(void)
182 {
183 deinit();
184 }
185
init(void)186 void Texture2DFilteringCase::init(void)
187 {
188 checkSupport(m_renderCtxInfo, m_internalFormat);
189
190 try
191 {
192 if (!m_filenames.empty())
193 {
194 m_textures.reserve(1);
195 m_textures.push_back(glu::Texture2D::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
196 (int)m_filenames.size(), m_filenames));
197 }
198 else
199 {
200 // Create 2 textures.
201 m_textures.reserve(2);
202 for (int ndx = 0; ndx < 2; ndx++)
203 m_textures.push_back(new glu::Texture2D(m_renderCtx, m_internalFormat, m_width, m_height));
204
205 const bool mipmaps = true;
206 const int numLevels = mipmaps ? deLog2Floor32(de::max(m_width, m_height)) + 1 : 1;
207 const tcu::TextureFormatInfo fmtInfo =
208 tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
209 const tcu::Vec4 cBias = fmtInfo.valueMin;
210 const tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
211
212 // Fill first gradient texture.
213 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
214 {
215 tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
216 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
217
218 m_textures[0]->getRefTexture().allocLevel(levelNdx);
219 tcu::fillWithComponentGradients(m_textures[0]->getRefTexture().getLevel(levelNdx), gMin, gMax);
220 }
221
222 // Fill second with grid texture.
223 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
224 {
225 uint32_t step = 0x00ffffff / numLevels;
226 uint32_t rgb = step * levelNdx;
227 uint32_t colorA = 0xff000000 | rgb;
228 uint32_t colorB = 0xff000000 | ~rgb;
229
230 m_textures[1]->getRefTexture().allocLevel(levelNdx);
231 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevel(levelNdx), 4,
232 tcu::RGBA(colorA).toVec() * cScale + cBias,
233 tcu::RGBA(colorB).toVec() * cScale + cBias);
234 }
235
236 // Upload.
237 for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
238 (*i)->upload();
239 }
240
241 // Compute cases.
242 {
243 const struct
244 {
245 int texNdx;
246 float lodX;
247 float lodY;
248 float oX;
249 float oY;
250 } cases[] = {
251 {0, 1.6f, 2.9f, -1.0f, -2.7f},
252 {0, -2.0f, -1.35f, -0.2f, 0.7f},
253 {1, 0.14f, 0.275f, -1.5f, -1.1f},
254 {1, -0.92f, -2.64f, 0.4f, -0.1f},
255 };
256
257 const float viewportW = (float)de::min<int>(TEX2D_VIEWPORT_WIDTH, m_renderCtx.getRenderTarget().getWidth());
258 const float viewportH =
259 (float)de::min<int>(TEX2D_VIEWPORT_HEIGHT, m_renderCtx.getRenderTarget().getHeight());
260
261 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
262 {
263 const int texNdx = de::clamp(cases[caseNdx].texNdx, 0, (int)m_textures.size() - 1);
264 const float lodX = cases[caseNdx].lodX;
265 const float lodY = cases[caseNdx].lodY;
266 const float oX = cases[caseNdx].oX;
267 const float oY = cases[caseNdx].oY;
268 const float sX = deFloatExp2(lodX) * viewportW / float(m_textures[texNdx]->getRefTexture().getWidth());
269 const float sY = deFloatExp2(lodY) * viewportH / float(m_textures[texNdx]->getRefTexture().getHeight());
270
271 m_cases.push_back(FilterCase(m_textures[texNdx], tcu::Vec2(oX, oY), tcu::Vec2(oX + sX, oY + sY)));
272 }
273 }
274
275 m_caseNdx = 0;
276 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
277 }
278 catch (...)
279 {
280 // Clean up to save memory.
281 Texture2DFilteringCase::deinit();
282 throw;
283 }
284 }
285
deinit(void)286 void Texture2DFilteringCase::deinit(void)
287 {
288 for (std::vector<glu::Texture2D *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
289 delete *i;
290 m_textures.clear();
291
292 m_renderer.clear();
293 m_cases.clear();
294 }
295
iterate(void)296 Texture2DFilteringCase::IterateResult Texture2DFilteringCase::iterate(void)
297 {
298 const glw::Functions &gl = m_renderCtx.getFunctions();
299 const RandomViewport viewport(m_renderCtx.getRenderTarget(), TEX2D_VIEWPORT_WIDTH, TEX2D_VIEWPORT_HEIGHT,
300 deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
301 const tcu::TextureFormat texFmt = m_textures[0]->getRefTexture().getFormat();
302 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
303 const FilterCase &curCase = m_cases[m_caseNdx];
304 const tcu::ScopedLogSection section(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx),
305 string("Test ") + de::toString(m_caseNdx));
306 ReferenceParams refParams(TEXTURETYPE_2D);
307 tcu::Surface rendered(viewport.width, viewport.height);
308 vector<float> texCoord;
309
310 if (viewport.width < TEX2D_MIN_VIEWPORT_WIDTH || viewport.height < TEX2D_MIN_VIEWPORT_HEIGHT)
311 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
312
313 // Setup params for reference.
314 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_minFilter, m_magFilter);
315 refParams.samplerType = getSamplerType(texFmt);
316 refParams.lodMode = LODMODE_EXACT;
317 refParams.colorBias = fmtInfo.lookupBias;
318 refParams.colorScale = fmtInfo.lookupScale;
319
320 // Compute texture coordinates.
321 m_testCtx.getLog() << TestLog::Message << "Texture coordinates: " << curCase.minCoord << " -> " << curCase.maxCoord
322 << TestLog::EndMessage;
323 computeQuadTexCoord2D(texCoord, curCase.minCoord, curCase.maxCoord);
324
325 gl.bindTexture(GL_TEXTURE_2D, curCase.texture->getGLTexture());
326 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_minFilter);
327 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_magFilter);
328 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrapS);
329 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrapT);
330
331 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
332 m_renderer.renderQuad(0, &texCoord[0], refParams);
333 glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess());
334
335 {
336 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
337 const tcu::PixelFormat pixelFormat = m_renderCtx.getRenderTarget().getPixelFormat();
338 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2),
339 tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
340 tcu::LodPrecision lodPrecision;
341 tcu::LookupPrecision lookupPrecision;
342
343 lodPrecision.derivateBits = 18;
344 lodPrecision.lodBits = 6;
345 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
346 lookupPrecision.coordBits = tcu::IVec3(20, 20, 0);
347 lookupPrecision.uvwBits = tcu::IVec3(7, 7, 0);
348 lookupPrecision.colorMask = getCompareMask(pixelFormat);
349
350 const bool isHighQuality =
351 verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(), &texCoord[0],
352 refParams, lookupPrecision, lodPrecision, pixelFormat);
353
354 if (!isHighQuality)
355 {
356 // Evaluate against lower precision requirements.
357 lodPrecision.lodBits = 4;
358 lookupPrecision.uvwBits = tcu::IVec3(4, 4, 0);
359
360 m_testCtx.getLog()
361 << TestLog::Message
362 << "Warning: Verification against high precision requirements failed, trying with lower requirements."
363 << TestLog::EndMessage;
364
365 const bool isOk = verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
366 &texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
367
368 if (!isOk)
369 {
370 m_testCtx.getLog()
371 << TestLog::Message
372 << "ERROR: Verification against low precision requirements failed, failing test case."
373 << TestLog::EndMessage;
374 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
375 }
376 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
377 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
378 }
379 }
380
381 m_caseNdx += 1;
382 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
383 }
384
385 class TextureCubeFilteringCase : public tcu::TestCase
386 {
387 public:
388 TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
389 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
390 uint32_t wrapT, bool onlySampleFaceInterior, uint32_t internalFormat, int width,
391 int height);
392 TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx, const glu::ContextInfo &ctxInfo,
393 const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
394 uint32_t wrapT, bool onlySampleFaceInterior, const std::vector<std::string> &filenames);
395 ~TextureCubeFilteringCase(void);
396
397 void init(void);
398 void deinit(void);
399 IterateResult iterate(void);
400
401 private:
402 TextureCubeFilteringCase(const TextureCubeFilteringCase &other);
403 TextureCubeFilteringCase &operator=(const TextureCubeFilteringCase &other);
404
405 glu::RenderContext &m_renderCtx;
406 const glu::ContextInfo &m_renderCtxInfo;
407
408 const uint32_t m_minFilter;
409 const uint32_t m_magFilter;
410 const uint32_t m_wrapS;
411 const uint32_t m_wrapT;
412 const bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
413
414 const uint32_t m_internalFormat;
415 const int m_width;
416 const int m_height;
417
418 const std::vector<std::string> m_filenames;
419
420 struct FilterCase
421 {
422 const glu::TextureCube *texture;
423 tcu::Vec2 bottomLeft;
424 tcu::Vec2 topRight;
425
FilterCasedeqp::gles3::Functional::TextureCubeFilteringCase::FilterCase426 FilterCase(void) : texture(DE_NULL)
427 {
428 }
429
FilterCasedeqp::gles3::Functional::TextureCubeFilteringCase::FilterCase430 FilterCase(const glu::TextureCube *tex_, const tcu::Vec2 &bottomLeft_, const tcu::Vec2 &topRight_)
431 : texture(tex_)
432 , bottomLeft(bottomLeft_)
433 , topRight(topRight_)
434 {
435 }
436 };
437
438 std::vector<glu::TextureCube *> m_textures;
439 std::vector<FilterCase> m_cases;
440
441 TextureRenderer m_renderer;
442
443 int m_caseNdx;
444 };
445
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,bool onlySampleFaceInterior,uint32_t internalFormat,int width,int height)446 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
447 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
448 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
449 uint32_t wrapT, bool onlySampleFaceInterior, uint32_t internalFormat,
450 int width, int height)
451 : TestCase(testCtx, name, desc)
452 , m_renderCtx(renderCtx)
453 , m_renderCtxInfo(ctxInfo)
454 , m_minFilter(minFilter)
455 , m_magFilter(magFilter)
456 , m_wrapS(wrapS)
457 , m_wrapT(wrapT)
458 , m_onlySampleFaceInterior(onlySampleFaceInterior)
459 , m_internalFormat(internalFormat)
460 , m_width(width)
461 , m_height(height)
462 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
463 , m_caseNdx(0)
464 {
465 }
466
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,bool onlySampleFaceInterior,const std::vector<std::string> & filenames)467 TextureCubeFilteringCase::TextureCubeFilteringCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
468 const glu::ContextInfo &ctxInfo, const char *name, const char *desc,
469 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
470 uint32_t wrapT, bool onlySampleFaceInterior,
471 const std::vector<std::string> &filenames)
472 : TestCase(testCtx, name, desc)
473 , m_renderCtx(renderCtx)
474 , m_renderCtxInfo(ctxInfo)
475 , m_minFilter(minFilter)
476 , m_magFilter(magFilter)
477 , m_wrapS(wrapS)
478 , m_wrapT(wrapT)
479 , m_onlySampleFaceInterior(onlySampleFaceInterior)
480 , m_internalFormat(GL_NONE)
481 , m_width(0)
482 , m_height(0)
483 , m_filenames(filenames)
484 , m_renderer(renderCtx, testCtx.getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
485 , m_caseNdx(0)
486 {
487 }
488
~TextureCubeFilteringCase(void)489 TextureCubeFilteringCase::~TextureCubeFilteringCase(void)
490 {
491 deinit();
492 }
493
init(void)494 void TextureCubeFilteringCase::init(void)
495 {
496 checkSupport(m_renderCtxInfo, m_internalFormat);
497
498 try
499 {
500 if (!m_filenames.empty())
501 {
502 m_textures.reserve(1);
503 m_textures.push_back(glu::TextureCube::create(m_renderCtx, m_renderCtxInfo, m_testCtx.getArchive(),
504 (int)m_filenames.size() / 6, m_filenames));
505 }
506 else
507 {
508 DE_ASSERT(m_width == m_height);
509 m_textures.reserve(2);
510 for (int ndx = 0; ndx < 2; ndx++)
511 m_textures.push_back(new glu::TextureCube(m_renderCtx, m_internalFormat, m_width));
512
513 const int numLevels = deLog2Floor32(de::max(m_width, m_height)) + 1;
514 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(m_textures[0]->getRefTexture().getFormat());
515 tcu::Vec4 cBias = fmtInfo.valueMin;
516 tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
517
518 // Fill first with gradient texture.
519 static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] = {
520 {tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative x
521 {tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive x
522 {tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // negative y
523 {tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, // positive y
524 {tcu::Vec4(0.0f, 0.0f, 0.0f, 0.5f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)}, // negative z
525 {tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)} // positive z
526 };
527 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
528 {
529 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
530 {
531 m_textures[0]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
532 tcu::fillWithComponentGradients(
533 m_textures[0]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face),
534 gradients[face][0] * cScale + cBias, gradients[face][1] * cScale + cBias);
535 }
536 }
537
538 // Fill second with grid texture.
539 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
540 {
541 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
542 {
543 uint32_t step = 0x00ffffff / (numLevels * tcu::CUBEFACE_LAST);
544 uint32_t rgb = step * levelNdx * face;
545 uint32_t colorA = 0xff000000 | rgb;
546 uint32_t colorB = 0xff000000 | ~rgb;
547
548 m_textures[1]->getRefTexture().allocLevel((tcu::CubeFace)face, levelNdx);
549 tcu::fillWithGrid(m_textures[1]->getRefTexture().getLevelFace(levelNdx, (tcu::CubeFace)face), 4,
550 tcu::RGBA(colorA).toVec() * cScale + cBias,
551 tcu::RGBA(colorB).toVec() * cScale + cBias);
552 }
553 }
554
555 // Upload.
556 for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
557 (*i)->upload();
558 }
559
560 // Compute cases
561 {
562 const glu::TextureCube *tex0 = m_textures[0];
563 const glu::TextureCube *tex1 = m_textures.size() > 1 ? m_textures[1] : tex0;
564
565 if (m_onlySampleFaceInterior)
566 {
567 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f))); // minification
568 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f))); // magnification
569 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f))); // minification
570 m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f, 0.5f))); // magnification
571 }
572 else
573 {
574 if (m_renderCtx.getRenderTarget().getNumSamples() == 0)
575 m_cases.push_back(
576 FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f))); // minification
577 else
578 m_cases.push_back(FilterCase(
579 tex0, tcu::Vec2(-1.19f, -1.3f),
580 tcu::Vec2(
581 1.1f,
582 1.35f))); // minification - w/ tweak to avoid hitting triangle edges with face switchpoint
583
584 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f))); // magnification
585 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f))); // minification
586 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f))); // magnification
587 }
588 }
589
590 m_caseNdx = 0;
591 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
592 }
593 catch (...)
594 {
595 // Clean up to save memory.
596 TextureCubeFilteringCase::deinit();
597 throw;
598 }
599 }
600
deinit(void)601 void TextureCubeFilteringCase::deinit(void)
602 {
603 for (std::vector<glu::TextureCube *>::iterator i = m_textures.begin(); i != m_textures.end(); i++)
604 delete *i;
605 m_textures.clear();
606
607 m_renderer.clear();
608 m_cases.clear();
609 }
610
getFaceDesc(const tcu::CubeFace face)611 static const char *getFaceDesc(const tcu::CubeFace face)
612 {
613 switch (face)
614 {
615 case tcu::CUBEFACE_NEGATIVE_X:
616 return "-X";
617 case tcu::CUBEFACE_POSITIVE_X:
618 return "+X";
619 case tcu::CUBEFACE_NEGATIVE_Y:
620 return "-Y";
621 case tcu::CUBEFACE_POSITIVE_Y:
622 return "+Y";
623 case tcu::CUBEFACE_NEGATIVE_Z:
624 return "-Z";
625 case tcu::CUBEFACE_POSITIVE_Z:
626 return "+Z";
627 default:
628 DE_ASSERT(false);
629 return DE_NULL;
630 }
631 }
632
iterate(void)633 TextureCubeFilteringCase::IterateResult TextureCubeFilteringCase::iterate(void)
634 {
635 const glw::Functions &gl = m_renderCtx.getFunctions();
636 const int viewportSize = 28;
637 const RandomViewport viewport(m_renderCtx.getRenderTarget(), viewportSize, viewportSize,
638 deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
639 const tcu::ScopedLogSection iterSection(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx),
640 string("Test ") + de::toString(m_caseNdx));
641 const FilterCase &curCase = m_cases[m_caseNdx];
642 const tcu::TextureFormat &texFmt = curCase.texture->getRefTexture().getFormat();
643 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
644 ReferenceParams sampleParams(TEXTURETYPE_CUBE);
645
646 if (viewport.width < viewportSize || viewport.height < viewportSize)
647 throw tcu::NotSupportedError("Too small render target", DE_NULL, __FILE__, __LINE__);
648
649 // Setup texture
650 gl.bindTexture(GL_TEXTURE_CUBE_MAP, curCase.texture->getGLTexture());
651 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, m_minFilter);
652 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, m_magFilter);
653 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, m_wrapS);
654 gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, m_wrapT);
655
656 // Other state
657 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
658
659 // Params for reference computation.
660 sampleParams.sampler = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
661 sampleParams.sampler.seamlessCubeMap = true;
662 sampleParams.samplerType = getSamplerType(texFmt);
663 sampleParams.colorBias = fmtInfo.lookupBias;
664 sampleParams.colorScale = fmtInfo.lookupScale;
665 sampleParams.lodMode = LODMODE_EXACT;
666
667 m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight
668 << TestLog::EndMessage;
669
670 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
671 {
672 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
673 tcu::Surface result(viewport.width, viewport.height);
674 vector<float> texCoord;
675
676 computeQuadTexCoordCube(texCoord, face, curCase.bottomLeft, curCase.topRight);
677
678 m_testCtx.getLog() << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
679
680 // \todo Log texture coordinates.
681
682 m_renderer.renderQuad(0, &texCoord[0], sampleParams);
683 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
684
685 glu::readPixels(m_renderCtx, viewport.x, viewport.y, result.getAccess());
686 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
687
688 {
689 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
690 const tcu::PixelFormat pixelFormat = m_renderCtx.getRenderTarget().getPixelFormat();
691 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2),
692 tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
693 tcu::LodPrecision lodPrecision;
694 tcu::LookupPrecision lookupPrecision;
695
696 lodPrecision.derivateBits = 10;
697 lodPrecision.lodBits = 5;
698 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / sampleParams.colorScale;
699 lookupPrecision.coordBits = tcu::IVec3(10, 10, 10);
700 lookupPrecision.uvwBits = tcu::IVec3(6, 6, 0);
701 lookupPrecision.colorMask = getCompareMask(pixelFormat);
702
703 const bool isHighQuality =
704 verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), &texCoord[0],
705 sampleParams, lookupPrecision, lodPrecision, pixelFormat);
706
707 if (!isHighQuality)
708 {
709 // Evaluate against lower precision requirements.
710 lodPrecision.lodBits = 4;
711 lookupPrecision.uvwBits = tcu::IVec3(4, 4, 0);
712
713 m_testCtx.getLog() << TestLog::Message
714 << "Warning: Verification against high precision requirements failed, trying with "
715 "lower requirements."
716 << TestLog::EndMessage;
717
718 const bool isOk =
719 verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), &texCoord[0],
720 sampleParams, lookupPrecision, lodPrecision, pixelFormat);
721
722 if (!isOk)
723 {
724 m_testCtx.getLog()
725 << TestLog::Message
726 << "ERROR: Verification against low precision requirements failed, failing test case."
727 << TestLog::EndMessage;
728 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
729 }
730 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
731 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
732 }
733 }
734 }
735
736 m_caseNdx += 1;
737 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
738 }
739
740 // 2D array filtering
741
742 class Texture2DArrayFilteringCase : public TestCase
743 {
744 public:
745 Texture2DArrayFilteringCase(Context &context, const char *name, const char *desc, uint32_t minFilter,
746 uint32_t magFilter, uint32_t wrapS, uint32_t wrapT, uint32_t internalFormat, int width,
747 int height, int numLayers);
748 ~Texture2DArrayFilteringCase(void);
749
750 void init(void);
751 void deinit(void);
752 IterateResult iterate(void);
753
754 private:
755 Texture2DArrayFilteringCase(const Texture2DArrayFilteringCase &);
756 Texture2DArrayFilteringCase &operator=(const Texture2DArrayFilteringCase &);
757
758 const uint32_t m_minFilter;
759 const uint32_t m_magFilter;
760 const uint32_t m_wrapS;
761 const uint32_t m_wrapT;
762
763 const uint32_t m_internalFormat;
764 const int m_width;
765 const int m_height;
766 const int m_numLayers;
767
768 struct FilterCase
769 {
770 const glu::Texture2DArray *texture;
771 tcu::Vec2 lod;
772 tcu::Vec2 offset;
773 tcu::Vec2 layerRange;
774
FilterCasedeqp::gles3::Functional::Texture2DArrayFilteringCase::FilterCase775 FilterCase(void) : texture(DE_NULL)
776 {
777 }
778
FilterCasedeqp::gles3::Functional::Texture2DArrayFilteringCase::FilterCase779 FilterCase(const glu::Texture2DArray *tex_, const tcu::Vec2 &lod_, const tcu::Vec2 &offset_,
780 const tcu::Vec2 &layerRange_)
781 : texture(tex_)
782 , lod(lod_)
783 , offset(offset_)
784 , layerRange(layerRange_)
785 {
786 }
787 };
788
789 glu::Texture2DArray *m_gradientTex;
790 glu::Texture2DArray *m_gridTex;
791
792 TextureRenderer m_renderer;
793
794 std::vector<FilterCase> m_cases;
795 int m_caseNdx;
796 };
797
Texture2DArrayFilteringCase(Context & context,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,uint32_t internalFormat,int width,int height,int numLayers)798 Texture2DArrayFilteringCase::Texture2DArrayFilteringCase(Context &context, const char *name, const char *desc,
799 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
800 uint32_t wrapT, uint32_t internalFormat, int width, int height,
801 int numLayers)
802 : TestCase(context, name, desc)
803 , m_minFilter(minFilter)
804 , m_magFilter(magFilter)
805 , m_wrapS(wrapS)
806 , m_wrapT(wrapT)
807 , m_internalFormat(internalFormat)
808 , m_width(width)
809 , m_height(height)
810 , m_numLayers(numLayers)
811 , m_gradientTex(DE_NULL)
812 , m_gridTex(DE_NULL)
813 , m_renderer(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES,
814 glu::PRECISION_HIGHP)
815 , m_caseNdx(0)
816 {
817 }
818
~Texture2DArrayFilteringCase(void)819 Texture2DArrayFilteringCase::~Texture2DArrayFilteringCase(void)
820 {
821 Texture2DArrayFilteringCase::deinit();
822 }
823
init(void)824 void Texture2DArrayFilteringCase::init(void)
825 {
826 checkSupport(m_context.getContextInfo(), m_internalFormat);
827
828 try
829 {
830 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_internalFormat);
831 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
832 const tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
833 const tcu::Vec4 cBias = fmtInfo.valueMin;
834 const int numLevels = deLog2Floor32(de::max(m_width, m_height)) + 1;
835
836 // Create textures.
837 m_gradientTex =
838 new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers);
839 m_gridTex =
840 new glu::Texture2DArray(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_numLayers);
841
842 const tcu::IVec4 levelSwz[] = {
843 tcu::IVec4(0, 1, 2, 3),
844 tcu::IVec4(2, 1, 3, 0),
845 tcu::IVec4(3, 0, 1, 2),
846 tcu::IVec4(1, 3, 2, 0),
847 };
848
849 // Fill first gradient texture (gradient direction varies between layers).
850 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
851 {
852 m_gradientTex->getRefTexture().allocLevel(levelNdx);
853
854 const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
855
856 for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++)
857 {
858 const tcu::IVec4 swz = levelSwz[layerNdx % DE_LENGTH_OF_ARRAY(levelSwz)];
859 const tcu::Vec4 gMin =
860 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0], swz[1], swz[2], swz[3]) * cScale + cBias;
861 const tcu::Vec4 gMax =
862 tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0], swz[1], swz[2], swz[3]) * cScale + cBias;
863
864 tcu::fillWithComponentGradients(
865 tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin,
866 gMax);
867 }
868 }
869
870 // Fill second with grid texture (each layer has unique colors).
871 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
872 {
873 m_gridTex->getRefTexture().allocLevel(levelNdx);
874
875 const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
876
877 for (int layerNdx = 0; layerNdx < m_numLayers; layerNdx++)
878 {
879 const uint32_t step = 0x00ffffff / (numLevels * m_numLayers - 1);
880 const uint32_t rgb = step * (levelNdx + layerNdx * numLevels);
881 const uint32_t colorA = 0xff000000 | rgb;
882 const uint32_t colorB = 0xff000000 | ~rgb;
883
884 tcu::fillWithGrid(
885 tcu::getSubregion(levelBuf, 0, 0, layerNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), 4,
886 tcu::RGBA(colorA).toVec() * cScale + cBias, tcu::RGBA(colorB).toVec() * cScale + cBias);
887 }
888 }
889
890 // Upload.
891 m_gradientTex->upload();
892 m_gridTex->upload();
893
894 // Test cases
895 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec2(1.5f, 2.8f), tcu::Vec2(-1.0f, -2.7f),
896 tcu::Vec2(-0.5f, float(m_numLayers) + 0.5f)));
897 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec2(0.2f, 0.175f), tcu::Vec2(-2.0f, -3.7f),
898 tcu::Vec2(-0.5f, float(m_numLayers) + 0.5f)));
899 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec2(-0.8f, -2.3f), tcu::Vec2(0.2f, -0.1f),
900 tcu::Vec2(float(m_numLayers) + 0.5f, -0.5f)));
901
902 // Level rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
903 if (m_context.getRenderTarget().getNumSamples() == 0)
904 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec2(-2.0f, -1.5f), tcu::Vec2(-0.1f, 0.9f),
905 tcu::Vec2(1.50001f, 1.49999f)));
906
907 m_caseNdx = 0;
908 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
909 }
910 catch (...)
911 {
912 // Clean up to save memory.
913 Texture2DArrayFilteringCase::deinit();
914 throw;
915 }
916 }
917
deinit(void)918 void Texture2DArrayFilteringCase::deinit(void)
919 {
920 delete m_gradientTex;
921 delete m_gridTex;
922
923 m_gradientTex = DE_NULL;
924 m_gridTex = DE_NULL;
925
926 m_renderer.clear();
927 m_cases.clear();
928 }
929
iterate(void)930 Texture2DArrayFilteringCase::IterateResult Texture2DArrayFilteringCase::iterate(void)
931 {
932 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
933 const RandomViewport viewport(m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT,
934 deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
935 const FilterCase &curCase = m_cases[m_caseNdx];
936 const tcu::TextureFormat texFmt = curCase.texture->getRefTexture().getFormat();
937 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
938 const tcu::ScopedLogSection section(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx),
939 string("Test ") + de::toString(m_caseNdx));
940 ReferenceParams refParams(TEXTURETYPE_2D_ARRAY);
941 tcu::Surface rendered(viewport.width, viewport.height);
942 tcu::Vec3 texCoord[4];
943
944 if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT)
945 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
946
947 // Setup params for reference.
948 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapT, m_minFilter, m_magFilter);
949 refParams.samplerType = getSamplerType(texFmt);
950 refParams.lodMode = LODMODE_EXACT;
951 refParams.colorBias = fmtInfo.lookupBias;
952 refParams.colorScale = fmtInfo.lookupScale;
953
954 // Compute texture coordinates.
955 m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod
956 << ", offset = " << curCase.offset << TestLog::EndMessage;
957
958 {
959 const float lodX = curCase.lod.x();
960 const float lodY = curCase.lod.y();
961 const float oX = curCase.offset.x();
962 const float oY = curCase.offset.y();
963 const float sX = deFloatExp2(lodX) * float(viewport.width) / float(m_gradientTex->getRefTexture().getWidth());
964 const float sY = deFloatExp2(lodY) * float(viewport.height) / float(m_gradientTex->getRefTexture().getHeight());
965 const float l0 = curCase.layerRange.x();
966 const float l1 = curCase.layerRange.y();
967
968 texCoord[0] = tcu::Vec3(oX, oY, l0);
969 texCoord[1] = tcu::Vec3(oX, oY + sY, l0 * 0.5f + l1 * 0.5f);
970 texCoord[2] = tcu::Vec3(oX + sX, oY, l0 * 0.5f + l1 * 0.5f);
971 texCoord[3] = tcu::Vec3(oX + sX, oY + sY, l1);
972 }
973
974 gl.bindTexture(GL_TEXTURE_2D_ARRAY, curCase.texture->getGLTexture());
975 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, m_minFilter);
976 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, m_magFilter);
977 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, m_wrapS);
978 gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, m_wrapT);
979
980 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
981 m_renderer.renderQuad(0, (const float *)&texCoord[0], refParams);
982 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
983
984 {
985 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
986 const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
987 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2),
988 tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
989 tcu::LodPrecision lodPrecision;
990 tcu::LookupPrecision lookupPrecision;
991
992 lodPrecision.derivateBits = 18;
993 lodPrecision.lodBits = 6;
994 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
995 lookupPrecision.coordBits = tcu::IVec3(20, 20, 20);
996 lookupPrecision.uvwBits = tcu::IVec3(7, 7, 0);
997 lookupPrecision.colorMask = getCompareMask(pixelFormat);
998
999 const bool isHighQuality =
1000 verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1001 (const float *)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1002
1003 if (!isHighQuality)
1004 {
1005 // Evaluate against lower precision requirements.
1006 lodPrecision.lodBits = 4;
1007 lookupPrecision.uvwBits = tcu::IVec3(4, 4, 0);
1008
1009 m_testCtx.getLog()
1010 << TestLog::Message
1011 << "Warning: Verification against high precision requirements failed, trying with lower requirements."
1012 << TestLog::EndMessage;
1013
1014 const bool isOk =
1015 verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1016 (const float *)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1017
1018 if (!isOk)
1019 {
1020 m_testCtx.getLog()
1021 << TestLog::Message
1022 << "ERROR: Verification against low precision requirements failed, failing test case."
1023 << TestLog::EndMessage;
1024 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1025 }
1026 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1027 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
1028 }
1029 }
1030
1031 m_caseNdx += 1;
1032 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
1033 }
1034
1035 // 3D filtering
1036
1037 class Texture3DFilteringCase : public TestCase
1038 {
1039 public:
1040 Texture3DFilteringCase(Context &context, const char *name, const char *desc, uint32_t minFilter, uint32_t magFilter,
1041 uint32_t wrapS, uint32_t wrapT, uint32_t wrapR, uint32_t internalFormat, int width,
1042 int height, int depth);
1043 ~Texture3DFilteringCase(void);
1044
1045 void init(void);
1046 void deinit(void);
1047 IterateResult iterate(void);
1048
1049 private:
1050 Texture3DFilteringCase(const Texture3DFilteringCase &other);
1051 Texture3DFilteringCase &operator=(const Texture3DFilteringCase &other);
1052
1053 const uint32_t m_minFilter;
1054 const uint32_t m_magFilter;
1055 const uint32_t m_wrapS;
1056 const uint32_t m_wrapT;
1057 const uint32_t m_wrapR;
1058
1059 const uint32_t m_internalFormat;
1060 const int m_width;
1061 const int m_height;
1062 const int m_depth;
1063
1064 struct FilterCase
1065 {
1066 const glu::Texture3D *texture;
1067 tcu::Vec3 lod;
1068 tcu::Vec3 offset;
1069
FilterCasedeqp::gles3::Functional::Texture3DFilteringCase::FilterCase1070 FilterCase(void) : texture(DE_NULL)
1071 {
1072 }
1073
FilterCasedeqp::gles3::Functional::Texture3DFilteringCase::FilterCase1074 FilterCase(const glu::Texture3D *tex_, const tcu::Vec3 &lod_, const tcu::Vec3 &offset_)
1075 : texture(tex_)
1076 , lod(lod_)
1077 , offset(offset_)
1078 {
1079 }
1080 };
1081
1082 glu::Texture3D *m_gradientTex;
1083 glu::Texture3D *m_gridTex;
1084
1085 TextureRenderer m_renderer;
1086
1087 std::vector<FilterCase> m_cases;
1088 int m_caseNdx;
1089 };
1090
Texture3DFilteringCase(Context & context,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,uint32_t wrapR,uint32_t internalFormat,int width,int height,int depth)1091 Texture3DFilteringCase::Texture3DFilteringCase(Context &context, const char *name, const char *desc, uint32_t minFilter,
1092 uint32_t magFilter, uint32_t wrapS, uint32_t wrapT, uint32_t wrapR,
1093 uint32_t internalFormat, int width, int height, int depth)
1094 : TestCase(context, name, desc)
1095 , m_minFilter(minFilter)
1096 , m_magFilter(magFilter)
1097 , m_wrapS(wrapS)
1098 , m_wrapT(wrapT)
1099 , m_wrapR(wrapR)
1100 , m_internalFormat(internalFormat)
1101 , m_width(width)
1102 , m_height(height)
1103 , m_depth(depth)
1104 , m_gradientTex(DE_NULL)
1105 , m_gridTex(DE_NULL)
1106 , m_renderer(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES,
1107 glu::PRECISION_HIGHP)
1108 , m_caseNdx(0)
1109 {
1110 }
1111
~Texture3DFilteringCase(void)1112 Texture3DFilteringCase::~Texture3DFilteringCase(void)
1113 {
1114 Texture3DFilteringCase::deinit();
1115 }
1116
init(void)1117 void Texture3DFilteringCase::init(void)
1118 {
1119 checkSupport(m_context.getContextInfo(), m_internalFormat);
1120
1121 try
1122 {
1123 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_internalFormat);
1124 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
1125 const tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
1126 const tcu::Vec4 cBias = fmtInfo.valueMin;
1127 const int numLevels = deLog2Floor32(de::max(de::max(m_width, m_height), m_depth)) + 1;
1128
1129 // Create textures.
1130 m_gradientTex = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1131 m_gridTex = new glu::Texture3D(m_context.getRenderContext(), m_internalFormat, m_width, m_height, m_depth);
1132
1133 // Fill first gradient texture.
1134 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1135 {
1136 tcu::Vec4 gMin = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
1137 tcu::Vec4 gMax = tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
1138
1139 m_gradientTex->getRefTexture().allocLevel(levelNdx);
1140 tcu::fillWithComponentGradients(m_gradientTex->getRefTexture().getLevel(levelNdx), gMin, gMax);
1141 }
1142
1143 // Fill second with grid texture.
1144 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
1145 {
1146 uint32_t step = 0x00ffffff / numLevels;
1147 uint32_t rgb = step * levelNdx;
1148 uint32_t colorA = 0xff000000 | rgb;
1149 uint32_t colorB = 0xff000000 | ~rgb;
1150
1151 m_gridTex->getRefTexture().allocLevel(levelNdx);
1152 tcu::fillWithGrid(m_gridTex->getRefTexture().getLevel(levelNdx), 4,
1153 tcu::RGBA(colorA).toVec() * cScale + cBias, tcu::RGBA(colorB).toVec() * cScale + cBias);
1154 }
1155
1156 // Upload.
1157 m_gradientTex->upload();
1158 m_gridTex->upload();
1159
1160 // Test cases
1161 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec3(1.5f, 2.8f, 1.0f), tcu::Vec3(-1.0f, -2.7f, -2.275f)));
1162 m_cases.push_back(FilterCase(m_gradientTex, tcu::Vec3(-2.0f, -1.5f, -1.8f), tcu::Vec3(-0.1f, 0.9f, -0.25f)));
1163 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec3(0.2f, 0.175f, 0.3f), tcu::Vec3(-2.0f, -3.7f, -1.825f)));
1164 m_cases.push_back(FilterCase(m_gridTex, tcu::Vec3(-0.8f, -2.3f, -2.5f), tcu::Vec3(0.2f, -0.1f, 1.325f)));
1165
1166 m_caseNdx = 0;
1167 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1168 }
1169 catch (...)
1170 {
1171 // Clean up to save memory.
1172 Texture3DFilteringCase::deinit();
1173 throw;
1174 }
1175 }
1176
deinit(void)1177 void Texture3DFilteringCase::deinit(void)
1178 {
1179 delete m_gradientTex;
1180 delete m_gridTex;
1181
1182 m_gradientTex = DE_NULL;
1183 m_gridTex = DE_NULL;
1184
1185 m_renderer.clear();
1186 m_cases.clear();
1187 }
1188
iterate(void)1189 Texture3DFilteringCase::IterateResult Texture3DFilteringCase::iterate(void)
1190 {
1191 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1192 const RandomViewport viewport(m_context.getRenderTarget(), TEX3D_VIEWPORT_WIDTH, TEX3D_VIEWPORT_HEIGHT,
1193 deStringHash(getName()) ^ deInt32Hash(m_caseNdx));
1194 const FilterCase &curCase = m_cases[m_caseNdx];
1195 const tcu::TextureFormat texFmt = curCase.texture->getRefTexture().getFormat();
1196 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
1197 const tcu::ScopedLogSection section(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx),
1198 string("Test ") + de::toString(m_caseNdx));
1199 ReferenceParams refParams(TEXTURETYPE_3D);
1200 tcu::Surface rendered(viewport.width, viewport.height);
1201 tcu::Vec3 texCoord[4];
1202
1203 if (viewport.width < TEX3D_MIN_VIEWPORT_WIDTH || viewport.height < TEX3D_MIN_VIEWPORT_HEIGHT)
1204 throw tcu::NotSupportedError("Too small render target", "", __FILE__, __LINE__);
1205
1206 // Setup params for reference.
1207 refParams.sampler = glu::mapGLSampler(m_wrapS, m_wrapT, m_wrapR, m_minFilter, m_magFilter);
1208 refParams.samplerType = getSamplerType(texFmt);
1209 refParams.lodMode = LODMODE_EXACT;
1210 refParams.colorBias = fmtInfo.lookupBias;
1211 refParams.colorScale = fmtInfo.lookupScale;
1212
1213 // Compute texture coordinates.
1214 m_testCtx.getLog() << TestLog::Message << "Approximate lod per axis = " << curCase.lod
1215 << ", offset = " << curCase.offset << TestLog::EndMessage;
1216
1217 {
1218 const float lodX = curCase.lod.x();
1219 const float lodY = curCase.lod.y();
1220 const float lodZ = curCase.lod.z();
1221 const float oX = curCase.offset.x();
1222 const float oY = curCase.offset.y();
1223 const float oZ = curCase.offset.z();
1224 const float sX = deFloatExp2(lodX) * float(viewport.width) / float(m_gradientTex->getRefTexture().getWidth());
1225 const float sY = deFloatExp2(lodY) * float(viewport.height) / float(m_gradientTex->getRefTexture().getHeight());
1226 const float sZ = deFloatExp2(lodZ) * float(de::max(viewport.width, viewport.height)) /
1227 float(m_gradientTex->getRefTexture().getDepth());
1228
1229 texCoord[0] = tcu::Vec3(oX, oY, oZ);
1230 texCoord[1] = tcu::Vec3(oX, oY + sY, oZ + sZ * 0.5f);
1231 texCoord[2] = tcu::Vec3(oX + sX, oY, oZ + sZ * 0.5f);
1232 texCoord[3] = tcu::Vec3(oX + sX, oY + sY, oZ + sZ);
1233 }
1234
1235 gl.bindTexture(GL_TEXTURE_3D, curCase.texture->getGLTexture());
1236 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, m_minFilter);
1237 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, m_magFilter);
1238 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, m_wrapS);
1239 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, m_wrapT);
1240 gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, m_wrapR);
1241
1242 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
1243 m_renderer.renderQuad(0, (const float *)&texCoord[0], refParams);
1244 glu::readPixels(m_context.getRenderContext(), viewport.x, viewport.y, rendered.getAccess());
1245
1246 {
1247 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
1248 const tcu::PixelFormat pixelFormat = m_context.getRenderTarget().getPixelFormat();
1249 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2),
1250 tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
1251 tcu::LodPrecision lodPrecision;
1252 tcu::LookupPrecision lookupPrecision;
1253
1254 lodPrecision.derivateBits = 18;
1255 lodPrecision.lodBits = 6;
1256 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
1257 lookupPrecision.coordBits = tcu::IVec3(20, 20, 20);
1258 lookupPrecision.uvwBits = tcu::IVec3(7, 7, 7);
1259 lookupPrecision.colorMask = getCompareMask(pixelFormat);
1260
1261 const bool isHighQuality =
1262 verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1263 (const float *)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1264
1265 if (!isHighQuality)
1266 {
1267 // Evaluate against lower precision requirements.
1268 lodPrecision.lodBits = 4;
1269 lookupPrecision.uvwBits = tcu::IVec3(4, 4, 4);
1270
1271 m_testCtx.getLog()
1272 << TestLog::Message
1273 << "Warning: Verification against high precision requirements failed, trying with lower requirements."
1274 << TestLog::EndMessage;
1275
1276 const bool isOk =
1277 verifyTextureResult(m_testCtx, rendered.getAccess(), curCase.texture->getRefTexture(),
1278 (const float *)&texCoord[0], refParams, lookupPrecision, lodPrecision, pixelFormat);
1279
1280 if (!isOk)
1281 {
1282 m_testCtx.getLog()
1283 << TestLog::Message
1284 << "ERROR: Verification against low precision requirements failed, failing test case."
1285 << TestLog::EndMessage;
1286 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1287 }
1288 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1289 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
1290 }
1291 }
1292
1293 m_caseNdx += 1;
1294 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
1295 }
1296
TextureFilteringTests(Context & context)1297 TextureFilteringTests::TextureFilteringTests(Context &context)
1298 : TestCaseGroup(context, "filtering", "Texture Filtering Tests")
1299 {
1300 }
1301
~TextureFilteringTests(void)1302 TextureFilteringTests::~TextureFilteringTests(void)
1303 {
1304 }
1305
init(void)1306 void TextureFilteringTests::init(void)
1307 {
1308 static const struct
1309 {
1310 const char *name;
1311 uint32_t mode;
1312 } wrapModes[] = {{"clamp", GL_CLAMP_TO_EDGE}, {"repeat", GL_REPEAT}, {"mirror", GL_MIRRORED_REPEAT}};
1313
1314 static const struct
1315 {
1316 const char *name;
1317 uint32_t mode;
1318 } minFilterModes[] = {{"nearest", GL_NEAREST},
1319 {"linear", GL_LINEAR},
1320 {"nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST},
1321 {"linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST},
1322 {"nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR},
1323 {"linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR}};
1324
1325 static const struct
1326 {
1327 const char *name;
1328 uint32_t mode;
1329 } magFilterModes[] = {{"nearest", GL_NEAREST}, {"linear", GL_LINEAR}};
1330
1331 static const struct
1332 {
1333 int width;
1334 int height;
1335 } sizes2D[] = {{4, 8}, {32, 64}, {128, 128}, {3, 7}, {31, 55}, {127, 99}};
1336
1337 static const struct
1338 {
1339 int width;
1340 int height;
1341 } sizesCube[] = {{8, 8}, {64, 64}, {128, 128}, {7, 7}, {63, 63}};
1342
1343 static const struct
1344 {
1345 int width;
1346 int height;
1347 int numLayers;
1348 } sizes2DArray[] = {{4, 8, 8}, {32, 64, 16}, {128, 32, 64}, {3, 7, 5}, {63, 63, 63}};
1349
1350 static const struct
1351 {
1352 int width;
1353 int height;
1354 int depth;
1355 } sizes3D[] = {{4, 8, 8}, {32, 64, 16}, {128, 32, 64}, {3, 7, 5}, {63, 63, 63}};
1356
1357 static const struct
1358 {
1359 const char *name;
1360 uint32_t format;
1361 } filterableFormatsByType[] = {{"rgba16f", GL_RGBA16F},
1362 {"r11f_g11f_b10f", GL_R11F_G11F_B10F},
1363 {"rgb9_e5", GL_RGB9_E5},
1364 {"rgba8", GL_RGBA8},
1365 {"rgba8_snorm", GL_RGBA8_SNORM},
1366 {"rgb565", GL_RGB565},
1367 {"rgba4", GL_RGBA4},
1368 {"rgb5_a1", GL_RGB5_A1},
1369 {"srgb8_alpha8", GL_SRGB8_ALPHA8},
1370 {"srgb_r8", GL_SR8_EXT},
1371 {"srgb_rg8", GL_SRG8_EXT},
1372 {"rgb10_a2", GL_RGB10_A2}};
1373
1374 // 2D texture filtering.
1375 {
1376 tcu::TestCaseGroup *group2D = new tcu::TestCaseGroup(m_testCtx, "2d", "2D Texture Filtering");
1377 addChild(group2D);
1378
1379 // Formats.
1380 tcu::TestCaseGroup *formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats");
1381 group2D->addChild(formatsGroup);
1382 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1383 {
1384 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1385 {
1386 uint32_t minFilter = minFilterModes[filterNdx].mode;
1387 const char *filterName = minFilterModes[filterNdx].name;
1388 uint32_t format = filterableFormatsByType[fmtNdx].format;
1389 const char *formatName = filterableFormatsByType[fmtNdx].name;
1390 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1391 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1392 string name = string(formatName) + "_" + filterName;
1393 uint32_t wrapS = GL_REPEAT;
1394 uint32_t wrapT = GL_REPEAT;
1395 int width = 64;
1396 int height = 64;
1397
1398 formatsGroup->addChild(new Texture2DFilteringCase(
1399 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(), "", minFilter,
1400 magFilter, wrapS, wrapT, format, width, height));
1401 }
1402 }
1403
1404 // ETC1 format.
1405 {
1406 std::vector<std::string> filenames;
1407 for (int i = 0; i <= 7; i++)
1408 filenames.push_back(string("data/etc1/photo_helsinki_mip_") + de::toString(i) + ".pkm");
1409
1410 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1411 {
1412 uint32_t minFilter = minFilterModes[filterNdx].mode;
1413 const char *filterName = minFilterModes[filterNdx].name;
1414 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1415 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1416 string name = string("etc1_rgb8_") + filterName;
1417 uint32_t wrapS = GL_REPEAT;
1418 uint32_t wrapT = GL_REPEAT;
1419
1420 formatsGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(),
1421 m_context.getContextInfo(), name.c_str(), "",
1422 minFilter, magFilter, wrapS, wrapT, filenames));
1423 }
1424 }
1425
1426 // Sizes.
1427 tcu::TestCaseGroup *sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1428 group2D->addChild(sizesGroup);
1429 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2D); sizeNdx++)
1430 {
1431 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1432 {
1433 uint32_t minFilter = minFilterModes[filterNdx].mode;
1434 const char *filterName = minFilterModes[filterNdx].name;
1435 uint32_t format = GL_RGBA8;
1436 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1437 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1438 uint32_t wrapS = GL_REPEAT;
1439 uint32_t wrapT = GL_REPEAT;
1440 int width = sizes2D[sizeNdx].width;
1441 int height = sizes2D[sizeNdx].height;
1442 string name = de::toString(width) + "x" + de::toString(height) + "_" + filterName;
1443
1444 sizesGroup->addChild(new Texture2DFilteringCase(m_testCtx, m_context.getRenderContext(),
1445 m_context.getContextInfo(), name.c_str(), "", minFilter,
1446 magFilter, wrapS, wrapT, format, width, height));
1447 }
1448 }
1449
1450 // Wrap modes.
1451 tcu::TestCaseGroup *combinationsGroup =
1452 new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1453 group2D->addChild(combinationsGroup);
1454 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1455 {
1456 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1457 {
1458 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1459 {
1460 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1461 {
1462 uint32_t minFilter = minFilterModes[minFilterNdx].mode;
1463 uint32_t magFilter = magFilterModes[magFilterNdx].mode;
1464 uint32_t format = GL_RGBA8;
1465 uint32_t wrapS = wrapModes[wrapSNdx].mode;
1466 uint32_t wrapT = wrapModes[wrapTNdx].mode;
1467 int width = 63;
1468 int height = 57;
1469 string name = string(minFilterModes[minFilterNdx].name) + "_" +
1470 magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" +
1471 wrapModes[wrapTNdx].name;
1472
1473 combinationsGroup->addChild(new Texture2DFilteringCase(
1474 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(), "",
1475 minFilter, magFilter, wrapS, wrapT, format, width, height));
1476 }
1477 }
1478 }
1479 }
1480 }
1481
1482 // Cube map texture filtering.
1483 {
1484 tcu::TestCaseGroup *groupCube = new tcu::TestCaseGroup(m_testCtx, "cube", "Cube Map Texture Filtering");
1485 addChild(groupCube);
1486
1487 // Formats.
1488 tcu::TestCaseGroup *formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "2D Texture Formats");
1489 groupCube->addChild(formatsGroup);
1490 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1491 {
1492 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1493 {
1494 uint32_t minFilter = minFilterModes[filterNdx].mode;
1495 const char *filterName = minFilterModes[filterNdx].name;
1496 uint32_t format = filterableFormatsByType[fmtNdx].format;
1497 const char *formatName = filterableFormatsByType[fmtNdx].name;
1498 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1499 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1500 string name = string(formatName) + "_" + filterName;
1501 uint32_t wrapS = GL_REPEAT;
1502 uint32_t wrapT = GL_REPEAT;
1503 int width = 64;
1504 int height = 64;
1505
1506 formatsGroup->addChild(new TextureCubeFilteringCase(
1507 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(), "", minFilter,
1508 magFilter, wrapS, wrapT, false /* always sample exterior as well */, format, width, height));
1509 }
1510 }
1511
1512 // ETC1 format.
1513 {
1514 static const char *faceExt[] = {"neg_x", "pos_x", "neg_y", "pos_y", "neg_z", "pos_z"};
1515
1516 const int numLevels = 7;
1517 vector<string> filenames;
1518 for (int level = 0; level < numLevels; level++)
1519 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
1520 filenames.push_back(string("data/etc1/skybox_") + faceExt[face] + "_mip_" + de::toString(level) +
1521 ".pkm");
1522
1523 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1524 {
1525 uint32_t minFilter = minFilterModes[filterNdx].mode;
1526 const char *filterName = minFilterModes[filterNdx].name;
1527 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1528 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1529 string name = string("etc1_rgb8_") + filterName;
1530 uint32_t wrapS = GL_REPEAT;
1531 uint32_t wrapT = GL_REPEAT;
1532
1533 formatsGroup->addChild(new TextureCubeFilteringCase(
1534 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(), "", minFilter,
1535 magFilter, wrapS, wrapT, false /* always sample exterior as well */, filenames));
1536 }
1537 }
1538
1539 // Sizes.
1540 tcu::TestCaseGroup *sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1541 groupCube->addChild(sizesGroup);
1542 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCube); sizeNdx++)
1543 {
1544 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1545 {
1546 uint32_t minFilter = minFilterModes[filterNdx].mode;
1547 const char *filterName = minFilterModes[filterNdx].name;
1548 uint32_t format = GL_RGBA8;
1549 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1550 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1551 uint32_t wrapS = GL_REPEAT;
1552 uint32_t wrapT = GL_REPEAT;
1553 int width = sizesCube[sizeNdx].width;
1554 int height = sizesCube[sizeNdx].height;
1555 string name = de::toString(width) + "x" + de::toString(height) + "_" + filterName;
1556
1557 sizesGroup->addChild(new TextureCubeFilteringCase(
1558 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(), "", minFilter,
1559 magFilter, wrapS, wrapT, false, format, width, height));
1560 }
1561 }
1562
1563 // Filter/wrap mode combinations.
1564 tcu::TestCaseGroup *combinationsGroup =
1565 new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1566 groupCube->addChild(combinationsGroup);
1567 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1568 {
1569 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1570 {
1571 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1572 {
1573 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1574 {
1575 uint32_t minFilter = minFilterModes[minFilterNdx].mode;
1576 uint32_t magFilter = magFilterModes[magFilterNdx].mode;
1577 uint32_t format = GL_RGBA8;
1578 uint32_t wrapS = wrapModes[wrapSNdx].mode;
1579 uint32_t wrapT = wrapModes[wrapTNdx].mode;
1580 int width = 63;
1581 int height = 63;
1582 string name = string(minFilterModes[minFilterNdx].name) + "_" +
1583 magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" +
1584 wrapModes[wrapTNdx].name;
1585
1586 combinationsGroup->addChild(new TextureCubeFilteringCase(
1587 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), name.c_str(), "",
1588 minFilter, magFilter, wrapS, wrapT, false, format, width, height));
1589 }
1590 }
1591 }
1592 }
1593
1594 // Cases with no visible cube edges.
1595 tcu::TestCaseGroup *onlyFaceInteriorGroup =
1596 new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
1597 groupCube->addChild(onlyFaceInteriorGroup);
1598
1599 for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
1600 {
1601 bool isLinear = isLinearI != 0;
1602 uint32_t filter = isLinear ? GL_LINEAR : GL_NEAREST;
1603
1604 onlyFaceInteriorGroup->addChild(new TextureCubeFilteringCase(
1605 m_testCtx, m_context.getRenderContext(), m_context.getContextInfo(), isLinear ? "linear" : "nearest",
1606 "", filter, filter, GL_REPEAT, GL_REPEAT, true, GL_RGBA8, 63, 63));
1607 }
1608 }
1609
1610 // 2D array texture filtering.
1611 {
1612 tcu::TestCaseGroup *const group2DArray =
1613 new tcu::TestCaseGroup(m_testCtx, "2d_array", "2D Array Texture Filtering");
1614 addChild(group2DArray);
1615
1616 // Formats.
1617 tcu::TestCaseGroup *const formatsGroup =
1618 new tcu::TestCaseGroup(m_testCtx, "formats", "2D Array Texture Formats");
1619 group2DArray->addChild(formatsGroup);
1620 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1621 {
1622 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1623 {
1624 uint32_t minFilter = minFilterModes[filterNdx].mode;
1625 const char *filterName = minFilterModes[filterNdx].name;
1626 uint32_t format = filterableFormatsByType[fmtNdx].format;
1627 const char *formatName = filterableFormatsByType[fmtNdx].name;
1628 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1629 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1630 string name = string(formatName) + "_" + filterName;
1631 uint32_t wrapS = GL_REPEAT;
1632 uint32_t wrapT = GL_REPEAT;
1633 int width = 128;
1634 int height = 128;
1635 int numLayers = 8;
1636
1637 formatsGroup->addChild(new Texture2DArrayFilteringCase(
1638 m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, width, height, numLayers));
1639 }
1640 }
1641
1642 // Sizes.
1643 tcu::TestCaseGroup *sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1644 group2DArray->addChild(sizesGroup);
1645 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes2DArray); sizeNdx++)
1646 {
1647 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1648 {
1649 uint32_t minFilter = minFilterModes[filterNdx].mode;
1650 const char *filterName = minFilterModes[filterNdx].name;
1651 uint32_t format = GL_RGBA8;
1652 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1653 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1654 uint32_t wrapS = GL_REPEAT;
1655 uint32_t wrapT = GL_REPEAT;
1656 int width = sizes2DArray[sizeNdx].width;
1657 int height = sizes2DArray[sizeNdx].height;
1658 int numLayers = sizes2DArray[sizeNdx].numLayers;
1659 string name =
1660 de::toString(width) + "x" + de::toString(height) + "x" + de::toString(numLayers) + "_" + filterName;
1661
1662 sizesGroup->addChild(new Texture2DArrayFilteringCase(m_context, name.c_str(), "", minFilter, magFilter,
1663 wrapS, wrapT, format, width, height, numLayers));
1664 }
1665 }
1666
1667 // Wrap modes.
1668 tcu::TestCaseGroup *const combinationsGroup =
1669 new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1670 group2DArray->addChild(combinationsGroup);
1671 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1672 {
1673 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1674 {
1675 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1676 {
1677 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1678 {
1679 uint32_t minFilter = minFilterModes[minFilterNdx].mode;
1680 uint32_t magFilter = magFilterModes[magFilterNdx].mode;
1681 uint32_t format = GL_RGBA8;
1682 uint32_t wrapS = wrapModes[wrapSNdx].mode;
1683 uint32_t wrapT = wrapModes[wrapTNdx].mode;
1684 int width = 123;
1685 int height = 107;
1686 int numLayers = 7;
1687 string name = string(minFilterModes[minFilterNdx].name) + "_" +
1688 magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" +
1689 wrapModes[wrapTNdx].name;
1690
1691 combinationsGroup->addChild(new Texture2DArrayFilteringCase(m_context, name.c_str(), "",
1692 minFilter, magFilter, wrapS, wrapT,
1693 format, width, height, numLayers));
1694 }
1695 }
1696 }
1697 }
1698 }
1699
1700 // 3D texture filtering.
1701 {
1702 tcu::TestCaseGroup *group3D = new tcu::TestCaseGroup(m_testCtx, "3d", "3D Texture Filtering");
1703 addChild(group3D);
1704
1705 // Formats.
1706 tcu::TestCaseGroup *formatsGroup = new tcu::TestCaseGroup(m_testCtx, "formats", "3D Texture Formats");
1707 group3D->addChild(formatsGroup);
1708 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
1709 {
1710 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1711 {
1712 uint32_t minFilter = minFilterModes[filterNdx].mode;
1713 const char *filterName = minFilterModes[filterNdx].name;
1714 uint32_t format = filterableFormatsByType[fmtNdx].format;
1715 const char *formatName = filterableFormatsByType[fmtNdx].name;
1716 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1717 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1718 string name = string(formatName) + "_" + filterName;
1719 uint32_t wrapS = GL_REPEAT;
1720 uint32_t wrapT = GL_REPEAT;
1721 uint32_t wrapR = GL_REPEAT;
1722 int width = 64;
1723 int height = 64;
1724 int depth = 64;
1725
1726 formatsGroup->addChild(new Texture3DFilteringCase(m_context, name.c_str(), "", minFilter, magFilter,
1727 wrapS, wrapT, wrapR, format, width, height, depth));
1728 }
1729 }
1730
1731 // Sizes.
1732 tcu::TestCaseGroup *sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
1733 group3D->addChild(sizesGroup);
1734 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes3D); sizeNdx++)
1735 {
1736 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
1737 {
1738 uint32_t minFilter = minFilterModes[filterNdx].mode;
1739 const char *filterName = minFilterModes[filterNdx].name;
1740 uint32_t format = GL_RGBA8;
1741 bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
1742 uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
1743 uint32_t wrapS = GL_REPEAT;
1744 uint32_t wrapT = GL_REPEAT;
1745 uint32_t wrapR = GL_REPEAT;
1746 int width = sizes3D[sizeNdx].width;
1747 int height = sizes3D[sizeNdx].height;
1748 int depth = sizes3D[sizeNdx].depth;
1749 string name =
1750 de::toString(width) + "x" + de::toString(height) + "x" + de::toString(depth) + "_" + filterName;
1751
1752 sizesGroup->addChild(new Texture3DFilteringCase(m_context, name.c_str(), "", minFilter, magFilter,
1753 wrapS, wrapT, wrapR, format, width, height, depth));
1754 }
1755 }
1756
1757 // Wrap modes.
1758 tcu::TestCaseGroup *combinationsGroup =
1759 new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
1760 group3D->addChild(combinationsGroup);
1761 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
1762 {
1763 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
1764 {
1765 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
1766 {
1767 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
1768 {
1769 for (int wrapRNdx = 0; wrapRNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapRNdx++)
1770 {
1771 uint32_t minFilter = minFilterModes[minFilterNdx].mode;
1772 uint32_t magFilter = magFilterModes[magFilterNdx].mode;
1773 uint32_t format = GL_RGBA8;
1774 uint32_t wrapS = wrapModes[wrapSNdx].mode;
1775 uint32_t wrapT = wrapModes[wrapTNdx].mode;
1776 uint32_t wrapR = wrapModes[wrapRNdx].mode;
1777 int width = 63;
1778 int height = 57;
1779 int depth = 67;
1780 string name = string(minFilterModes[minFilterNdx].name) + "_" +
1781 magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name + "_" +
1782 wrapModes[wrapTNdx].name + "_" + wrapModes[wrapRNdx].name;
1783
1784 combinationsGroup->addChild(
1785 new Texture3DFilteringCase(m_context, name.c_str(), "", minFilter, magFilter, wrapS,
1786 wrapT, wrapR, format, width, height, depth));
1787 }
1788 }
1789 }
1790 }
1791 }
1792 }
1793 }
1794
1795 } // namespace Functional
1796 } // namespace gles3
1797 } // namespace deqp
1798