1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 "es31fTextureFilteringTests.hpp"
25
26 #include "glsTextureTestUtil.hpp"
27
28 #include "gluPixelTransfer.hpp"
29 #include "gluTexture.hpp"
30 #include "gluTextureUtil.hpp"
31
32 #include "tcuCommandLine.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "tcuTexLookupVerifier.hpp"
36 #include "tcuVectorUtil.hpp"
37
38 #include "deStringUtil.hpp"
39 #include "deString.h"
40
41 #include "glwFunctions.hpp"
42 #include "glwEnums.hpp"
43
44 namespace deqp
45 {
46 namespace gles31
47 {
48 namespace Functional
49 {
50
51 using std::string;
52 using std::vector;
53 using tcu::TestLog;
54 using namespace gls::TextureTestUtil;
55 using namespace glu::TextureTestUtil;
56
getFaceDesc(const tcu::CubeFace face)57 static const char *getFaceDesc(const tcu::CubeFace face)
58 {
59 switch (face)
60 {
61 case tcu::CUBEFACE_NEGATIVE_X:
62 return "-X";
63 case tcu::CUBEFACE_POSITIVE_X:
64 return "+X";
65 case tcu::CUBEFACE_NEGATIVE_Y:
66 return "-Y";
67 case tcu::CUBEFACE_POSITIVE_Y:
68 return "+Y";
69 case tcu::CUBEFACE_NEGATIVE_Z:
70 return "-Z";
71 case tcu::CUBEFACE_POSITIVE_Z:
72 return "+Z";
73 default:
74 DE_ASSERT(false);
75 return DE_NULL;
76 }
77 }
78
logCubeArrayTexCoords(TestLog & log,vector<float> & texCoord)79 static void logCubeArrayTexCoords(TestLog &log, vector<float> &texCoord)
80 {
81 const size_t numVerts = texCoord.size() / 4;
82
83 DE_ASSERT(texCoord.size() % 4 == 0);
84
85 for (size_t vertNdx = 0; vertNdx < numVerts; vertNdx++)
86 {
87 const size_t coordNdx = vertNdx * 4;
88
89 const float u = texCoord[coordNdx + 0];
90 const float v = texCoord[coordNdx + 1];
91 const float w = texCoord[coordNdx + 2];
92 const float q = texCoord[coordNdx + 3];
93
94 log << TestLog::Message << vertNdx << ": (" << u << ", " << v << ", " << w << ", " << q << ")"
95 << TestLog::EndMessage;
96 }
97 }
98
99 // Cube map array filtering
100
101 class TextureCubeArrayFilteringCase : public TestCase
102 {
103 public:
104 TextureCubeArrayFilteringCase(Context &context, const char *name, const char *desc, uint32_t minFilter,
105 uint32_t magFilter, uint32_t wrapS, uint32_t wrapT, uint32_t internalFormat, int size,
106 int depth, bool onlySampleFaceInterior = false);
107
108 ~TextureCubeArrayFilteringCase(void);
109
110 void init(void);
111 void deinit(void);
112 IterateResult iterate(void);
113
114 private:
115 TextureCubeArrayFilteringCase(const TextureCubeArrayFilteringCase &);
116 TextureCubeArrayFilteringCase &operator=(const TextureCubeArrayFilteringCase &);
117
118 const uint32_t m_minFilter;
119 const uint32_t m_magFilter;
120 const uint32_t m_wrapS;
121 const uint32_t m_wrapT;
122
123 const uint32_t m_internalFormat;
124 const int m_size;
125 const int m_depth;
126
127 const bool m_onlySampleFaceInterior; //!< If true, we avoid sampling anywhere near a face's edges.
128
129 struct FilterCase
130 {
131 const glu::TextureCubeArray *texture;
132 tcu::Vec2 bottomLeft;
133 tcu::Vec2 topRight;
134 tcu::Vec2 layerRange;
135
FilterCasedeqp::gles31::Functional::TextureCubeArrayFilteringCase::FilterCase136 FilterCase(void) : texture(DE_NULL)
137 {
138 }
139
FilterCasedeqp::gles31::Functional::TextureCubeArrayFilteringCase::FilterCase140 FilterCase(const glu::TextureCubeArray *tex_, const tcu::Vec2 &bottomLeft_, const tcu::Vec2 &topRight_,
141 const tcu::Vec2 &layerRange_)
142 : texture(tex_)
143 , bottomLeft(bottomLeft_)
144 , topRight(topRight_)
145 , layerRange(layerRange_)
146 {
147 }
148 };
149
150 glu::TextureCubeArray *m_gradientTex;
151 glu::TextureCubeArray *m_gridTex;
152
153 TextureRenderer m_renderer;
154
155 std::vector<FilterCase> m_cases;
156 int m_caseNdx;
157 };
158
TextureCubeArrayFilteringCase(Context & context,const char * name,const char * desc,uint32_t minFilter,uint32_t magFilter,uint32_t wrapS,uint32_t wrapT,uint32_t internalFormat,int size,int depth,bool onlySampleFaceInterior)159 TextureCubeArrayFilteringCase::TextureCubeArrayFilteringCase(Context &context, const char *name, const char *desc,
160 uint32_t minFilter, uint32_t magFilter, uint32_t wrapS,
161 uint32_t wrapT, uint32_t internalFormat, int size,
162 int depth, bool onlySampleFaceInterior)
163 : TestCase(context, name, desc)
164 , m_minFilter(minFilter)
165 , m_magFilter(magFilter)
166 , m_wrapS(wrapS)
167 , m_wrapT(wrapT)
168 , m_internalFormat(internalFormat)
169 , m_size(size)
170 , m_depth(depth)
171 , m_onlySampleFaceInterior(onlySampleFaceInterior)
172 , m_gradientTex(DE_NULL)
173 , m_gridTex(DE_NULL)
174 , m_renderer(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_310_ES,
175 glu::PRECISION_HIGHP)
176 , m_caseNdx(0)
177 {
178 }
179
~TextureCubeArrayFilteringCase(void)180 TextureCubeArrayFilteringCase::~TextureCubeArrayFilteringCase(void)
181 {
182 TextureCubeArrayFilteringCase::deinit();
183 }
184
init(void)185 void TextureCubeArrayFilteringCase::init(void)
186 {
187 auto ctxType = m_context.getRenderContext().getType();
188 const bool isES32orGL45 = glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
189 glu::contextSupports(ctxType, glu::ApiType::core(4, 5));
190
191 if (!isES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
192 throw tcu::NotSupportedError("GL_EXT_texture_cube_map_array not supported");
193
194 if (m_internalFormat == GL_SR8_EXT && !(m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_R8")))
195 TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_R8 not supported");
196
197 if (m_internalFormat == GL_SRG8_EXT &&
198 !(m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_RG8")))
199 TCU_THROW(NotSupportedError, "GL_EXT_texture_sRGB_RG8 not supported");
200
201 try
202 {
203 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
204 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_internalFormat);
205 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
206 const tcu::Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
207 const tcu::Vec4 cBias = fmtInfo.valueMin;
208 const int numLevels = deLog2Floor32(m_size) + 1;
209 const int numLayers = m_depth / 6;
210
211 if (!isContextTypeES(ctxType))
212 gl.enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
213
214 // Create textures.
215 m_gradientTex = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
216 m_gridTex = new glu::TextureCubeArray(m_context.getRenderContext(), m_internalFormat, m_size, m_depth);
217
218 const tcu::IVec4 levelSwz[] = {
219 tcu::IVec4(0, 1, 2, 3),
220 tcu::IVec4(2, 1, 3, 0),
221 tcu::IVec4(3, 0, 1, 2),
222 tcu::IVec4(1, 3, 2, 0),
223 };
224
225 // Fill first gradient texture (gradient direction varies between layers).
226 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
227 {
228 m_gradientTex->getRefTexture().allocLevel(levelNdx);
229
230 const tcu::PixelBufferAccess levelBuf = m_gradientTex->getRefTexture().getLevel(levelNdx);
231
232 for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
233 {
234 const tcu::IVec4 swz = levelSwz[layerFaceNdx % DE_LENGTH_OF_ARRAY(levelSwz)];
235 const tcu::Vec4 gMin =
236 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f).swizzle(swz[0], swz[1], swz[2], swz[3]) * cScale + cBias;
237 const tcu::Vec4 gMax =
238 tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f).swizzle(swz[0], swz[1], swz[2], swz[3]) * cScale + cBias;
239
240 tcu::fillWithComponentGradients(
241 tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), gMin,
242 gMax);
243 }
244 }
245
246 // Fill second with grid texture (each layer has unique colors).
247 for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
248 {
249 m_gridTex->getRefTexture().allocLevel(levelNdx);
250
251 const tcu::PixelBufferAccess levelBuf = m_gridTex->getRefTexture().getLevel(levelNdx);
252
253 for (int layerFaceNdx = 0; layerFaceNdx < m_depth; layerFaceNdx++)
254 {
255 const uint32_t step = 0x00ffffff / (numLevels * m_depth - 1);
256 const uint32_t rgb = step * (levelNdx + layerFaceNdx * numLevels);
257 const uint32_t colorA = 0xff000000 | rgb;
258 const uint32_t colorB = 0xff000000 | ~rgb;
259
260 tcu::fillWithGrid(
261 tcu::getSubregion(levelBuf, 0, 0, layerFaceNdx, levelBuf.getWidth(), levelBuf.getHeight(), 1), 4,
262 tcu::RGBA(colorA).toVec() * cScale + cBias, tcu::RGBA(colorB).toVec() * cScale + cBias);
263 }
264 }
265
266 // Upload.
267 m_gradientTex->upload();
268 m_gridTex->upload();
269
270 // Test cases
271 {
272 const glu::TextureCubeArray *const tex0 = m_gradientTex;
273 const glu::TextureCubeArray *const tex1 = m_gridTex;
274
275 if (m_onlySampleFaceInterior)
276 {
277 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f),
278 tcu::Vec2(-0.5f, float(numLayers) + 0.5f))); // minification
279 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.5f, 0.65f), tcu::Vec2(0.8f, 0.8f),
280 tcu::Vec2(-0.5f, float(numLayers) + 0.5f))); // magnification
281 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-0.8f, -0.8f), tcu::Vec2(0.8f, 0.8f),
282 tcu::Vec2(float(numLayers) + 0.5f, -0.5f))); // minification
283 m_cases.push_back(FilterCase(tex1, tcu::Vec2(0.2f, 0.2f), tcu::Vec2(0.6f, 0.5f),
284 tcu::Vec2(float(numLayers) + 0.5f, -0.5f))); // magnification
285 }
286 else
287 {
288 const bool isSingleSample = (m_context.getRenderTarget().getNumSamples() == 0);
289
290 // minification - w/ tweak to avoid hitting triangle edges with a face switchpoint in multisample configs
291 if (isSingleSample)
292 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.25f, -1.2f), tcu::Vec2(1.2f, 1.25f),
293 tcu::Vec2(-0.5f, float(numLayers) + 0.5f)));
294 else
295 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f),
296 tcu::Vec2(-0.5f, float(numLayers) + 0.5f)));
297
298 m_cases.push_back(FilterCase(tex0, tcu::Vec2(0.8f, 0.8f), tcu::Vec2(1.25f, 1.20f),
299 tcu::Vec2(-0.5f, float(numLayers) + 0.5f))); // magnification
300 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.19f, -1.3f), tcu::Vec2(1.1f, 1.35f),
301 tcu::Vec2(float(numLayers) + 0.5f, -0.5f))); // minification
302 m_cases.push_back(FilterCase(tex1, tcu::Vec2(-1.2f, -1.1f), tcu::Vec2(-0.8f, -0.8f),
303 tcu::Vec2(float(numLayers) + 0.5f, -0.5f))); // magnification
304
305 // Layer rounding - only in single-sample configs as multisample configs may produce smooth transition at the middle.
306 if (isSingleSample && (numLayers > 1))
307 m_cases.push_back(FilterCase(tex0, tcu::Vec2(-2.0f, -1.5f), tcu::Vec2(-0.1f, 0.9f),
308 tcu::Vec2(1.50001f, 1.49999f)));
309 }
310 }
311
312 m_caseNdx = 0;
313 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
314 }
315 catch (...)
316 {
317 // Clean up to save memory.
318 TextureCubeArrayFilteringCase::deinit();
319 throw;
320 }
321 }
322
deinit(void)323 void TextureCubeArrayFilteringCase::deinit(void)
324 {
325 delete m_gradientTex;
326 delete m_gridTex;
327
328 m_gradientTex = DE_NULL;
329 m_gridTex = DE_NULL;
330
331 m_renderer.clear();
332 m_cases.clear();
333
334 if (!isContextTypeES(m_context.getRenderContext().getType()))
335 m_context.getRenderContext().getFunctions().disable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
336 }
337
iterate(void)338 TextureCubeArrayFilteringCase::IterateResult TextureCubeArrayFilteringCase::iterate(void)
339 {
340 TestLog &log = m_testCtx.getLog();
341 const glu::RenderContext &renderCtx = m_context.getRenderContext();
342 const glw::Functions &gl = renderCtx.getFunctions();
343 const int viewportSize = 28;
344 const uint32_t randomSeed =
345 deStringHash(getName()) ^ deInt32Hash(m_caseNdx) ^ m_testCtx.getCommandLine().getBaseSeed();
346 const RandomViewport viewport(m_context.getRenderTarget(), viewportSize, viewportSize, randomSeed);
347 const FilterCase &curCase = m_cases[m_caseNdx];
348 const tcu::TextureFormat texFmt = curCase.texture->getRefTexture().getFormat();
349 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
350 const tcu::ScopedLogSection section(m_testCtx.getLog(), string("Test") + de::toString(m_caseNdx),
351 string("Test ") + de::toString(m_caseNdx));
352 ReferenceParams refParams(TEXTURETYPE_CUBE_ARRAY);
353
354 if (viewport.width < viewportSize || viewport.height < viewportSize)
355 throw tcu::NotSupportedError("Render target too small", "", __FILE__, __LINE__);
356
357 // Params for reference computation.
358 refParams.sampler = glu::mapGLSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, m_minFilter, m_magFilter);
359 refParams.sampler.seamlessCubeMap = true;
360 refParams.samplerType = getSamplerType(texFmt);
361 refParams.colorBias = fmtInfo.lookupBias;
362 refParams.colorScale = fmtInfo.lookupScale;
363 refParams.lodMode = LODMODE_EXACT;
364
365 gl.bindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, curCase.texture->getGLTexture());
366 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, m_minFilter);
367 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, m_magFilter);
368 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, m_wrapS);
369 gl.texParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, m_wrapT);
370
371 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
372
373 m_testCtx.getLog() << TestLog::Message << "Coordinates: " << curCase.bottomLeft << " -> " << curCase.topRight
374 << TestLog::EndMessage;
375
376 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
377 {
378 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
379 tcu::Surface result(viewport.width, viewport.height);
380 vector<float> texCoord;
381
382 computeQuadTexCoordCubeArray(texCoord, face, curCase.bottomLeft, curCase.topRight, curCase.layerRange);
383
384 log << TestLog::Message << "Face " << getFaceDesc(face) << TestLog::EndMessage;
385
386 log << TestLog::Message << "Texture coordinates:" << TestLog::EndMessage;
387
388 logCubeArrayTexCoords(log, texCoord);
389
390 m_renderer.renderQuad(0, &texCoord[0], refParams);
391 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
392
393 glu::readPixels(renderCtx, viewport.x, viewport.y, result.getAccess());
394 GLU_EXPECT_NO_ERROR(gl.getError(), "Read pixels");
395
396 {
397 const bool isNearestOnly = m_minFilter == GL_NEAREST && m_magFilter == GL_NEAREST;
398 const tcu::PixelFormat pixelFormat = renderCtx.getRenderTarget().getPixelFormat();
399 const tcu::IVec4 coordBits = tcu::IVec4(10);
400 const tcu::IVec4 colorBits = max(getBitsVec(pixelFormat) - (isNearestOnly ? 1 : 2),
401 tcu::IVec4(0)); // 1 inaccurate bit if nearest only, 2 otherwise
402 tcu::LodPrecision lodPrecision;
403 tcu::LookupPrecision lookupPrecision;
404
405 lodPrecision.derivateBits = 10;
406 lodPrecision.lodBits = 5;
407 lookupPrecision.colorThreshold = tcu::computeFixedPointThreshold(colorBits) / refParams.colorScale;
408 lookupPrecision.coordBits = coordBits.toWidth<3>();
409 lookupPrecision.uvwBits = tcu::IVec3(6);
410 lookupPrecision.colorMask = getCompareMask(pixelFormat);
411
412 const bool isHighQuality =
413 verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), &texCoord[0],
414 refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
415
416 if (!isHighQuality)
417 {
418 // Evaluate against lower precision requirements.
419 lodPrecision.lodBits = 4;
420 lookupPrecision.uvwBits = tcu::IVec3(4);
421
422 m_testCtx.getLog() << TestLog::Message
423 << "Warning: Verification against high precision requirements failed, trying with "
424 "lower requirements."
425 << TestLog::EndMessage;
426
427 const bool isOk =
428 verifyTextureResult(m_testCtx, result.getAccess(), curCase.texture->getRefTexture(), &texCoord[0],
429 refParams, lookupPrecision, coordBits, lodPrecision, pixelFormat);
430
431 if (!isOk)
432 {
433 m_testCtx.getLog()
434 << TestLog::Message
435 << "ERROR: Verification against low precision requirements failed, failing test case."
436 << TestLog::EndMessage;
437 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
438 }
439 else if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
440 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality filtering result");
441 }
442 }
443 }
444
445 m_caseNdx += 1;
446 return m_caseNdx < (int)m_cases.size() ? CONTINUE : STOP;
447 }
448
TextureFilteringTests(Context & context)449 TextureFilteringTests::TextureFilteringTests(Context &context)
450 : TestCaseGroup(context, "filtering", "Texture Filtering Tests")
451 {
452 }
453
~TextureFilteringTests(void)454 TextureFilteringTests::~TextureFilteringTests(void)
455 {
456 }
457
init(void)458 void TextureFilteringTests::init(void)
459 {
460 static const struct
461 {
462 const char *name;
463 uint32_t mode;
464 } wrapModes[] = {{"clamp", GL_CLAMP_TO_EDGE}, {"repeat", GL_REPEAT}, {"mirror", GL_MIRRORED_REPEAT}};
465
466 static const struct
467 {
468 const char *name;
469 uint32_t mode;
470 } minFilterModes[] = {{"nearest", GL_NEAREST},
471 {"linear", GL_LINEAR},
472 {"nearest_mipmap_nearest", GL_NEAREST_MIPMAP_NEAREST},
473 {"linear_mipmap_nearest", GL_LINEAR_MIPMAP_NEAREST},
474 {"nearest_mipmap_linear", GL_NEAREST_MIPMAP_LINEAR},
475 {"linear_mipmap_linear", GL_LINEAR_MIPMAP_LINEAR}};
476
477 static const struct
478 {
479 const char *name;
480 uint32_t mode;
481 } magFilterModes[] = {{"nearest", GL_NEAREST}, {"linear", GL_LINEAR}};
482
483 static const struct
484 {
485 int size;
486 int depth;
487 } sizesCubeArray[] = {{8, 6}, {64, 12}, {128, 12}, {7, 12}, {63, 18}};
488
489 static const struct
490 {
491 const char *name;
492 uint32_t format;
493 } filterableFormatsByType[] = {{"rgba16f", GL_RGBA16F},
494 {"r11f_g11f_b10f", GL_R11F_G11F_B10F},
495 {"rgb9_e5", GL_RGB9_E5},
496 {"rgba8", GL_RGBA8},
497 {"rgba8_snorm", GL_RGBA8_SNORM},
498 {"rgb565", GL_RGB565},
499 {"rgba4", GL_RGBA4},
500 {"rgb5_a1", GL_RGB5_A1},
501 {"sr8", GL_SR8_EXT},
502 {"srg8", GL_SRG8_EXT},
503 {"srgb8_alpha8", GL_SRGB8_ALPHA8},
504 {"rgb10_a2", GL_RGB10_A2}};
505
506 // Cube map array texture filtering.
507 {
508 tcu::TestCaseGroup *const groupCubeArray =
509 new tcu::TestCaseGroup(m_testCtx, "cube_array", "Cube Map Array Texture Filtering");
510 addChild(groupCubeArray);
511
512 // Formats.
513 {
514 tcu::TestCaseGroup *const formatsGroup =
515 new tcu::TestCaseGroup(m_testCtx, "formats", "Cube Map Array Texture Formats");
516 groupCubeArray->addChild(formatsGroup);
517
518 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(filterableFormatsByType); fmtNdx++)
519 {
520 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
521 {
522 const uint32_t minFilter = minFilterModes[filterNdx].mode;
523 const char *filterName = minFilterModes[filterNdx].name;
524 const uint32_t format = filterableFormatsByType[fmtNdx].format;
525 const char *formatName = filterableFormatsByType[fmtNdx].name;
526 const bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
527 const uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
528 const string name = string(formatName) + "_" + filterName;
529 const uint32_t wrapS = GL_REPEAT;
530 const uint32_t wrapT = GL_REPEAT;
531 const int size = 64;
532 const int depth = 12;
533
534 formatsGroup->addChild(new TextureCubeArrayFilteringCase(
535 m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, size, depth));
536 }
537 }
538 }
539
540 // Sizes.
541 {
542 tcu::TestCaseGroup *const sizesGroup = new tcu::TestCaseGroup(m_testCtx, "sizes", "Texture Sizes");
543 groupCubeArray->addChild(sizesGroup);
544
545 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizesCubeArray); sizeNdx++)
546 {
547 for (int filterNdx = 0; filterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); filterNdx++)
548 {
549 const uint32_t minFilter = minFilterModes[filterNdx].mode;
550 const char *filterName = minFilterModes[filterNdx].name;
551 const uint32_t format = GL_RGBA8;
552 const bool isMipmap = minFilter != GL_NEAREST && minFilter != GL_LINEAR;
553 const uint32_t magFilter = isMipmap ? GL_LINEAR : minFilter;
554 const uint32_t wrapS = GL_REPEAT;
555 const uint32_t wrapT = GL_REPEAT;
556 const int size = sizesCubeArray[sizeNdx].size;
557 const int depth = sizesCubeArray[sizeNdx].depth;
558 const string name =
559 de::toString(size) + "x" + de::toString(size) + "x" + de::toString(depth) + "_" + filterName;
560
561 sizesGroup->addChild(new TextureCubeArrayFilteringCase(
562 m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, size, depth));
563 }
564 }
565 }
566
567 // Wrap modes.
568 {
569 tcu::TestCaseGroup *const combinationsGroup =
570 new tcu::TestCaseGroup(m_testCtx, "combinations", "Filter and wrap mode combinations");
571 groupCubeArray->addChild(combinationsGroup);
572
573 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(minFilterModes); minFilterNdx++)
574 {
575 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(magFilterModes); magFilterNdx++)
576 {
577 for (int wrapSNdx = 0; wrapSNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapSNdx++)
578 {
579 for (int wrapTNdx = 0; wrapTNdx < DE_LENGTH_OF_ARRAY(wrapModes); wrapTNdx++)
580 {
581 const uint32_t minFilter = minFilterModes[minFilterNdx].mode;
582 const uint32_t magFilter = magFilterModes[magFilterNdx].mode;
583 const uint32_t format = GL_RGBA8;
584 const uint32_t wrapS = wrapModes[wrapSNdx].mode;
585 const uint32_t wrapT = wrapModes[wrapTNdx].mode;
586 const int size = 63;
587 const int depth = 12;
588 const string name = string(minFilterModes[minFilterNdx].name) + "_" +
589 magFilterModes[magFilterNdx].name + "_" + wrapModes[wrapSNdx].name +
590 "_" + wrapModes[wrapTNdx].name;
591
592 combinationsGroup->addChild(new TextureCubeArrayFilteringCase(
593 m_context, name.c_str(), "", minFilter, magFilter, wrapS, wrapT, format, size, depth));
594 }
595 }
596 }
597 }
598 }
599
600 // Cases with no visible cube edges.
601 {
602 tcu::TestCaseGroup *const onlyFaceInteriorGroup =
603 new tcu::TestCaseGroup(m_testCtx, "no_edges_visible", "Don't sample anywhere near a face's edges");
604 groupCubeArray->addChild(onlyFaceInteriorGroup);
605
606 for (int isLinearI = 0; isLinearI <= 1; isLinearI++)
607 {
608 const bool isLinear = isLinearI != 0;
609 const uint32_t filter = isLinear ? GL_LINEAR : GL_NEAREST;
610
611 onlyFaceInteriorGroup->addChild(
612 new TextureCubeArrayFilteringCase(m_context, isLinear ? "linear" : "nearest", "", filter, filter,
613 GL_REPEAT, GL_REPEAT, GL_RGBA8, 63, 12, true));
614 }
615 }
616 }
617 }
618
619 } // namespace Functional
620 } // namespace gles31
621 } // namespace deqp
622