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