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